diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-06-15 21:44:39 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-06-15 21:44:39 +0000 |
commit | a493eb7ae02cfab54494aa867b0895ab6a66f266 (patch) | |
tree | 1b2c9f243e281f08541d4e109f6c11247e4daaa3 | |
parent | da6addb0a6292746681dd8bf4d92b32648b404ba (diff) | |
parent | fdb16c9d501c4b6752f13c07c14d288e077a55f0 (diff) | |
download | nix-a493eb7ae02cfab54494aa867b0895ab6a66f266.tar.gz |
Snap for 8730993 from fdb16c9d501c4b6752f13c07c14d288e077a55f0 to mainline-tzdata3-releaseaml_tz3_314012070aml_tz3_314012050aml_tz3_314012010aml_tz3_313110000aml_tz3_312511020aml_tz3_312511010aml_tz3_312410020aml_tz3_312410010android12-mainline-tzdata3-releaseaml_tz3_314012010
Change-Id: Ide614347dd43b85d5e48e340f139bfb99e4319b3
101 files changed, 2429 insertions, 5900 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 90eb8fa..82a8727 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,6 +1,5 @@ { "git": { - "sha1": "afba7c5a33dd4fd62b047e64089487cf822ccec2" - }, - "path_in_vcs": "" -}
\ No newline at end of file + "sha1": "4c7021787a174493bf1abb90a711d7464e6c80f6" + } +} diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3d432e0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +/CHANGELOG.md merge=union @@ -25,22 +25,20 @@ rust_library { name: "libnix", host_supported: true, crate_name: "nix", - cargo_env_compat: true, - cargo_pkg_version: "0.23.1", srcs: ["src/lib.rs"], edition: "2018", rustlibs: [ "libbitflags", "libcfg_if", "liblibc", - "libmemoffset", ], apex_available: [ "//apex_available:platform", - "com.android.bluetooth", - "com.android.compos", "com.android.virt", ], - vendor_available: true, - min_sdk_version: "29", } + +// dependent_library ["feature_list"] +// bitflags-1.2.1 "default" +// cfg-if-1.0.0 +// libc-0.2.94 "default,extra_traits,std" diff --git a/CHANGELOG.md b/CHANGELOG.md index 77d5b2a..1297ba7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,216 +1,7 @@ # Change Log All notable changes to this project will be documented in this file. -This project adheres to [Semantic Versioning](https://semver.org/). - -## [0.23.1] - 2021-12-16 - -### Added -### Changed - -- Relaxed the bitflags requirement from 1.3.1 to 1.1. This partially reverts - #1492. From now on, the MSRV is not guaranteed to work with all versions of - all dependencies, just with some version of all dependencies. - (#[1607](https://github.com/nix-rust/nix/pull/1607)) - -### Fixed - -- Fixed soundness issues in `FdSet::insert`, `FdSet::remove`, and - `FdSet::contains` involving file descriptors outside of the range - `0..FD_SETSIZE`. - (#[1575](https://github.com/nix-rust/nix/pull/1575)) - -### Removed - -## [0.23.0] - 2021-09-28 -### Added - -- Added the `LocalPeerCred` sockopt. - (#[1482](https://github.com/nix-rust/nix/pull/1482)) -- Added `TimeSpec::from_duration` and `TimeSpec::from_timespec` - (#[1465](https://github.com/nix-rust/nix/pull/1465)) -- Added `IPV6_V6ONLY` sockopt. - (#[1470](https://github.com/nix-rust/nix/pull/1470)) -- Added `impl From<User> for libc::passwd` trait implementation to convert a `User` - into a `libc::passwd`. Consumes the `User` struct to give ownership over - the member pointers. - (#[1471](https://github.com/nix-rust/nix/pull/1471)) -- Added `pthread_kill`. - (#[1472](https://github.com/nix-rust/nix/pull/1472)) -- Added `mknodat`. - (#[1473](https://github.com/nix-rust/nix/pull/1473)) -- Added `setrlimit` and `getrlimit`. - (#[1302](https://github.com/nix-rust/nix/pull/1302)) -- Added `ptrace::interrupt` method for platforms that support `PTRACE_INTERRUPT` - (#[1422](https://github.com/nix-rust/nix/pull/1422)) -- Added `IP6T_SO_ORIGINAL_DST` sockopt. - (#[1490](https://github.com/nix-rust/nix/pull/1490)) -- Added the `PTRACE_EVENT_STOP` variant to the `sys::ptrace::Event` enum - (#[1335](https://github.com/nix-rust/nix/pull/1335)) -- Exposed `SockAddr::from_raw_sockaddr` - (#[1447](https://github.com/nix-rust/nix/pull/1447)) -- Added `TcpRepair` - (#[1503](https://github.com/nix-rust/nix/pull/1503)) -- Enabled `pwritev` and `preadv` for more operating systems. - (#[1511](https://github.com/nix-rust/nix/pull/1511)) -- Added support for `TCP_MAXSEG` TCP Maximum Segment Size socket options - (#[1292](https://github.com/nix-rust/nix/pull/1292)) -- Added `Ipv4RecvErr` and `Ipv6RecvErr` sockopts and associated control messages. - (#[1514](https://github.com/nix-rust/nix/pull/1514)) -- Added `AsRawFd` implementation on `PollFd`. - (#[1516](https://github.com/nix-rust/nix/pull/1516)) -- Added `Ipv4Ttl` and `Ipv6Ttl` sockopts. - (#[1515](https://github.com/nix-rust/nix/pull/1515)) -- Added `MAP_EXCL`, `MAP_ALIGNED_SUPER`, and `MAP_CONCEAL` mmap flags, and - exposed `MAP_ANONYMOUS` for all operating systems. - (#[1522](https://github.com/nix-rust/nix/pull/1522)) - (#[1525](https://github.com/nix-rust/nix/pull/1525)) - (#[1531](https://github.com/nix-rust/nix/pull/1531)) - (#[1534](https://github.com/nix-rust/nix/pull/1534)) -- Added read/write accessors for 'events' on `PollFd`. - (#[1517](https://github.com/nix-rust/nix/pull/1517)) - -### Changed - -- `FdSet::{contains, highest, fds}` no longer require a mutable reference. - (#[1464](https://github.com/nix-rust/nix/pull/1464)) -- `User::gecos` and corresponding `libc::passwd::pw_gecos` are supported on - 64-bit Android, change conditional compilation to include the field in - 64-bit Android builds - (#[1471](https://github.com/nix-rust/nix/pull/1471)) -- `eventfd`s are supported on Android, change conditional compilation to - include `sys::eventfd::eventfd` and `sys::eventfd::EfdFlags`for Android - builds. - (#[1481](https://github.com/nix-rust/nix/pull/1481)) -- Most enums that come from C, for example `Errno`, are now marked as - `#[non_exhaustive]`. - (#[1474](https://github.com/nix-rust/nix/pull/1474)) -- Many more functions, mostly contructors, are now `const`. - (#[1476](https://github.com/nix-rust/nix/pull/1476)) - (#[1492](https://github.com/nix-rust/nix/pull/1492)) -- `sys::event::KEvent::filter` now returns a `Result` instead of being - infalliable. The only cases where it will now return an error are cases - where it previously would've had undefined behavior. - (#[1484](https://github.com/nix-rust/nix/pull/1484)) -- Minimum supported Rust version is now 1.46.0. - ([#1492](https://github.com/nix-rust/nix/pull/1492)) -- Rework `UnixAddr` to encapsulate internals better in order to fix soundness - issues. No longer allows creating a `UnixAddr` from a raw `sockaddr_un`. - ([#1496](https://github.com/nix-rust/nix/pull/1496)) -- Raised bitflags to 1.3.0 and the MSRV to 1.46.0. - ([#1492](https://github.com/nix-rust/nix/pull/1492)) - -### Fixed - -- `posix_fadvise` now returns errors in the conventional way, rather than as a - non-zero value in `Ok()`. - (#[1538](https://github.com/nix-rust/nix/pull/1538)) -- Added more errno definitions for better backwards compatibility with - Nix 0.21.0. - (#[1467](https://github.com/nix-rust/nix/pull/1467)) -- Fixed potential undefined behavior in `Signal::try_from` on some platforms. - (#[1484](https://github.com/nix-rust/nix/pull/1484)) -- Fixed buffer overflow in `unistd::getgrouplist`. - (#[1545](https://github.com/nix-rust/nix/pull/1545)) - - -### Removed - -- Removed a couple of termios constants on redox that were never actually - supported. - (#[1483](https://github.com/nix-rust/nix/pull/1483)) -- Removed `nix::sys::signal::NSIG`. It was of dubious utility, and not correct - for all platforms. - (#[1484](https://github.com/nix-rust/nix/pull/1484)) -- Removed support for 32-bit Apple targets, since they've been dropped by both - Rustc and Xcode. - (#[1492](https://github.com/nix-rust/nix/pull/1492)) -- Deprecated `SockAddr/InetAddr::to_str` in favor of `ToString::to_string` - (#[1495](https://github.com/nix-rust/nix/pull/1495)) -- Removed `SigevNotify` on OpenBSD and Redox. - (#[1511](https://github.com/nix-rust/nix/pull/1511)) - -## [0.22.0] - 9 July 2021 -### Added -- Added `if_nameindex` (#[1445](https://github.com/nix-rust/nix/pull/1445)) -- Added `nmount` for FreeBSD. - (#[1453](https://github.com/nix-rust/nix/pull/1453)) -- Added `IpFreebind` socket option (sockopt) on Linux, Fuchsia and Android. - (#[1456](https://github.com/nix-rust/nix/pull/1456)) -- Added `TcpUserTimeout` socket option (sockopt) on Linux and Fuchsia. - (#[1457](https://github.com/nix-rust/nix/pull/1457)) -- Added `renameat2` for Linux - (#[1458](https://github.com/nix-rust/nix/pull/1458)) -- Added `RxqOvfl` support on Linux, Fuchsia and Android. - (#[1455](https://github.com/nix-rust/nix/pull/1455)) - -### Changed -- `ptsname_r` now returns a lossily-converted string in the event of bad UTF, - just like `ptsname`. - ([#1446](https://github.com/nix-rust/nix/pull/1446)) -- Nix's error type is now a simple wrapper around the platform's Errno. This - means it is now `Into<std::io::Error>`. It's also `Clone`, `Copy`, `Eq`, and - has a small fixed size. It also requires less typing. For example, the old - enum variant `nix::Error::Sys(nix::errno::Errno::EINVAL)` is now simply - `nix::Error::EINVAL`. - ([#1446](https://github.com/nix-rust/nix/pull/1446)) - -### Fixed -### Removed - -## [0.21.0] - 31 May 2021 -### Added -- Added `getresuid` and `getresgid` - (#[1430](https://github.com/nix-rust/nix/pull/1430)) -- Added TIMESTAMPNS support for linux - (#[1402](https://github.com/nix-rust/nix/pull/1402)) -- Added `sendfile64` (#[1439](https://github.com/nix-rust/nix/pull/1439)) -- Added `MS_LAZYTIME` to `MsFlags` - (#[1437](https://github.com/nix-rust/nix/pull/1437)) - -### Changed -- Made `forkpty` unsafe, like `fork` - (#[1390](https://github.com/nix-rust/nix/pull/1390)) -- Made `Uid`, `Gid` and `Pid` methods `from_raw` and `as_raw` a `const fn` - (#[1429](https://github.com/nix-rust/nix/pull/1429)) -- Made `Uid::is_root` a `const fn` - (#[1429](https://github.com/nix-rust/nix/pull/1429)) -- `AioCb` is now always pinned. Once a `libc::aiocb` gets sent to the kernel, - its address in memory must not change. Nix now enforces that by using - `std::pin`. Most users won't need to change anything, except when using - `aio_suspend`. See that method's documentation for the new usage. - (#[1440](https://github.com/nix-rust/nix/pull/1440)) -- `LioCb` is now constructed using a distinct `LioCbBuilder` struct. This - avoids a soundness issue with the old `LioCb`. Usage is similar but - construction now uses the builder pattern. See the documentation for - details. - (#[1440](https://github.com/nix-rust/nix/pull/1440)) -- Minimum supported Rust version is now 1.41.0. - ([#1440](https://github.com/nix-rust/nix/pull/1440)) -- Errno aliases are now associated consts on `Errno`, instead of consts in the - `errno` module. - (#[1452](https://github.com/nix-rust/nix/pull/1452)) - -### Fixed -- Allow `sockaddr_ll` size, as reported by the Linux kernel, to be smaller then it's definition - (#[1395](https://github.com/nix-rust/nix/pull/1395)) -- Fix spurious errors using `sendmmsg` with multiple cmsgs - (#[1414](https://github.com/nix-rust/nix/pull/1414)) -- Added `Errno::EOPNOTSUPP` to FreeBSD, where it was missing. - (#[1452](https://github.com/nix-rust/nix/pull/1452)) - -### Removed - -- Removed `sys::socket::accept4` from Android arm because libc removed it in - version 0.2.87. - ([#1399](https://github.com/nix-rust/nix/pull/1399)) -- `AioCb::from_boxed_slice` and `AioCb::from_boxed_mut_slice` have been - removed. They were useful with earlier versions of Rust, but should no - longer be needed now that async/await are available. `AioCb`s now work - exclusively with borrowed buffers, not owned ones. - (#[1440](https://github.com/nix-rust/nix/pull/1440)) -- Removed some Errno values from platforms where they aren't actually defined. - (#[1452](https://github.com/nix-rust/nix/pull/1452)) +This project adheres to [Semantic Versioning](http://semver.org/). ## [0.20.0] - 20 February 2021 ### Added diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..55990c4 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,114 @@ +# Contributing to nix + +We're really glad you're interested in contributing to nix! This +document has a few pointers and guidelines to help get you started. + +To have a welcoming and inclusive project, nix uses the Rust project's +[Code of Conduct][conduct]. All contributors are expected to follow it. + +[conduct]: https://www.rust-lang.org/conduct.html + + +# Issues + +We use GitHub's [issue tracker][issues]. + +[issues]: https://github.com/nix-rust/nix/issues + + +## Bug reports + +Before submitting a new bug report, please [search existing +issues][issue-search] to see if there's something related. If not, just +[open a new issue][new-issue]! + +As a reminder, the more information you can give in your issue, the +easier it is to figure out how to fix it. For nix, this will likely +include the OS and version, and the architecture. + +[issue-search]: https://github.com/nix-rust/nix/search?utf8=%E2%9C%93&q=is%3Aissue&type=Issues +[new-issue]: https://github.com/nix-rust/nix/issues/new + + +## Feature / API requests + +If you'd like a new API or feature added, please [open a new +issue][new-issue] requesting it. As with reporting a bug, the more +information you can provide, the better. + + +## Labels + +We use labels to help manage issues. The structure is modeled after +[Rust's issue labeling scheme][rust-labels]: +- **A-**prefixed labels state which area of the project the issue + relates to +- **E-**prefixed labels explain the level of experience necessary to fix the + issue +- **O-**prefixed labels specify the OS for issues that are OS-specific +- **R-**prefixed labels specify the architecture for issues that are + architecture-specific + +[rust-labels]: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#issue-triage + + +# Pull requests + +GitHub pull requests are the primary mechanism we use to change nix. GitHub itself has +some [great documentation][pr-docs] on using the Pull Request feature. We use the 'fork and +pull' model described there. + +Please make pull requests against the `master` branch. + +If you change the API by way of adding, removing or changing something or if +you fix a bug, please add an appropriate note to the [change log][cl]. We +follow the conventions of [Keep A CHANGELOG][kacl]. + +[cl]: https://github.com/nix-rust/nix/blob/master/CHANGELOG.md +[kacl]: https://github.com/olivierlacan/keep-a-changelog/tree/18adb5f5be7a898d046f6a4acb93e39dcf40c4ad +[pr-docs]: https://help.github.com/articles/using-pull-requests/ + +## Testing + +nix has a test suite that you can run with `cargo test`. Ideally, we'd like pull +requests to include tests where they make sense. For example, when fixing a bug, +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 +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]. + +[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 `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 + +All pull requests are merged via [bors], an integration bot. After the +pull request has been reviewed, the reviewer will leave a comment like + +> bors r+ + +to let bors know that it was approved. Then bors will check that it passes +tests when merged with the latest changes in the `master` branch, and +merge if the tests succeed. + +[bors]: https://bors-ng.github.io/ + + +## API conventions + +If you're adding a new API, we have a [document with +conventions][conventions] to use throughout the nix project. + +[conventions]: https://github.com/nix-rust/nix/blob/master/CONVENTIONS.md diff --git a/CONVENTIONS.md b/CONVENTIONS.md new file mode 100644 index 0000000..2461085 --- /dev/null +++ b/CONVENTIONS.md @@ -0,0 +1,86 @@ +# Conventions + +In order to achieve our goal of wrapping [libc][libc] code in idiomatic rust +constructs with minimal performance overhead, we follow the following +conventions. + +Note that, thus far, not all the code follows these conventions and not all +conventions we try to follow have been documented here. If you find an instance +of either, feel free to remedy the flaw by opening a pull request with +appropriate changes or additions. + +## Change Log + +We follow the conventions laid out in [Keep A CHANGELOG][kacl]. + +[kacl]: https://github.com/olivierlacan/keep-a-changelog/tree/18adb5f5be7a898d046f6a4acb93e39dcf40c4ad + +## libc constants, functions and structs + +We do not define integer constants ourselves, but use or reexport them from the +[libc crate][libc]. + +We use the functions exported from [libc][libc] instead of writing our own +`extern` declarations. + +We use the `struct` definitions from [libc][libc] internally instead of writing +our own. If we want to add methods to a libc type, we use the newtype pattern. +For example, + +```rust +pub struct SigSet(libc::sigset_t); + +impl SigSet { + ... +} +``` + +When creating newtypes, we use Rust's `CamelCase` type naming convention. + +## Bitflags + +Many C functions have flags parameters that are combined from constants using +bitwise operations. We represent the types of these parameters by types defined +using our `libc_bitflags!` macro, which is a convenience wrapper around the +`bitflags!` macro from the [bitflags crate][bitflags] that brings in the +constant value from `libc`. + +We name the type for a set of constants whose element's names start with `FOO_` +`FooFlags`. + +For example, + +```rust +libc_bitflags!{ + pub struct ProtFlags: libc::c_int { + PROT_NONE; + PROT_READ; + PROT_WRITE; + PROT_EXEC; + #[cfg(any(target_os = "linux", target_os = "android"))] + PROT_GROWSDOWN; + #[cfg(any(target_os = "linux", target_os = "android"))] + PROT_GROWSUP; + } +} +``` + + +## Enumerations + +We represent sets of constants that are intended as mutually exclusive arguments +to parameters of functions by [enumerations][enum]. + + +## Structures Initialized by libc Functions + +Whenever we need to use a [libc][libc] function to properly initialize a +variable and said function allows us to use uninitialized memory, we use +[`std::mem::MaybeUninit`][std_MaybeUninit] when defining the variable. This +allows us to avoid the overhead incurred by zeroing or otherwise initializing +the variable. + +[bitflags]: https://crates.io/crates/bitflags/ +[enum]: https://doc.rust-lang.org/reference.html#enumerations +[libc]: https://crates.io/crates/libc/ +[std_MaybeUninit]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html @@ -3,25 +3,25 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. +# to registry (e.g., crates.io) dependencies # -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) [package] edition = "2018" -rust-version = "1.46" name = "nix" -version = "0.23.1" +version = "0.20.0" authors = ["The nix-rust Project Developers"] -include = ["src/**/*", "test/**/*", "LICENSE", "README.md", "CHANGELOG.md"] +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", "x86_64-unknown-illumos"] +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" @@ -54,29 +54,24 @@ version = "1.1" version = "1.0" [dependencies.libc] -version = "0.2.102" +version = "0.2.82" features = ["extra_traits"] -[dev-dependencies.assert-impl] -version = "0.1" +[dev-dependencies.bytes] +version = "0.4.8" [dev-dependencies.lazy_static] version = "1.2" -[dev-dependencies.parking_lot] -version = "0.11.2" - [dev-dependencies.rand] -version = "0.8" +version = "0.6" [dev-dependencies.semver] -version = "1.0.0" +version = "0.9.0" [dev-dependencies.tempfile] -version = "3.2.0" +version = "3.0.5" [target."cfg(any(target_os = \"android\", target_os = \"linux\"))".dev-dependencies.caps] version = "0.5.1" -[target."cfg(not(target_os = \"redox\"))".dependencies.memoffset] -version = "0.6.3" [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 d2ca8ee..885fa10 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -2,13 +2,19 @@ name = "nix" description = "Rust friendly bindings to *nix APIs" edition = "2018" -version = "0.23.1" -rust-version = "1.46" +version = "0.20.0" authors = ["The nix-rust Project Developers"] repository = "https://github.com/nix-rust/nix" license = "MIT" categories = ["os::unix-apis"] -include = ["src/**/*", "test/**/*", "LICENSE", "README.md", "CHANGELOG.md"] +exclude = [ + "/.gitignore", + "/.cirrus.yml", + "/ci/*", + "/Cross.toml", + "/RELEASE_PROCEDURE.md", + "/bors.toml" +] [package.metadata.docs.rs] targets = [ @@ -21,28 +27,23 @@ targets = [ "x86_64-unknown-netbsd", "x86_64-unknown-dragonfly", "x86_64-fuchsia", - "x86_64-unknown-redox", - "x86_64-unknown-illumos" + "x86_64-unknown-redox" ] [dependencies] -libc = { version = "0.2.102", features = [ "extra_traits" ] } +libc = { version = "0.2.82", features = [ "extra_traits" ] } bitflags = "1.1" cfg-if = "1.0" -[target.'cfg(not(target_os = "redox"))'.dependencies] -memoffset = "0.6.3" - [target.'cfg(target_os = "dragonfly")'.build-dependencies] cc = "1" [dev-dependencies] -assert-impl = "0.1" +bytes = "0.4.8" lazy_static = "1.2" -parking_lot = "0.11.2" -rand = "0.8" -tempfile = "3.2.0" -semver = "1.0.0" +rand = "0.6" +tempfile = "3.0.5" +semver = "0.9.0" [target.'cfg(any(target_os = "android", target_os = "linux"))'.dev-dependencies] caps = "0.5.1" @@ -7,13 +7,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/nix/nix-0.23.1.crate" + value: "https://static.crates.io/crates/nix/nix-0.20.0.crate" } - version: "0.23.1" + version: "0.20.0" license_type: NOTICE last_upgrade_date { - year: 2022 - month: 3 - day: 16 + year: 2021 + month: 4 + day: 2 } } @@ -1,7 +1,7 @@ # Rust bindings to *nix APIs [![Cirrus Build Status](https://api.cirrus-ci.com/github/nix-rust/nix.svg)](https://cirrus-ci.com/github/nix-rust/nix) -[![crates.io](https://img.shields.io/crates/v/nix.svg)](https://crates.io/crates/nix) +[![crates.io](http://meritbadge.herokuapp.com/nix)](https://crates.io/crates/nix) [Documentation (Releases)](https://docs.rs/nix/) @@ -17,7 +17,7 @@ usage. As an example of what Nix provides, examine the differences between what is exposed by libc and nix for the -[gethostname](https://man7.org/linux/man-pages/man2/gethostname.2.html) system +[gethostname](http://man7.org/linux/man-pages/man2/gethostname.2.html) system call: ```rust,ignore @@ -68,26 +68,33 @@ Tier 2: * aarch64-linux-android * arm-linux-androideabi * arm-unknown-linux-musleabi + * armv7-apple-ios * armv7-linux-androideabi + * armv7s-apple-ios + * i386-apple-ios + * i686-apple-darwin * i686-linux-android * powerpc-unknown-linux-gnu * s390x-unknown-linux-gnu * x86_64-apple-ios * x86_64-linux-android - * x86_64-unknown-illumos * x86_64-unknown-netbsd Tier 3: * x86_64-fuchsia - * x86_64-unknown-dragonfly - * x86_64-unknown-linux-gnux32 - * x86_64-unknown-openbsd * x86_64-unknown-redox + * x86_64-unknown-linux-gnux32 + +## Usage -## Minimum Supported Rust Version (MSRV) +`nix` requires Rust 1.40.0 or newer. -nix is supported on Rust 1.46.0 and higher. It's MSRV will not be -changed in the future without bumping the major or minor version. +To use `nix`, add this to your `Cargo.toml`: + +```toml +[dependencies] +nix = "0.20.0" +``` ## Contributing diff --git a/TEST_MAPPING b/TEST_MAPPING index b44b9e2..5d7fef5 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -1,102 +1,14 @@ // Generated by update_crate_tests.py for tests that depend on this crate. { - "imports": [ - { - "path": "external/rust/crates/tokio" - } - ], "presubmit": [ { - "name": "ZipFuseTest" - }, - { - "name": "apkdmverity.test" - }, - { - "name": "authfs_device_test_src_lib" - }, - { - "name": "diced_open_dice_cbor_test" - }, - { - "name": "diced_sample_inputs_test" - }, - { - "name": "diced_test" - }, - { - "name": "diced_utils_test" - }, - { - "name": "diced_vendor_test" - }, - { - "name": "keystore2_crypto_test_rust" - }, - { - "name": "keystore2_selinux_concurrency_test" - }, - { "name": "keystore2_test" }, { - "name": "keystore2_test_utils_test" - }, - { - "name": "legacykeystore_test" - }, - { - "name": "microdroid_manager_test" - }, - { - "name": "virtualizationservice_device_test" - } - ], - "presubmit-rust": [ - { - "name": "ZipFuseTest" - }, - { - "name": "apkdmverity.test" - }, - { - "name": "authfs_device_test_src_lib" - }, - { - "name": "diced_open_dice_cbor_test" - }, - { - "name": "diced_sample_inputs_test" - }, - { - "name": "diced_test" - }, - { - "name": "diced_utils_test" - }, - { - "name": "diced_vendor_test" - }, - { "name": "keystore2_crypto_test_rust" }, { - "name": "keystore2_selinux_concurrency_test" - }, - { - "name": "keystore2_test" - }, - { - "name": "keystore2_test_utils_test" - }, - { - "name": "legacykeystore_test" - }, - { - "name": "microdroid_manager_test" - }, - { - "name": "virtualizationservice_device_test" + "name": "vpnprofilestore_test" } ] } diff --git a/cargo2android.json b/cargo2android.json index f8fb37c..42b7833 100644 --- a/cargo2android.json +++ b/cargo2android.json @@ -1,13 +1,9 @@ { "apex-available": [ "//apex_available:platform", - "com.android.bluetooth", - "com.android.compos", "com.android.virt" ], "dependencies": true, "device": true, - "min-sdk-version": "29", - "run": true, - "vendor-available": true -} + "run": true +}
\ No newline at end of file diff --git a/patches/0001-Allow-android-compiled-binaries-to-use-timerfd.patch b/patches/0001-Allow-android-compiled-binaries-to-use-timerfd.patch new file mode 100644 index 0000000..e164a3c --- /dev/null +++ b/patches/0001-Allow-android-compiled-binaries-to-use-timerfd.patch @@ -0,0 +1,26 @@ +From e09a4f4e8661e8036819deb97dc1d9fcf2a49d2b Mon Sep 17 00:00:00 2001 +From: Zach Johnson <zachoverflow@google.com> +Date: Tue, 17 Nov 2020 11:05:57 -0800 +Subject: [PATCH] Allow android compiled binaries to use timerfd + +Bug: 171749953 +Test: compile +Change-Id: Iaf16615cf834df02537e3b569ab08dd98a497a70 +--- + src/sys/mod.rs | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/sys/mod.rs b/src/sys/mod.rs +index bf7f541..b8b9e6f 100644 +--- a/src/sys/mod.rs ++++ b/src/sys/mod.rs +@@ -103,5 +103,5 @@ pub mod wait; + #[cfg(any(target_os = "android", target_os = "linux"))] + pub mod inotify; + +-#[cfg(target_os = "linux")] ++#[cfg(any(target_os = "android", target_os = "linux"))] + pub mod timerfd; +-- +2.29.2.299.gdc1121823c-goog + @@ -53,12 +53,14 @@ impl Dir { /// Converts from a file descriptor, closing it on success or failure. pub fn from_fd(fd: RawFd) -> Result<Self> { - let d = ptr::NonNull::new(unsafe { libc::fdopendir(fd) }).ok_or_else(|| { + let d = unsafe { libc::fdopendir(fd) }; + if d.is_null() { let e = Error::last(); unsafe { libc::close(fd) }; - e - })?; - Ok(Dir(d)) + return Err(e); + }; + // Always guaranteed to be non-null by the previous check + Ok(Dir(ptr::NonNull::new(d).unwrap())) } /// Returns an iterator of `Result<Entry>` which rewinds when finished. @@ -84,7 +86,7 @@ impl AsRawFd for Dir { impl Drop for Dir { fn drop(&mut self) { let e = Errno::result(unsafe { libc::closedir(self.0.as_ptr()) }); - if !std::thread::panicking() && e == Err(Errno::EBADF) { + if !std::thread::panicking() && e == Err(Error::Sys(Errno::EBADF)) { panic!("Closing an invalid file descriptor!"); }; } @@ -190,7 +192,6 @@ impl Entry { target_os = "emscripten", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", target_os = "ios", target_os = "l4re", target_os = "linux", @@ -205,13 +206,11 @@ impl Entry { target_os = "emscripten", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", target_os = "ios", target_os = "l4re", target_os = "linux", target_os = "macos", target_os = "solaris")))] - #[allow(clippy::useless_conversion)] // Not useless on all OSes pub fn ino(&self) -> u64 { u64::from(self.0.d_fileno) } @@ -227,7 +226,6 @@ impl Entry { /// notably, some Linux filesystems don't implement this. The caller should use `stat` or /// `fstat` if this returns `None`. pub fn file_type(&self) -> Option<Type> { - #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] match self.0.d_type { libc::DT_FIFO => Some(Type::Fifo), libc::DT_CHR => Some(Type::CharacterDevice), @@ -238,9 +236,5 @@ impl Entry { libc::DT_SOCK => Some(Type::Socket), /* libc::DT_UNKNOWN | */ _ => None, } - - // illumos and Solaris systems do not have the d_type member at all: - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - None } } @@ -1,25 +1,12 @@ -//! Environment variables use cfg_if::cfg_if; -use std::fmt; - -/// Indicates that [`clearenv`] failed for some unknown reason -#[derive(Clone, Copy, Debug)] -pub struct ClearEnvError; - -impl fmt::Display for ClearEnvError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "clearenv failed") - } -} - -impl std::error::Error for ClearEnvError {} +use crate::{Error, Result}; /// Clear the environment of all name-value pairs. /// /// On platforms where libc provides `clearenv()`, it will be used. libc's /// `clearenv()` is documented to return an error code but not set errno; if the /// return value indicates a failure, this function will return -/// [`ClearEnvError`]. +/// `Error::UnsupportedOperation`. /// /// On platforms where libc does not provide `clearenv()`, a fallback /// implementation will be used that iterates over all environment variables and @@ -38,7 +25,8 @@ impl std::error::Error for ClearEnvError {} /// `environ` is currently held. The latter is not an issue if the only other /// environment access in the program is via `std::env`, but the requirement on /// thread safety must still be upheld. -pub unsafe fn clearenv() -> std::result::Result<(), ClearEnvError> { +pub unsafe fn clearenv() -> Result<()> { + let ret; cfg_if! { if #[cfg(any(target_os = "fuchsia", target_os = "wasi", @@ -47,19 +35,19 @@ pub unsafe fn clearenv() -> std::result::Result<(), ClearEnvError> { target_os = "linux", target_os = "android", target_os = "emscripten"))] { - let ret = libc::clearenv(); + ret = libc::clearenv(); } else { use std::env; for (name, _) in env::vars_os() { env::remove_var(name); } - let ret = 0; + ret = 0; } } if ret == 0 { Ok(()) } else { - Err(ClearEnvError) + Err(Error::UnsupportedOperation) } } diff --git a/src/errno.rs b/src/errno.rs index 3da246e..e5c7092 100644 --- a/src/errno.rs +++ b/src/errno.rs @@ -1,6 +1,5 @@ use cfg_if::cfg_if; use libc::{c_int, c_void}; -use std::convert::TryFrom; use std::{fmt, io, error}; use crate::{Error, Result}; @@ -26,10 +25,6 @@ cfg_if! { unsafe fn errno_location() -> *mut c_int { libc::__errno_location() } - } else if #[cfg(any(target_os = "illumos", target_os = "solaris"))] { - unsafe fn errno_location() -> *mut c_int { - libc::___errno() - } } } @@ -49,43 +44,6 @@ pub fn errno() -> i32 { } impl Errno { - /// Convert this `Error` to an [`Errno`](enum.Errno.html). - /// - /// # Example - /// - /// ``` - /// # use nix::Error; - /// # use nix::errno::Errno; - /// let e = Error::from(Errno::EPERM); - /// assert_eq!(Some(Errno::EPERM), e.as_errno()); - /// ``` - #[deprecated( - since = "0.22.0", - note = "It's a no-op now; just delete it." - )] - pub const fn as_errno(self) -> Option<Self> { - Some(self) - } - - /// Create a nix Error from a given errno - #[deprecated( - since = "0.22.0", - note = "It's a no-op now; just delete it." - )] - #[allow(clippy::wrong_self_convention)] // False positive - pub fn from_errno(errno: Errno) -> Error { - errno - } - - /// Create a new invalid argument error (`EINVAL`) - #[deprecated( - since = "0.22.0", - note = "Use Errno::EINVAL instead" - )] - pub const fn invalid_argument() -> Error { - Errno::EINVAL - } - pub fn last() -> Self { last() } @@ -94,7 +52,7 @@ impl Errno { desc(self) } - pub const fn from_i32(err: i32) -> Errno { + pub fn from_i32(err: i32) -> Errno { from_i32(err) } @@ -104,29 +62,13 @@ impl Errno { /// Returns `Ok(value)` if it does not contain the sentinel value. This /// should not be used when `-1` is not the errno sentinel value. - #[inline] pub fn result<S: ErrnoSentinel + PartialEq<S>>(value: S) -> Result<S> { if value == S::sentinel() { - Err(Self::last()) + Err(Error::Sys(Self::last())) } else { Ok(value) } } - - /// Backwards compatibility hack for Nix <= 0.21.0 users - /// - /// In older versions of Nix, `Error::Sys` was an enum variant. Now it's a - /// function, which is compatible with most of the former use cases of the - /// enum variant. But you should use `Error(Errno::...)` instead. - #[deprecated( - since = "0.22.0", - note = "Use Errno::... instead" - )] - #[allow(non_snake_case)] - #[inline] - pub const fn Sys(errno: Errno) -> Error { - errno - } } /// The sentinel value indicates that a function failed and more detailed @@ -148,7 +90,7 @@ impl ErrnoSentinel for i64 { } impl ErrnoSentinel for *mut c_void { - fn sentinel() -> Self { -1isize as *mut c_void } + fn sentinel() -> Self { (-1 as isize) as *mut c_void } } impl ErrnoSentinel for libc::sighandler_t { @@ -169,16 +111,6 @@ impl From<Errno> for io::Error { } } -impl TryFrom<io::Error> for Errno { - type Error = io::Error; - - fn try_from(ioerror: io::Error) -> std::result::Result<Self, io::Error> { - ioerror.raw_os_error() - .map(Errno::from_i32) - .ok_or(ioerror) - } -} - fn last() -> Errno { Errno::from_i32(errno()) } @@ -258,142 +190,114 @@ fn desc(errno: Errno) -> &'static str { EHOSTUNREACH => "No route to host", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] ECHRNG => "Channel number out of range", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] EL2NSYNC => "Level 2 not synchronized", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] EL3HLT => "Level 3 halted", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] EL3RST => "Level 3 reset", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] ELNRNG => "Link number out of range", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] EUNATCH => "Protocol driver not attached", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] ENOCSI => "No CSI structure available", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] EL2HLT => "Level 2 halted", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] EBADE => "Invalid exchange", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] EBADR => "Invalid request descriptor", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] EXFULL => "Exchange full", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] ENOANO => "No anode", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] EBADRQC => "Invalid request code", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] EBADSLT => "Invalid slot", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] EBFONT => "Bad font file format", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] ENOSTR => "Device not a stream", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] ENODATA => "No data available", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] ETIME => "Timer expired", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] ENOSR => "Out of streams resources", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] ENONET => "Machine is not on the network", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] ENOPKG => "Package not installed", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] EREMOTE => "Object is remote", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] ENOLINK => "Link has been severed", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] EADV => "Advertise error", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] ESRMNT => "Srmount error", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] ECOMM => "Communication error on send", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] EPROTO => "Protocol error", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] EMULTIHOP => "Multihop attempted", @@ -405,70 +309,55 @@ fn desc(errno: Errno) -> &'static str { target_os = "fuchsia"))] EBADMSG => "Not a data message", - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - EBADMSG => "Trying to read unreadable message", - #[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", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] ENOTUNIQ => "Name not unique on network", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] EBADFD => "File descriptor in bad state", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] EREMCHG => "Remote address changed", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] ELIBACC => "Can not access a needed shared library", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] ELIBBAD => "Accessing a corrupted shared library", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] ELIBSCN => ".lib section in a.out corrupted", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] ELIBMAX => "Attempting to link in too many shared libraries", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] ELIBEXEC => "Cannot exec a shared library directly", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia", target_os = "openbsd"))] EILSEQ => "Illegal byte sequence", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] ERESTART => "Interrupted system call should be restarted", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] ESTRPIPE => "Streams pipe error", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] EUSERS => "Too many users", @@ -515,7 +404,6 @@ fn desc(errno: Errno) -> &'static str { EMEDIUMTYPE => "Wrong medium type", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", target_os = "fuchsia"))] ECANCELED => "Operation canceled", @@ -539,16 +427,10 @@ fn desc(errno: Errno) -> &'static str { target_os = "fuchsia"))] EOWNERDEAD => "Owner died", - #[cfg(any( target_os = "illumos", target_os = "solaris"))] - EOWNERDEAD => "Process died with lock", - #[cfg(any(target_os = "linux", target_os = "android", target_os = "fuchsia"))] ENOTRECOVERABLE => "State not recoverable", - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - ENOTRECOVERABLE => "Lock is not recoverable", - #[cfg(any(all(target_os = "linux", not(target_arch="mips")), target_os = "fuchsia"))] ERFKILL => "Operation not possible due to RF-kill", @@ -563,8 +445,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "redox"))] EMULTIHOP => "Multihop attempted", - #[cfg(any(target_os = "freebsd", target_os = "dragonfly", - target_os = "redox"))] + #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "redox"))] ENOLINK => "Link has been severed", #[cfg(target_os = "freebsd")] @@ -581,8 +462,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "dragonfly", target_os = "ios", target_os = "openbsd", target_os = "netbsd", - target_os = "redox", target_os = "illumos", - target_os = "solaris"))] + target_os = "redox"))] EOVERFLOW => "Value too large to be stored in data type", #[cfg(any(target_os = "macos", target_os = "freebsd", @@ -608,7 +488,7 @@ fn desc(errno: Errno) -> &'static str { EPROTO => "Protocol error", #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "ios", target_os = "openbsd"))] + target_os = "ios", target_os = "openbsd", ))] ENOTRECOVERABLE => "State not recoverable", #[cfg(any(target_os = "macos", target_os = "freebsd", @@ -617,8 +497,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "dragonfly", target_os = "ios", - target_os = "openbsd", target_os = "netbsd", - target_os = "illumos", target_os = "solaris"))] + target_os = "openbsd", target_os = "netbsd"))] ENOTSUP => "Operation not supported", #[cfg(any(target_os = "macos", target_os = "freebsd", @@ -635,15 +514,13 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "dragonfly", target_os = "ios", target_os = "openbsd", target_os = "netbsd", - target_os = "redox", target_os = "illumos", - target_os = "solaris"))] + target_os = "redox"))] EDQUOT => "Disc quota exceeded", #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "dragonfly", target_os = "ios", target_os = "openbsd", target_os = "netbsd", - target_os = "redox", target_os = "illumos", - target_os = "solaris"))] + target_os = "redox"))] ESTALE => "Stale NFS file handle", #[cfg(any(target_os = "macos", target_os = "freebsd", @@ -711,16 +588,14 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any(target_os = "macos", target_os = "ios"))] EBADMACHO => "Malformed Macho file", - #[cfg(any(target_os = "macos", target_os = "ios", - target_os = "netbsd"))] + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))] EMULTIHOP => "Reserved", #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd", target_os = "redox"))] ENODATA => "No message available on STREAM", - #[cfg(any(target_os = "macos", target_os = "ios", - target_os = "netbsd"))] + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))] ENOLINK => "Reserved", #[cfg(any(target_os = "macos", target_os = "ios", @@ -735,8 +610,7 @@ fn desc(errno: Errno) -> &'static str { target_os = "netbsd", target_os = "redox"))] ETIME => "STREAM ioctl timeout", - #[cfg(any(target_os = "macos", target_os = "ios", - target_os = "illumos", target_os = "solaris"))] + #[cfg(any(target_os = "macos", target_os = "ios"))] EOPNOTSUPP => "Operation not supported on socket", #[cfg(any(target_os = "macos", target_os = "ios"))] @@ -753,15 +627,6 @@ fn desc(errno: Errno) -> &'static str { #[cfg(target_os = "dragonfly")] EASYNC => "Async", - - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - EDEADLOCK => "Resource deadlock would occur", - - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - ELOCKUNMAPPED => "Locked lock was unmapped", - - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - ENOTACTIVE => "Facility is not active", } } @@ -770,7 +635,6 @@ fn desc(errno: Errno) -> &'static str { mod consts { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(i32)] - #[non_exhaustive] pub enum Errno { UnknownErrno = 0, EPERM = libc::EPERM, @@ -908,29 +772,11 @@ mod consts { EHWPOISON = libc::EHWPOISON, } - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EWOULDBLOCK instead" - )] pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EDEADLOCK instead" - )] pub const EDEADLOCK: Errno = Errno::EDEADLK; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::ENOTSUP instead" - )] - pub const ENOTSUP: Errno = Errno::EOPNOTSUPP; - - impl Errno { - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - pub const EDEADLOCK: Errno = Errno::EDEADLK; - pub const ENOTSUP: Errno = Errno::EOPNOTSUPP; - } + pub const ENOTSUP: Errno = Errno::EOPNOTSUPP; - pub const fn from_i32(e: i32) -> Errno { + pub fn from_i32(e: i32) -> Errno { use self::Errno::*; match e { @@ -1076,7 +922,6 @@ mod consts { mod consts { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(i32)] - #[non_exhaustive] pub enum Errno { UnknownErrno = 0, EPERM = libc::EPERM, @@ -1187,29 +1032,13 @@ mod consts { EQFULL = libc::EQFULL, } - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::ELAST instead" - )] - pub const ELAST: Errno = Errno::EQFULL; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EWOULDBLOCK instead" - )] + pub const ELAST: Errno = Errno::EQFULL; pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EDEADLOCK instead" - )] pub const EDEADLOCK: Errno = Errno::EDEADLK; - impl Errno { - pub const ELAST: Errno = Errno::EQFULL; - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - pub const EDEADLOCK: Errno = Errno::EDEADLK; - } + pub const EL2NSYNC: Errno = Errno::UnknownErrno; - pub const fn from_i32(e: i32) -> Errno { + pub fn from_i32(e: i32) -> Errno { use self::Errno::*; match e { @@ -1328,7 +1157,6 @@ mod consts { mod consts { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(i32)] - #[non_exhaustive] pub enum Errno { UnknownErrno = 0, EPERM = libc::EPERM, @@ -1429,35 +1257,13 @@ mod consts { EOWNERDEAD = libc::EOWNERDEAD, } - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::ELAST instead" - )] pub const ELAST: Errno = Errno::EOWNERDEAD; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EWOULDBLOCK instead" - )] pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EDEADLOCK instead" - )] pub const EDEADLOCK: Errno = Errno::EDEADLK; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EOPNOTSUPP instead" - )] - pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; - impl Errno { - pub const ELAST: Errno = Errno::EOWNERDEAD; - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - pub const EDEADLOCK: Errno = Errno::EDEADLK; - pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; - } + pub const EL2NSYNC: Errno = Errno::UnknownErrno; - pub const fn from_i32(e: i32) -> Errno { + pub fn from_i32(e: i32) -> Errno { use self::Errno::*; match e { @@ -1567,7 +1373,6 @@ mod consts { mod consts { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(i32)] - #[non_exhaustive] pub enum Errno { UnknownErrno = 0, EPERM = libc::EPERM, @@ -1666,35 +1471,14 @@ mod consts { EASYNC = libc::EASYNC, } - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::ELAST instead" - )] pub const ELAST: Errno = Errno::EASYNC; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EWOULDBLOCK instead" - )] pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EDEADLOCK instead" - )] pub const EDEADLOCK: Errno = Errno::EDEADLK; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EOPNOTSUPP instead" - )] pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; - impl Errno { - pub const ELAST: Errno = Errno::EASYNC; - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - pub const EDEADLOCK: Errno = Errno::EDEADLK; - pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; - } + pub const EL2NSYNC: Errno = Errno::UnknownErrno; - pub const fn from_i32(e: i32) -> Errno { + pub fn from_i32(e: i32) -> Errno { use self::Errno::*; match e { @@ -1802,7 +1586,6 @@ mod consts { mod consts { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(i32)] - #[non_exhaustive] pub enum Errno { UnknownErrno = 0, EPERM = libc::EPERM, @@ -1902,23 +1685,12 @@ mod consts { EPROTO = libc::EPROTO, } - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::ELAST instead" - )] pub const ELAST: Errno = Errno::ENOTSUP; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EWOULDBLOCK instead" - )] pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - impl Errno { - pub const ELAST: Errno = Errno::ENOTSUP; - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - } + pub const EL2NSYNC: Errno = Errno::UnknownErrno; - pub const fn from_i32(e: i32) -> Errno { + pub fn from_i32(e: i32) -> Errno { use self::Errno::*; match e { @@ -2026,7 +1798,6 @@ mod consts { mod consts { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(i32)] - #[non_exhaustive] pub enum Errno { UnknownErrno = 0, EPERM = libc::EPERM, @@ -2127,23 +1898,12 @@ mod consts { EPROTO = libc::EPROTO, } - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::ELAST instead" - )] pub const ELAST: Errno = Errno::ENOTSUP; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EWOULDBLOCK instead" - )] pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - impl Errno { - pub const ELAST: Errno = Errno::ENOTSUP; - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - } + pub const EL2NSYNC: Errno = Errno::UnknownErrno; - pub const fn from_i32(e: i32) -> Errno { + pub fn from_i32(e: i32) -> Errno { use self::Errno::*; match e { @@ -2252,7 +2012,6 @@ mod consts { mod consts { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(i32)] - #[non_exhaustive] pub enum Errno { UnknownErrno = 0, EPERM = libc::EPERM, @@ -2342,17 +2101,12 @@ mod consts { EPROTO = libc::EPROTO, } - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EWOULDBLOCK instead" - )] + pub const ELAST: Errno = Errno::UnknownErrno; pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - impl Errno { - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - } + pub const EL2NSYNC: Errno = Errno::UnknownErrno; - pub const fn from_i32(e: i32) -> Errno { + pub fn from_i32(e: i32) -> Errno { use self::Errno::*; match e { @@ -2445,279 +2199,3 @@ mod consts { } } } - -#[cfg(any(target_os = "illumos", target_os = "solaris"))] -mod consts { - #[derive(Clone, Copy, Debug, Eq, PartialEq)] - #[repr(i32)] - #[non_exhaustive] - pub enum Errno { - UnknownErrno = 0, - EPERM = libc::EPERM, - ENOENT = libc::ENOENT, - ESRCH = libc::ESRCH, - EINTR = libc::EINTR, - EIO = libc::EIO, - ENXIO = libc::ENXIO, - E2BIG = libc::E2BIG, - ENOEXEC = libc::ENOEXEC, - EBADF = libc::EBADF, - ECHILD = libc::ECHILD, - EAGAIN = libc::EAGAIN, - ENOMEM = libc::ENOMEM, - EACCES = libc::EACCES, - EFAULT = libc::EFAULT, - ENOTBLK = libc::ENOTBLK, - EBUSY = libc::EBUSY, - EEXIST = libc::EEXIST, - EXDEV = libc::EXDEV, - ENODEV = libc::ENODEV, - ENOTDIR = libc::ENOTDIR, - EISDIR = libc::EISDIR, - EINVAL = libc::EINVAL, - ENFILE = libc::ENFILE, - EMFILE = libc::EMFILE, - ENOTTY = libc::ENOTTY, - ETXTBSY = libc::ETXTBSY, - EFBIG = libc::EFBIG, - ENOSPC = libc::ENOSPC, - ESPIPE = libc::ESPIPE, - EROFS = libc::EROFS, - EMLINK = libc::EMLINK, - EPIPE = libc::EPIPE, - EDOM = libc::EDOM, - ERANGE = libc::ERANGE, - ENOMSG = libc::ENOMSG, - EIDRM = libc::EIDRM, - ECHRNG = libc::ECHRNG, - EL2NSYNC = libc::EL2NSYNC, - EL3HLT = libc::EL3HLT, - EL3RST = libc::EL3RST, - ELNRNG = libc::ELNRNG, - EUNATCH = libc::EUNATCH, - ENOCSI = libc::ENOCSI, - EL2HLT = libc::EL2HLT, - EDEADLK = libc::EDEADLK, - ENOLCK = libc::ENOLCK, - ECANCELED = libc::ECANCELED, - ENOTSUP = libc::ENOTSUP, - EDQUOT = libc::EDQUOT, - EBADE = libc::EBADE, - EBADR = libc::EBADR, - EXFULL = libc::EXFULL, - ENOANO = libc::ENOANO, - EBADRQC = libc::EBADRQC, - EBADSLT = libc::EBADSLT, - EDEADLOCK = libc::EDEADLOCK, - EBFONT = libc::EBFONT, - EOWNERDEAD = libc::EOWNERDEAD, - ENOTRECOVERABLE = libc::ENOTRECOVERABLE, - ENOSTR = libc::ENOSTR, - ENODATA = libc::ENODATA, - ETIME = libc::ETIME, - ENOSR = libc::ENOSR, - ENONET = libc::ENONET, - ENOPKG = libc::ENOPKG, - EREMOTE = libc::EREMOTE, - ENOLINK = libc::ENOLINK, - EADV = libc::EADV, - ESRMNT = libc::ESRMNT, - ECOMM = libc::ECOMM, - EPROTO = libc::EPROTO, - ELOCKUNMAPPED = libc::ELOCKUNMAPPED, - ENOTACTIVE = libc::ENOTACTIVE, - EMULTIHOP = libc::EMULTIHOP, - EBADMSG = libc::EBADMSG, - ENAMETOOLONG = libc::ENAMETOOLONG, - EOVERFLOW = libc::EOVERFLOW, - ENOTUNIQ = libc::ENOTUNIQ, - EBADFD = libc::EBADFD, - EREMCHG = libc::EREMCHG, - ELIBACC = libc::ELIBACC, - ELIBBAD = libc::ELIBBAD, - ELIBSCN = libc::ELIBSCN, - ELIBMAX = libc::ELIBMAX, - ELIBEXEC = libc::ELIBEXEC, - EILSEQ = libc::EILSEQ, - ENOSYS = libc::ENOSYS, - ELOOP = libc::ELOOP, - ERESTART = libc::ERESTART, - ESTRPIPE = libc::ESTRPIPE, - ENOTEMPTY = libc::ENOTEMPTY, - EUSERS = libc::EUSERS, - ENOTSOCK = libc::ENOTSOCK, - EDESTADDRREQ = libc::EDESTADDRREQ, - EMSGSIZE = libc::EMSGSIZE, - EPROTOTYPE = libc::EPROTOTYPE, - ENOPROTOOPT = libc::ENOPROTOOPT, - EPROTONOSUPPORT = libc::EPROTONOSUPPORT, - ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, - EOPNOTSUPP = libc::EOPNOTSUPP, - EPFNOSUPPORT = libc::EPFNOSUPPORT, - EAFNOSUPPORT = libc::EAFNOSUPPORT, - EADDRINUSE = libc::EADDRINUSE, - EADDRNOTAVAIL = libc::EADDRNOTAVAIL, - ENETDOWN = libc::ENETDOWN, - ENETUNREACH = libc::ENETUNREACH, - ENETRESET = libc::ENETRESET, - ECONNABORTED = libc::ECONNABORTED, - ECONNRESET = libc::ECONNRESET, - ENOBUFS = libc::ENOBUFS, - EISCONN = libc::EISCONN, - ENOTCONN = libc::ENOTCONN, - ESHUTDOWN = libc::ESHUTDOWN, - ETOOMANYREFS = libc::ETOOMANYREFS, - ETIMEDOUT = libc::ETIMEDOUT, - ECONNREFUSED = libc::ECONNREFUSED, - EHOSTDOWN = libc::EHOSTDOWN, - EHOSTUNREACH = libc::EHOSTUNREACH, - EALREADY = libc::EALREADY, - EINPROGRESS = libc::EINPROGRESS, - ESTALE = libc::ESTALE, - } - - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::ELAST instead" - )] - pub const ELAST: Errno = Errno::ELAST; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EWOULDBLOCK instead" - )] - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - - impl Errno { - pub const ELAST: Errno = Errno::ESTALE; - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - } - - pub const fn from_i32(e: i32) -> Errno { - use self::Errno::*; - - match e { - libc::EPERM => EPERM, - libc::ENOENT => ENOENT, - libc::ESRCH => ESRCH, - libc::EINTR => EINTR, - libc::EIO => EIO, - libc::ENXIO => ENXIO, - libc::E2BIG => E2BIG, - libc::ENOEXEC => ENOEXEC, - libc::EBADF => EBADF, - libc::ECHILD => ECHILD, - libc::EAGAIN => EAGAIN, - libc::ENOMEM => ENOMEM, - libc::EACCES => EACCES, - libc::EFAULT => EFAULT, - libc::ENOTBLK => ENOTBLK, - libc::EBUSY => EBUSY, - libc::EEXIST => EEXIST, - libc::EXDEV => EXDEV, - libc::ENODEV => ENODEV, - libc::ENOTDIR => ENOTDIR, - libc::EISDIR => EISDIR, - libc::EINVAL => EINVAL, - libc::ENFILE => ENFILE, - libc::EMFILE => EMFILE, - libc::ENOTTY => ENOTTY, - libc::ETXTBSY => ETXTBSY, - libc::EFBIG => EFBIG, - libc::ENOSPC => ENOSPC, - libc::ESPIPE => ESPIPE, - libc::EROFS => EROFS, - libc::EMLINK => EMLINK, - libc::EPIPE => EPIPE, - libc::EDOM => EDOM, - libc::ERANGE => ERANGE, - libc::ENOMSG => ENOMSG, - libc::EIDRM => EIDRM, - libc::ECHRNG => ECHRNG, - libc::EL2NSYNC => EL2NSYNC, - libc::EL3HLT => EL3HLT, - libc::EL3RST => EL3RST, - libc::ELNRNG => ELNRNG, - libc::EUNATCH => EUNATCH, - libc::ENOCSI => ENOCSI, - libc::EL2HLT => EL2HLT, - libc::EDEADLK => EDEADLK, - libc::ENOLCK => ENOLCK, - libc::ECANCELED => ECANCELED, - libc::ENOTSUP => ENOTSUP, - libc::EDQUOT => EDQUOT, - libc::EBADE => EBADE, - libc::EBADR => EBADR, - libc::EXFULL => EXFULL, - libc::ENOANO => ENOANO, - libc::EBADRQC => EBADRQC, - libc::EBADSLT => EBADSLT, - libc::EDEADLOCK => EDEADLOCK, - libc::EBFONT => EBFONT, - libc::EOWNERDEAD => EOWNERDEAD, - libc::ENOTRECOVERABLE => ENOTRECOVERABLE, - libc::ENOSTR => ENOSTR, - libc::ENODATA => ENODATA, - libc::ETIME => ETIME, - libc::ENOSR => ENOSR, - libc::ENONET => ENONET, - libc::ENOPKG => ENOPKG, - libc::EREMOTE => EREMOTE, - libc::ENOLINK => ENOLINK, - libc::EADV => EADV, - libc::ESRMNT => ESRMNT, - libc::ECOMM => ECOMM, - libc::EPROTO => EPROTO, - libc::ELOCKUNMAPPED => ELOCKUNMAPPED, - libc::ENOTACTIVE => ENOTACTIVE, - libc::EMULTIHOP => EMULTIHOP, - libc::EBADMSG => EBADMSG, - libc::ENAMETOOLONG => ENAMETOOLONG, - libc::EOVERFLOW => EOVERFLOW, - libc::ENOTUNIQ => ENOTUNIQ, - libc::EBADFD => EBADFD, - libc::EREMCHG => EREMCHG, - libc::ELIBACC => ELIBACC, - libc::ELIBBAD => ELIBBAD, - libc::ELIBSCN => ELIBSCN, - libc::ELIBMAX => ELIBMAX, - libc::ELIBEXEC => ELIBEXEC, - libc::EILSEQ => EILSEQ, - libc::ENOSYS => ENOSYS, - libc::ELOOP => ELOOP, - libc::ERESTART => ERESTART, - libc::ESTRPIPE => ESTRPIPE, - libc::ENOTEMPTY => ENOTEMPTY, - libc::EUSERS => EUSERS, - libc::ENOTSOCK => ENOTSOCK, - libc::EDESTADDRREQ => EDESTADDRREQ, - libc::EMSGSIZE => EMSGSIZE, - libc::EPROTOTYPE => EPROTOTYPE, - libc::ENOPROTOOPT => ENOPROTOOPT, - libc::EPROTONOSUPPORT => EPROTONOSUPPORT, - libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT, - libc::EOPNOTSUPP => EOPNOTSUPP, - libc::EPFNOSUPPORT => EPFNOSUPPORT, - libc::EAFNOSUPPORT => EAFNOSUPPORT, - libc::EADDRINUSE => EADDRINUSE, - libc::EADDRNOTAVAIL => EADDRNOTAVAIL, - libc::ENETDOWN => ENETDOWN, - libc::ENETUNREACH => ENETUNREACH, - libc::ENETRESET => ENETRESET, - libc::ECONNABORTED => ECONNABORTED, - libc::ECONNRESET => ECONNRESET, - libc::ENOBUFS => ENOBUFS, - libc::EISCONN => EISCONN, - libc::ENOTCONN => ENOTCONN, - libc::ESHUTDOWN => ESHUTDOWN, - libc::ETOOMANYREFS => ETOOMANYREFS, - libc::ETIMEDOUT => ETIMEDOUT, - libc::ECONNREFUSED => ECONNREFUSED, - libc::EHOSTDOWN => EHOSTDOWN, - libc::EHOSTUNREACH => EHOSTUNREACH, - libc::EALREADY => EALREADY, - libc::EINPROGRESS => EINPROGRESS, - libc::ESTALE => ESTALE, - _ => UnknownErrno, - } - } -} diff --git a/src/fcntl.rs b/src/fcntl.rs index dd8e59a..d2242da 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -34,8 +34,6 @@ libc_bitflags! { AT_NO_AUTOMOUNT; #[cfg(any(target_os = "android", target_os = "linux"))] AT_EMPTY_PATH; - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - AT_EACCESS; } } @@ -50,7 +48,6 @@ libc_bitflags!( /// Open the file in append-only mode. O_APPEND; /// Generate a signal when input or output becomes possible. - #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] O_ASYNC; /// Closes the file descriptor once an `execve` call is made. /// @@ -66,7 +63,6 @@ libc_bitflags!( target_os = "netbsd"))] O_DIRECT; /// If the specified path isn't a directory, fail. - #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] O_DIRECTORY; /// Implicitly follow each `write()` with an `fdatasync()`. #[cfg(any(target_os = "android", @@ -166,7 +162,7 @@ libc_bitflags!( ); // The conversion is not identical on all operating systems. -#[allow(clippy::useless_conversion)] +#[allow(clippy::identity_conversion)] pub fn open<P: ?Sized + NixPath>(path: &P, oflag: OFlag, mode: Mode) -> Result<RawFd> { let fd = path.with_nix_path(|cstr| { unsafe { libc::open(cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) } @@ -176,7 +172,7 @@ pub fn open<P: ?Sized + NixPath>(path: &P, oflag: OFlag, mode: Mode) -> Result<R } // The conversion is not identical on all operating systems. -#[allow(clippy::useless_conversion)] +#[allow(clippy::identity_conversion)] #[cfg(not(target_os = "redox"))] pub fn openat<P: ?Sized + NixPath>( dirfd: RawFd, @@ -210,43 +206,6 @@ pub fn renameat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( Errno::result(res).map(drop) } -#[cfg(all( - target_os = "linux", - target_env = "gnu", -))] -libc_bitflags! { - pub struct RenameFlags: u32 { - RENAME_EXCHANGE; - RENAME_NOREPLACE; - RENAME_WHITEOUT; - } -} - -#[cfg(all( - target_os = "linux", - target_env = "gnu", -))] -pub fn renameat2<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( - old_dirfd: Option<RawFd>, - old_path: &P1, - new_dirfd: Option<RawFd>, - new_path: &P2, - flags: RenameFlags, -) -> Result<()> { - let res = old_path.with_nix_path(|old_cstr| { - new_path.with_nix_path(|new_cstr| unsafe { - libc::renameat2( - at_rawfd(old_dirfd), - old_cstr.as_ptr(), - at_rawfd(new_dirfd), - new_cstr.as_ptr(), - flags.bits(), - ) - }) - })??; - Errno::result(res).map(drop) -} - fn wrap_readlink_result(mut v: Vec<u8>, len: ssize_t) -> Result<OsString> { unsafe { v.set_len(len as usize) } v.shrink_to_fit(); @@ -289,19 +248,8 @@ fn inner_readlink<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P) -> Result } // Uh oh, the result is too long... // Let's try to ask lstat how many bytes to allocate. - let reported_size = match dirfd { - #[cfg(target_os = "redox")] - Some(_) => unreachable!(), - #[cfg(any(target_os = "android", target_os = "linux"))] - Some(dirfd) => { - let flags = if path.is_empty() { AtFlags::AT_EMPTY_PATH } else { AtFlags::empty() }; - super::sys::stat::fstatat(dirfd, path, flags | AtFlags::AT_SYMLINK_NOFOLLOW) - }, - #[cfg(not(any(target_os = "android", target_os = "linux", target_os = "redox")))] - Some(dirfd) => super::sys::stat::fstatat(dirfd, path, AtFlags::AT_SYMLINK_NOFOLLOW), - None => super::sys::stat::lstat(path) - } - .map(|x| x.st_size) + let reported_size = super::sys::stat::lstat(path) + .and_then(|x| Ok(x.st_size)) .unwrap_or(0); let mut try_size = if reported_size > 0 { // Note: even if `lstat`'s apparently valid answer turns out to be @@ -325,7 +273,7 @@ fn inner_readlink<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P) -> Result Some(next_size) => try_size = next_size, // It's absurd that this would happen, but handle it sanely // anyway. - None => break Err(Errno::ENAMETOOLONG), + None => break Err(super::Error::Sys(Errno::ENAMETOOLONG)), } } } @@ -374,7 +322,6 @@ libc_bitflags!( #[cfg(not(target_os = "redox"))] #[derive(Debug, Eq, Hash, PartialEq)] -#[non_exhaustive] pub enum FcntlArg<'a> { F_DUPFD(RawFd), F_DUPFD_CLOEXEC(RawFd), @@ -406,7 +353,6 @@ pub enum FcntlArg<'a> { #[cfg(target_os = "redox")] #[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)] -#[non_exhaustive] pub enum FcntlArg { F_DUPFD(RawFd), F_DUPFD_CLOEXEC(RawFd), @@ -456,7 +402,6 @@ pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result<c_int> { } #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[non_exhaustive] pub enum FlockArg { LockShared, LockExclusive, @@ -646,12 +591,12 @@ pub fn fallocate( ))] mod posix_fadvise { use crate::errno::Errno; + use libc; use std::os::unix::io::RawFd; use crate::Result; libc_enum! { #[repr(i32)] - #[non_exhaustive] pub enum PosixFadviseAdvice { POSIX_FADV_NORMAL, POSIX_FADV_SEQUENTIAL, @@ -667,14 +612,9 @@ mod posix_fadvise { offset: libc::off_t, len: libc::off_t, advice: PosixFadviseAdvice, - ) -> Result<()> { + ) -> Result<libc::c_int> { let res = unsafe { libc::posix_fadvise(fd, offset, len, advice as libc::c_int) }; - - if res == 0 { - Ok(()) - } else { - Err(Errno::from_i32(res)) - } + Errno::result(res) } } @@ -691,6 +631,6 @@ pub fn posix_fallocate(fd: RawFd, offset: libc::off_t, len: libc::off_t) -> Resu match Errno::result(res) { Err(err) => Err(err), Ok(0) => Ok(()), - Ok(errno) => Err(Errno::from_i32(errno)), + Ok(errno) => Err(crate::Error::Sys(Errno::from_i32(errno))), } } diff --git a/src/features.rs b/src/features.rs index ed80fd7..6b1cff5 100644 --- a/src/features.rs +++ b/src/features.rs @@ -94,28 +94,13 @@ mod os { } } -#[cfg(any( - target_os = "dragonfly", // Since ??? - target_os = "freebsd", // Since 10.0 - target_os = "illumos", // Since ??? - target_os = "netbsd", // Since 6.0 - target_os = "openbsd", // Since 5.7 - target_os = "redox", // Since 1-july-2020 -))] +#[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 = "fuchsia"))] mod os { /// Check if the OS supports atomic close-on-exec for sockets - pub const fn socket_atomic_cloexec() -> bool { - true - } -} - -#[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "fuchsia", - target_os = "solaris"))] -mod os { - /// Check if the OS supports atomic close-on-exec for sockets - pub const fn socket_atomic_cloexec() -> bool { + pub fn socket_atomic_cloexec() -> bool { false } } diff --git a/src/kmod.rs b/src/kmod.rs index c42068c..8789cb6 100644 --- a/src/kmod.rs +++ b/src/kmod.rs @@ -2,6 +2,7 @@ //! //! For more details see +use libc; use std::ffi::CStr; use std::os::unix::io::AsRawFd; @@ -41,7 +42,7 @@ use crate::Result; /// init_module(&mut contents, &CString::new("who=Rust when=Now,12").unwrap()).unwrap(); /// ``` /// -/// See [`man init_module(2)`](https://man7.org/linux/man-pages/man2/init_module.2.html) for more information. +/// See [`man init_module(2)`](http://man7.org/linux/man-pages/man2/init_module.2.html) for more information. pub fn init_module(module_image: &[u8], param_values: &CStr) -> Result<()> { let res = unsafe { libc::syscall( @@ -78,7 +79,7 @@ libc_bitflags!( /// finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()).unwrap(); /// ``` /// -/// See [`man init_module(2)`](https://man7.org/linux/man-pages/man2/init_module.2.html) for more information. +/// See [`man init_module(2)`](http://man7.org/linux/man-pages/man2/init_module.2.html) for more information. pub fn finit_module<T: AsRawFd>(fd: &T, param_values: &CStr, flags: ModuleInitFlags) -> Result<()> { let res = unsafe { libc::syscall( @@ -95,7 +96,7 @@ pub fn finit_module<T: AsRawFd>(fd: &T, param_values: &CStr, flags: ModuleInitFl libc_bitflags!( /// Flags used by `delete_module`. /// - /// See [`man delete_module(2)`](https://man7.org/linux/man-pages/man2/delete_module.2.html) + /// See [`man delete_module(2)`](http://man7.org/linux/man-pages/man2/delete_module.2.html) /// for a detailed description how these flags work. pub struct DeleteModuleFlags: libc::c_int { O_NONBLOCK; @@ -114,7 +115,7 @@ libc_bitflags!( /// delete_module(&CString::new("mymod").unwrap(), DeleteModuleFlags::O_NONBLOCK).unwrap(); /// ``` /// -/// See [`man delete_module(2)`](https://man7.org/linux/man-pages/man2/delete_module.2.html) for more information. +/// See [`man delete_module(2)`](http://man7.org/linux/man-pages/man2/delete_module.2.html) for more information. pub fn delete_module(name: &CStr, flags: DeleteModuleFlags) -> Result<()> { let res = unsafe { libc::syscall(libc::SYS_delete_module, name.as_ptr(), flags.bits()) }; @@ -5,13 +5,15 @@ #![crate_name = "nix"] #![cfg(unix)] #![allow(non_camel_case_types)] +// latest bitflags triggers a rustc bug with cross-crate macro expansions causing dead_code +// warnings even though the macro expands into something with allow(dead_code) +#![allow(dead_code)] #![cfg_attr(test, deny(warnings))] #![recursion_limit = "500"] #![deny(unused)] #![deny(unstable_features)] #![deny(missing_copy_implementations)] #![deny(missing_debug_implementations)] -#![warn(missing_docs)] // Re-exported external crates pub use libc; @@ -21,14 +23,13 @@ pub use libc; // Public crates #[cfg(not(target_os = "redox"))] -#[allow(missing_docs)] pub mod dir; pub mod env; -#[allow(missing_docs)] pub mod errno; +#[deny(missing_docs)] pub mod features; -#[allow(missing_docs)] pub mod fcntl; +#[deny(missing_docs)] #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", @@ -36,15 +37,12 @@ pub mod fcntl; target_os = "linux", target_os = "macos", target_os = "netbsd", - target_os = "illumos", target_os = "openbsd"))] pub mod ifaddrs; #[cfg(any(target_os = "android", target_os = "linux"))] -#[allow(missing_docs)] pub mod kmod; #[cfg(any(target_os = "android", - target_os = "freebsd", target_os = "linux"))] pub mod mount; #[cfg(any(target_os = "dragonfly", @@ -52,24 +50,23 @@ pub mod mount; target_os = "fushsia", target_os = "linux", target_os = "netbsd"))] -#[allow(missing_docs)] pub mod mqueue; +#[deny(missing_docs)] #[cfg(not(target_os = "redox"))] pub mod net; +#[deny(missing_docs)] pub mod poll; +#[deny(missing_docs)] #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] pub mod pty; pub mod sched; pub mod sys; -#[allow(missing_docs)] pub mod time; // This can be implemented for other platforms as soon as libc // provides bindings for them. #[cfg(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")))] -#[allow(missing_docs)] pub mod ucontext; -#[allow(missing_docs)] pub mod unistd; /* @@ -80,7 +77,7 @@ pub mod unistd; use libc::{c_char, PATH_MAX}; -use std::{ptr, result}; +use std::{error, fmt, ptr, result}; use std::ffi::{CStr, OsStr}; use std::os::unix::ffi::OsStrExt; use std::path::{Path, PathBuf}; @@ -88,31 +85,89 @@ use std::path::{Path, PathBuf}; use errno::Errno; /// Nix Result Type -pub type Result<T> = result::Result<T, Errno>; +pub type Result<T> = result::Result<T, Error>; -/// Nix's main error type. +/// Nix Error Type /// -/// It's a wrapper around Errno. As such, it's very interoperable with -/// [`std::io::Error`], but it has the advantages of: -/// * `Clone` -/// * `Copy` -/// * `Eq` -/// * Small size -/// * Represents all of the system's errnos, instead of just the most common -/// ones. -pub type Error = Errno; - -/// Common trait used to represent file system paths by many Nix functions. +/// The nix error type provides a common way of dealing with +/// various system system/libc calls that might fail. Each +/// error has a corresponding errno (usually the one from the +/// underlying OS) to which it can be mapped in addition to +/// implementing other common traits. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Error { + Sys(Errno), + InvalidPath, + /// The operation involved a conversion to Rust's native String type, which failed because the + /// string did not contain all valid UTF-8. + InvalidUtf8, + /// The operation is not supported by Nix, in this instance either use the libc bindings or + /// consult the module documentation to see if there is a more appropriate interface available. + UnsupportedOperation, +} + +impl Error { + /// Convert this `Error` to an [`Errno`](enum.Errno.html). + /// + /// # Example + /// + /// ``` + /// # use nix::Error; + /// # use nix::errno::Errno; + /// let e = Error::from(Errno::EPERM); + /// assert_eq!(Some(Errno::EPERM), e.as_errno()); + /// ``` + pub fn as_errno(self) -> Option<Errno> { + if let Error::Sys(e) = self { + Some(e) + } else { + None + } + } + + /// Create a nix Error from a given errno + pub fn from_errno(errno: Errno) -> Error { + Error::Sys(errno) + } + + /// Get the current errno and convert it to a nix Error + pub fn last() -> Error { + Error::Sys(Errno::last()) + } + + /// Create a new invalid argument error (`EINVAL`) + pub fn invalid_argument() -> Error { + Error::Sys(Errno::EINVAL) + } + +} + +impl From<Errno> for Error { + fn from(errno: Errno) -> Error { Error::from_errno(errno) } +} + +impl From<std::string::FromUtf8Error> for Error { + fn from(_: std::string::FromUtf8Error) -> Error { Error::InvalidUtf8 } +} + +impl error::Error for Error {} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Error::InvalidPath => write!(f, "Invalid path"), + Error::InvalidUtf8 => write!(f, "Invalid UTF-8 string"), + Error::UnsupportedOperation => write!(f, "Unsupported Operation"), + Error::Sys(errno) => write!(f, "{:?}: {}", errno, errno.desc()), + } + } +} + pub trait NixPath { - /// Is the path empty? fn is_empty(&self) -> bool; - /// Length of the path in bytes fn len(&self) -> usize; - /// Execute a function with this path as a `CStr`. - /// - /// Mostly used internally by Nix. fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T; } @@ -160,7 +215,7 @@ impl NixPath for CStr { where F: FnOnce(&CStr) -> T { // Equivalence with the [u8] impl. if self.len() >= PATH_MAX as usize { - return Err(Errno::ENAMETOOLONG) + return Err(Error::InvalidPath); } Ok(f(self)) @@ -181,11 +236,11 @@ impl NixPath for [u8] { let mut buf = [0u8; PATH_MAX as usize]; if self.len() >= PATH_MAX as usize { - return Err(Errno::ENAMETOOLONG) + return Err(Error::InvalidPath); } match self.iter().position(|b| *b == 0) { - Some(_) => Err(Errno::EINVAL), + Some(_) => Err(Error::InvalidPath), None => { unsafe { // TODO: Replace with bytes::copy_memory. rust-lang/rust#24028 diff --git a/src/macros.rs b/src/macros.rs index 3ccbfdd..feb02ea 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -83,9 +83,9 @@ macro_rules! libc_bitflags { macro_rules! libc_enum { // Exit rule. (@make_enum - name: $BitFlags:ident, { $v:vis + name: $BitFlags:ident, attrs: [$($attrs:tt)*], entries: [$($entries:tt)*], } @@ -97,98 +97,38 @@ macro_rules! libc_enum { } }; - // Exit rule including TryFrom - (@make_enum - name: $BitFlags:ident, - { - $v:vis - attrs: [$($attrs:tt)*], - entries: [$($entries:tt)*], - from_type: $repr:path, - try_froms: [$($try_froms:tt)*] - } - ) => { - $($attrs)* - #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] - $v enum $BitFlags { - $($entries)* - } - impl ::std::convert::TryFrom<$repr> for $BitFlags { - type Error = $crate::Error; - #[allow(unused_doc_comments)] - fn try_from(x: $repr) -> $crate::Result<Self> { - match x { - $($try_froms)* - _ => Err($crate::Error::EINVAL) - } - } - } - }; - // Done accumulating. (@accumulate_entries - name: $BitFlags:ident, - { - $v:vis - attrs: $attrs:tt, - }, - $entries:tt, - $try_froms:tt; - ) => { - libc_enum! { - @make_enum - name: $BitFlags, - { - $v - attrs: $attrs, - entries: $entries, - } - } - }; - - // Done accumulating and want TryFrom - (@accumulate_entries - name: $BitFlags:ident, { $v:vis + name: $BitFlags:ident, attrs: $attrs:tt, - from_type: $repr:path, }, - $entries:tt, - $try_froms:tt; + $entries:tt; ) => { libc_enum! { @make_enum - name: $BitFlags, { $v + name: $BitFlags, attrs: $attrs, entries: $entries, - from_type: $repr, - try_froms: $try_froms } } }; // Munch an attr. (@accumulate_entries - name: $BitFlags:ident, $prefix:tt, - [$($entries:tt)*], - [$($try_froms:tt)*]; + [$($entries:tt)*]; #[$attr:meta] $($tail:tt)* ) => { libc_enum! { @accumulate_entries - name: $BitFlags, $prefix, [ $($entries)* #[$attr] - ], - [ - $($try_froms)* - #[$attr] ]; $($tail)* } @@ -196,47 +136,32 @@ macro_rules! libc_enum { // Munch last ident if not followed by a comma. (@accumulate_entries - name: $BitFlags:ident, $prefix:tt, - [$($entries:tt)*], - [$($try_froms:tt)*]; + [$($entries:tt)*]; $entry:ident ) => { libc_enum! { @accumulate_entries - name: $BitFlags, $prefix, [ $($entries)* $entry = libc::$entry, - ], - [ - $($try_froms)* - libc::$entry => Ok($BitFlags::$entry), ]; } }; // Munch an ident; covers terminating comma case. (@accumulate_entries - name: $BitFlags:ident, $prefix:tt, - [$($entries:tt)*], - [$($try_froms:tt)*]; - $entry:ident, - $($tail:tt)* + [$($entries:tt)*]; + $entry:ident, $($tail:tt)* ) => { libc_enum! { @accumulate_entries - name: $BitFlags, $prefix, [ $($entries)* $entry = libc::$entry, - ], - [ - $($try_froms)* - libc::$entry => Ok($BitFlags::$entry), ]; $($tail)* } @@ -244,24 +169,16 @@ macro_rules! libc_enum { // Munch an ident and cast it to the given type; covers terminating comma. (@accumulate_entries - name: $BitFlags:ident, $prefix:tt, - [$($entries:tt)*], - [$($try_froms:tt)*]; - $entry:ident as $ty:ty, - $($tail:tt)* + [$($entries:tt)*]; + $entry:ident as $ty:ty, $($tail:tt)* ) => { libc_enum! { @accumulate_entries - name: $BitFlags, $prefix, [ $($entries)* $entry = libc::$entry as $ty, - ], - [ - $($try_froms)* - libc::$entry as $ty => Ok($BitFlags::$entry), ]; $($tail)* } @@ -276,36 +193,26 @@ macro_rules! libc_enum { ) => { libc_enum! { @accumulate_entries - name: $BitFlags, { $v + name: $BitFlags, attrs: [$(#[$attr])*], }, - [], []; $($vals)* } }; +} - // Entry rule including TryFrom - ( - $(#[$attr:meta])* - $v:vis enum $BitFlags:ident { - $($vals:tt)* - } - impl TryFrom<$repr:path> - ) => { - libc_enum! { - @accumulate_entries - name: $BitFlags, - { - $v - attrs: [$(#[$attr])*], - from_type: $repr, - }, - [], - []; - $($vals)* - } - }; +/// A Rust version of the familiar C `offset_of` macro. It returns the byte +/// offset of `field` within struct `ty` +#[cfg(not(target_os = "redox"))] +macro_rules! offset_of { + ($ty:ty, $field:ident) => {{ + // Safe because we don't actually read from the dereferenced pointer + #[allow(unused_unsafe)] // for when the macro is used in an unsafe block + unsafe { + &(*(ptr::null() as *const $ty)).$field as *const _ as usize + } + }} } diff --git a/src/mount/linux.rs b/src/mount.rs index 4cb2fa5..2c54761 100644 --- a/src/mount/linux.rs +++ b/src/mount.rs @@ -1,4 +1,3 @@ -#![allow(missing_docs)] use libc::{self, c_ulong, c_int}; use crate::{Result, NixPath}; use crate::errno::Errno; @@ -39,7 +38,6 @@ libc_bitflags!( MS_KERNMOUNT; MS_I_VERSION; MS_STRICTATIME; - MS_LAZYTIME; MS_ACTIVE; MS_NOUSER; MS_RMT_MASK; diff --git a/src/mount/bsd.rs b/src/mount/bsd.rs deleted file mode 100644 index 627bfa5..0000000 --- a/src/mount/bsd.rs +++ /dev/null @@ -1,426 +0,0 @@ -use crate::{ - Error, - Errno, - NixPath, - Result, - sys::uio::IoVec -}; -use libc::{c_char, c_int, c_uint, c_void}; -use std::{ - borrow::Cow, - ffi::{CString, CStr}, - fmt, - io, - ptr -}; - - -libc_bitflags!( - /// Used with [`Nmount::nmount`]. - pub struct MntFlags: c_int { - /// ACL support enabled. - #[cfg(any(target_os = "netbsd", target_os = "freebsd"))] - MNT_ACLS; - /// All I/O to the file system should be done asynchronously. - MNT_ASYNC; - /// dir should instead be a file system ID encoded as “FSID:val0:val1”. - #[cfg(target_os = "freebsd")] - MNT_BYFSID; - /// Force a read-write mount even if the file system appears to be - /// unclean. - MNT_FORCE; - /// GEOM journal support enabled. - #[cfg(target_os = "freebsd")] - MNT_GJOURNAL; - /// MAC support for objects. - #[cfg(any(target_os = "macos", target_os = "freebsd"))] - MNT_MULTILABEL; - /// Disable read clustering. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - MNT_NOCLUSTERR; - /// Disable write clustering. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - MNT_NOCLUSTERW; - /// Enable NFS version 4 ACLs. - #[cfg(target_os = "freebsd")] - MNT_NFS4ACLS; - /// Do not update access times. - MNT_NOATIME; - /// Disallow program execution. - MNT_NOEXEC; - /// Do not honor setuid or setgid bits on files when executing them. - MNT_NOSUID; - /// Do not follow symlinks. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - MNT_NOSYMFOLLOW; - /// Mount read-only. - MNT_RDONLY; - /// Causes the vfs subsystem to update its data structures pertaining to - /// the specified already mounted file system. - MNT_RELOAD; - /// Create a snapshot of the file system. - /// - /// See [mksnap_ffs(8)](https://www.freebsd.org/cgi/man.cgi?query=mksnap_ffs) - #[cfg(any(target_os = "macos", target_os = "freebsd"))] - MNT_SNAPSHOT; - /// Using soft updates. - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd" - ))] - MNT_SOFTDEP; - /// Directories with the SUID bit set chown new files to their own - /// owner. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - MNT_SUIDDIR; - /// All I/O to the file system should be done synchronously. - MNT_SYNCHRONOUS; - /// Union with underlying fs. - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "netbsd" - ))] - MNT_UNION; - /// Indicates that the mount command is being applied to an already - /// mounted file system. - MNT_UPDATE; - /// Check vnode use counts. - #[cfg(target_os = "freebsd")] - MNT_NONBUSY; - } -); - - -/// The Error type of [`Nmount::nmount`]. -/// -/// It wraps an [`Errno`], but also may contain an additional message returned -/// by `nmount(2)`. -#[derive(Debug)] -pub struct NmountError { - errno: Error, - errmsg: Option<String> -} - -impl NmountError { - /// Returns the additional error string sometimes generated by `nmount(2)`. - pub fn errmsg(&self) -> Option<&str> { - self.errmsg.as_deref() - } - - /// Returns the inner [`Error`] - pub const fn error(&self) -> Error { - self.errno - } - - fn new(error: Error, errmsg: Option<&CStr>) -> Self { - Self { - errno: error, - errmsg: errmsg.map(CStr::to_string_lossy).map(Cow::into_owned) - } - } -} - -impl std::error::Error for NmountError {} - -impl fmt::Display for NmountError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Some(errmsg) = &self.errmsg { - write!(f, "{:?}: {}: {}", self.errno, errmsg, self.errno.desc()) - } else { - write!(f, "{:?}: {}", self.errno, self.errno.desc()) - } - } -} - -impl From<NmountError> for io::Error { - fn from(err: NmountError) -> Self { - err.errno.into() - } -} - -/// Result type of [`Nmount::nmount`]. -pub type NmountResult = std::result::Result<(), NmountError>; - -/// Mount a FreeBSD file system. -/// -/// The `nmount(2)` system call works similarly to the `mount(8)` program; it -/// takes its options as a series of name-value pairs. Most of the values are -/// strings, as are all of the names. The `Nmount` structure builds up an -/// argument list and then executes the syscall. -/// -/// # Examples -/// -/// To mount `target` onto `mountpoint` with `nullfs`: -/// ``` -/// # use nix::unistd::Uid; -/// # use ::sysctl::CtlValue; -/// # if !Uid::current().is_root() && CtlValue::Int(0) == ::sysctl::value("vfs.usermount").unwrap() { -/// # return; -/// # }; -/// use nix::mount::{MntFlags, Nmount, unmount}; -/// use std::ffi::CString; -/// use tempfile::tempdir; -/// -/// let mountpoint = tempdir().unwrap(); -/// let target = tempdir().unwrap(); -/// -/// let fstype = CString::new("fstype").unwrap(); -/// let nullfs = CString::new("nullfs").unwrap(); -/// Nmount::new() -/// .str_opt(&fstype, &nullfs) -/// .str_opt_owned("fspath", mountpoint.path().to_str().unwrap()) -/// .str_opt_owned("target", target.path().to_str().unwrap()) -/// .nmount(MntFlags::empty()).unwrap(); -/// -/// unmount(mountpoint.path(), MntFlags::empty()).unwrap(); -/// ``` -/// -/// # See Also -/// * [`nmount(2)`](https://www.freebsd.org/cgi/man.cgi?query=nmount) -/// * [`nullfs(5)`](https://www.freebsd.org/cgi/man.cgi?query=nullfs) -#[cfg(target_os = "freebsd")] -#[derive(Debug, Default)] -pub struct Nmount<'a>{ - iov: Vec<IoVec<&'a [u8]>>, - is_owned: Vec<bool>, -} - -#[cfg(target_os = "freebsd")] -impl<'a> Nmount<'a> { - /// Add an opaque mount option. - /// - /// Some file systems take binary-valued mount options. They can be set - /// with this method. - /// - /// # Safety - /// - /// Unsafe because it will cause `Nmount::nmount` to dereference a raw - /// pointer. The user is responsible for ensuring that `val` is valid and - /// its lifetime outlives `self`! An easy way to do that is to give the - /// value a larger scope than `name` - /// - /// # Examples - /// ``` - /// use libc::c_void; - /// use nix::mount::Nmount; - /// use std::ffi::CString; - /// use std::mem; - /// - /// // Note that flags outlives name - /// let mut flags: u32 = 0xdeadbeef; - /// let name = CString::new("flags").unwrap(); - /// let p = &mut flags as *mut u32 as *mut c_void; - /// let len = mem::size_of_val(&flags); - /// let mut nmount = Nmount::new(); - /// unsafe { nmount.mut_ptr_opt(&name, p, len) }; - /// ``` - pub unsafe fn mut_ptr_opt( - &mut self, - name: &'a CStr, - val: *mut c_void, - len: usize - ) -> &mut Self - { - self.iov.push(IoVec::from_slice(name.to_bytes_with_nul())); - self.is_owned.push(false); - self.iov.push(IoVec::from_raw_parts(val, len)); - self.is_owned.push(false); - self - } - - /// Add a mount option that does not take a value. - /// - /// # Examples - /// ``` - /// use nix::mount::Nmount; - /// use std::ffi::CString; - /// - /// let read_only = CString::new("ro").unwrap(); - /// Nmount::new() - /// .null_opt(&read_only); - /// ``` - pub fn null_opt(&mut self, name: &'a CStr) -> &mut Self { - self.iov.push(IoVec::from_slice(name.to_bytes_with_nul())); - self.is_owned.push(false); - self.iov.push(IoVec::from_raw_parts(ptr::null_mut(), 0)); - self.is_owned.push(false); - self - } - - /// Add a mount option that does not take a value, but whose name must be - /// owned. - /// - /// - /// This has higher runtime cost than [`Nmount::null_opt`], but is useful - /// when the name's lifetime doesn't outlive the `Nmount`, or it's a - /// different string type than `CStr`. - /// - /// # Examples - /// ``` - /// use nix::mount::Nmount; - /// - /// let read_only = "ro"; - /// let mut nmount: Nmount<'static> = Nmount::new(); - /// nmount.null_opt_owned(read_only); - /// ``` - pub fn null_opt_owned<P: ?Sized + NixPath>(&mut self, name: &P) -> &mut Self - { - name.with_nix_path(|s| { - let len = s.to_bytes_with_nul().len(); - self.iov.push(IoVec::from_raw_parts( - // Must free it later - s.to_owned().into_raw() as *mut c_void, - len - )); - self.is_owned.push(true); - }).unwrap(); - self.iov.push(IoVec::from_raw_parts(ptr::null_mut(), 0)); - self.is_owned.push(false); - self - } - - /// Add a mount option as a [`CStr`]. - /// - /// # Examples - /// ``` - /// use nix::mount::Nmount; - /// use std::ffi::CString; - /// - /// let fstype = CString::new("fstype").unwrap(); - /// let nullfs = CString::new("nullfs").unwrap(); - /// Nmount::new() - /// .str_opt(&fstype, &nullfs); - /// ``` - pub fn str_opt( - &mut self, - name: &'a CStr, - val: &'a CStr - ) -> &mut Self - { - self.iov.push(IoVec::from_slice(name.to_bytes_with_nul())); - self.is_owned.push(false); - self.iov.push(IoVec::from_slice(val.to_bytes_with_nul())); - self.is_owned.push(false); - self - } - - /// Add a mount option as an owned string. - /// - /// This has higher runtime cost than [`Nmount::str_opt`], but is useful - /// when the value's lifetime doesn't outlive the `Nmount`, or it's a - /// different string type than `CStr`. - /// - /// # Examples - /// ``` - /// use nix::mount::Nmount; - /// use std::path::Path; - /// - /// let mountpoint = Path::new("/mnt"); - /// Nmount::new() - /// .str_opt_owned("fspath", mountpoint.to_str().unwrap()); - /// ``` - pub fn str_opt_owned<P1, P2>(&mut self, name: &P1, val: &P2) -> &mut Self - where P1: ?Sized + NixPath, - P2: ?Sized + NixPath - { - name.with_nix_path(|s| { - let len = s.to_bytes_with_nul().len(); - self.iov.push(IoVec::from_raw_parts( - // Must free it later - s.to_owned().into_raw() as *mut c_void, - len - )); - self.is_owned.push(true); - }).unwrap(); - val.with_nix_path(|s| { - let len = s.to_bytes_with_nul().len(); - self.iov.push(IoVec::from_raw_parts( - // Must free it later - s.to_owned().into_raw() as *mut c_void, - len - )); - self.is_owned.push(true); - }).unwrap(); - self - } - - /// Create a new `Nmount` struct with no options - pub fn new() -> Self { - Self::default() - } - - /// Actually mount the file system. - pub fn nmount(&mut self, flags: MntFlags) -> NmountResult { - // nmount can return extra error information via a "errmsg" return - // argument. - const ERRMSG_NAME: &[u8] = b"errmsg\0"; - let mut errmsg = vec![0u8; 255]; - self.iov.push(IoVec::from_raw_parts( - ERRMSG_NAME.as_ptr() as *mut c_void, - ERRMSG_NAME.len() - )); - self.iov.push(IoVec::from_raw_parts( - errmsg.as_mut_ptr() as *mut c_void, - errmsg.len() - )); - - let niov = self.iov.len() as c_uint; - let iovp = self.iov.as_mut_ptr() as *mut libc::iovec; - let res = unsafe { - libc::nmount(iovp, niov, flags.bits) - }; - match Errno::result(res) { - Ok(_) => Ok(()), - Err(error) => { - let errmsg = match errmsg.iter().position(|&x| x == 0) { - None => None, - Some(0) => None, - Some(n) => { - let sl = &errmsg[0..n + 1]; - Some(CStr::from_bytes_with_nul(sl).unwrap()) - } - }; - Err(NmountError::new(error, errmsg)) - } - } - } -} - -#[cfg(target_os = "freebsd")] -impl<'a> Drop for Nmount<'a> { - fn drop(&mut self) { - for (iov, is_owned) in self.iov.iter().zip(self.is_owned.iter()) { - if *is_owned { - // Free the owned string. Safe because we recorded ownership, - // and Nmount does not implement Clone. - unsafe { - drop(CString::from_raw(iov.0.iov_base as *mut c_char)); - } - } - } - } -} - -/// Unmount the file system mounted at `mountpoint`. -/// -/// Useful flags include -/// * `MNT_FORCE` - Unmount even if still in use. -/// * `MNT_BYFSID` - `mountpoint` is not a path, but a file system ID -/// encoded as `FSID:val0:val1`, where `val0` and `val1` -/// are the contents of the `fsid_t val[]` array in decimal. -/// The file system that has the specified file system ID -/// will be unmounted. See -/// [`statfs`](crate::sys::statfs::statfs) to determine the -/// `fsid`. -pub fn unmount<P>(mountpoint: &P, flags: MntFlags) -> Result<()> - where P: ?Sized + NixPath -{ - let res = mountpoint.with_nix_path(|cstr| { - unsafe { libc::unmount(cstr.as_ptr(), flags.bits) } - })?; - - Errno::result(res).map(drop) -} diff --git a/src/mount/mod.rs b/src/mount/mod.rs deleted file mode 100644 index 14bf2a9..0000000 --- a/src/mount/mod.rs +++ /dev/null @@ -1,21 +0,0 @@ -//! Mount file systems -#[cfg(any(target_os = "android", target_os = "linux"))] -mod linux; - -#[cfg(any(target_os = "android", target_os = "linux"))] -pub use self::linux::*; - -#[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] -mod bsd; - -#[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] -pub use self::bsd::*; diff --git a/src/mqueue.rs b/src/mqueue.rs index 34fd802..0215de5 100644 --- a/src/mqueue.rs +++ b/src/mqueue.rs @@ -1,6 +1,6 @@ //! Posix Message Queue functions //! -//! [Further reading and details on the C API](https://man7.org/linux/man-pages/man7/mq_overview.7.html) +//! [Further reading and details on the C API](http://man7.org/linux/man-pages/man7/mq_overview.7.html) use crate::Result; use crate::errno::Errno; @@ -59,7 +59,7 @@ impl MqAttr { } } - pub const fn flags(&self) -> mq_attr_member_t { + pub fn flags(&self) -> mq_attr_member_t { self.mq_attr.mq_flags } } @@ -67,7 +67,7 @@ impl MqAttr { /// Open a message queue /// -/// See also [`mq_open(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_open.html) +/// See also [`mq_open(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_open.html) // The mode.bits cast is only lossless on some OSes #[allow(clippy::cast_lossless)] pub fn mq_open(name: &CString, @@ -89,7 +89,7 @@ pub fn mq_open(name: &CString, /// Remove a message queue /// -/// See also [`mq_unlink(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_unlink.html) +/// See also [`mq_unlink(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_unlink.html) pub fn mq_unlink(name: &CString) -> Result<()> { let res = unsafe { libc::mq_unlink(name.as_ptr()) }; Errno::result(res).map(drop) @@ -97,7 +97,7 @@ pub fn mq_unlink(name: &CString) -> Result<()> { /// Close a message queue /// -/// See also [`mq_close(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_close.html) +/// See also [`mq_close(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_close.html) pub fn mq_close(mqdes: mqd_t) -> Result<()> { let res = unsafe { libc::mq_close(mqdes) }; Errno::result(res).map(drop) @@ -105,7 +105,7 @@ pub fn mq_close(mqdes: mqd_t) -> Result<()> { /// Receive a message from a message queue /// -/// See also [`mq_receive(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_receive.html) +/// See also [`mq_receive(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_receive.html) pub fn mq_receive(mqdes: mqd_t, message: &mut [u8], msg_prio: &mut u32) -> Result<usize> { let len = message.len() as size_t; let res = unsafe { @@ -119,7 +119,7 @@ pub fn mq_receive(mqdes: mqd_t, message: &mut [u8], msg_prio: &mut u32) -> Resul /// Send a message to a message queue /// -/// See also [`mq_send(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html) +/// See also [`mq_send(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html) pub fn mq_send(mqdes: mqd_t, message: &[u8], msq_prio: u32) -> Result<()> { let res = unsafe { libc::mq_send(mqdes, @@ -132,7 +132,7 @@ pub fn mq_send(mqdes: mqd_t, message: &[u8], msq_prio: u32) -> Result<()> { /// Get message queue attributes /// -/// See also [`mq_getattr(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_getattr.html) +/// See also [`mq_getattr(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_getattr.html) pub fn mq_getattr(mqd: mqd_t) -> Result<MqAttr> { let mut attr = mem::MaybeUninit::<libc::mq_attr>::uninit(); let res = unsafe { libc::mq_getattr(mqd, attr.as_mut_ptr()) }; @@ -143,7 +143,7 @@ pub fn mq_getattr(mqd: mqd_t) -> Result<MqAttr> { /// Returns the old attributes /// It is recommend to use the `mq_set_nonblock()` and `mq_remove_nonblock()` convenience functions as they are easier to use /// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_setattr.html) +/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_setattr.html) pub fn mq_setattr(mqd: mqd_t, newattr: &MqAttr) -> Result<MqAttr> { let mut attr = mem::MaybeUninit::<libc::mq_attr>::uninit(); let res = unsafe { @@ -155,7 +155,6 @@ pub fn mq_setattr(mqd: mqd_t, newattr: &MqAttr) -> Result<MqAttr> { /// Convenience function. /// Sets the `O_NONBLOCK` attribute for a given message queue descriptor /// Returns the old attributes -#[allow(clippy::useless_conversion)] // Not useless on all OSes pub fn mq_set_nonblock(mqd: mqd_t) -> Result<MqAttr> { let oldattr = mq_getattr(mqd)?; let newattr = MqAttr::new(mq_attr_member_t::from(MQ_OFlag::O_NONBLOCK.bits()), diff --git a/src/net/if_.rs b/src/net/if_.rs index bc00a43..9636488 100644 --- a/src/net/if_.rs +++ b/src/net/if_.rs @@ -3,8 +3,8 @@ //! Uses Linux and/or POSIX functions to resolve interface names like "eth0" //! or "socan1" into device numbers. -use crate::{Error, NixPath, Result}; use libc::c_uint; +use crate::{Result, Error, NixPath}; /// Resolve an interface into a interface number. pub fn if_nametoindex<P: ?Sized + NixPath>(name: &P) -> Result<c_uint> { @@ -21,41 +21,39 @@ libc_bitflags!( /// Standard interface flags, used by `getifaddrs` pub struct InterfaceFlags: libc::c_int { /// Interface is running. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html)) IFF_UP; /// Valid broadcast address set. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html)) IFF_BROADCAST; /// Internal debugging flag. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html)) IFF_DEBUG; /// Interface is a loopback interface. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html)) IFF_LOOPBACK; /// Interface is a point-to-point link. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html)) IFF_POINTOPOINT; /// Avoid use of trailers. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html)) #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "ios", target_os = "linux", target_os = "macos", target_os = "netbsd", - target_os = "illumos", target_os = "solaris"))] IFF_NOTRAILERS; /// Interface manages own routes. #[cfg(any(target_os = "dragonfly"))] IFF_SMART; /// Resources allocated. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html)) #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "fuchsia", - target_os = "illumos", target_os = "ios", target_os = "linux", target_os = "macos", @@ -64,16 +62,16 @@ libc_bitflags!( target_os = "solaris"))] IFF_RUNNING; /// No arp protocol, L2 destination address not set. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html)) IFF_NOARP; /// Interface is in promiscuous mode. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html)) IFF_PROMISC; /// Receive all multicast packets. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html)) IFF_ALLMULTI; /// Master of a load balancing bundle. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html)) #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] IFF_MASTER; /// transmission in progress, tx hardware queue is full @@ -84,10 +82,10 @@ libc_bitflags!( target_os = "ios"))] IFF_OACTIVE; /// Protocol code on board. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(target_os = "solaris")] IFF_INTELLIGENT; /// Slave of a load balancing bundle. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html)) #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] IFF_SLAVE; /// Can't hear own transmissions. @@ -99,7 +97,7 @@ libc_bitflags!( target_os = "osx"))] IFF_SIMPLEX; /// Supports multicast. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html)) IFF_MULTICAST; /// Per link layer defined bit. #[cfg(any(target_os = "dragonfly", @@ -110,10 +108,10 @@ libc_bitflags!( target_os = "ios"))] IFF_LINK0; /// Multicast using broadcast. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(any(target_os = "solaris"))] IFF_MULTI_BCAST; /// Is able to select media type via ifmap. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html)) #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] IFF_PORTSEL; /// Per link layer defined bit. @@ -125,10 +123,10 @@ libc_bitflags!( target_os = "ios"))] IFF_LINK1; /// Non-unique address. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(any(target_os = "solaris"))] IFF_UNNUMBERED; /// Auto media selection active. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html)) #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] IFF_AUTOMEDIA; /// Per link layer defined bit. @@ -145,15 +143,15 @@ libc_bitflags!( target_os = "macos", target_os = "ios"))] IFF_ALTPHYS; - /// DHCP controls interface. - #[cfg(any(target_os = "solaris", target_os = "illumos"))] + /// DHCP controlls interface. + #[cfg(any(target_os = "solaris"))] IFF_DHCPRUNNING; /// The addresses are lost when the interface goes down. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html)) #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] IFF_DYNAMIC; /// Do not advertise. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(any(target_os = "solaris"))] IFF_PRIVATE; /// Driver signals L1 up. Volatile. #[cfg(any(target_os = "fuchsia", target_os = "linux"))] @@ -165,7 +163,7 @@ libc_bitflags!( #[cfg(any(target_os = "freebsd"))] IFF_CANTCONFIG; /// Do not transmit packets. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(any(target_os = "solaris"))] IFF_NOXMIT; /// Driver signals dormant. Volatile. #[cfg(any(target_os = "fuchsia", target_os = "linux"))] @@ -174,7 +172,7 @@ libc_bitflags!( #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] IFF_PPROMISC; /// Just on-link subnet. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(any(target_os = "solaris"))] IFF_NOLOCAL; /// Echo sent packets. Volatile. #[cfg(any(target_os = "fuchsia", target_os = "linux"))] @@ -183,19 +181,19 @@ libc_bitflags!( #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] IFF_MONITOR; /// Address is deprecated. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(any(target_os = "solaris"))] IFF_DEPRECATED; /// Static ARP. #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] IFF_STATICARP; /// Address from stateless addrconf. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(any(target_os = "solaris"))] IFF_ADDRCONF; /// Interface is in polling mode. #[cfg(any(target_os = "dragonfly"))] IFF_NPOLLING; /// Router on interface. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(any(target_os = "solaris"))] IFF_ROUTER; /// Interface is in polling mode. #[cfg(any(target_os = "dragonfly"))] @@ -204,208 +202,66 @@ libc_bitflags!( #[cfg(any(target_os = "freebsd"))] IFF_DYING; /// No NUD on interface. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(any(target_os = "solaris"))] IFF_NONUD; /// Interface is being renamed #[cfg(any(target_os = "freebsd"))] IFF_RENAMING; /// Anycast address. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(any(target_os = "solaris"))] IFF_ANYCAST; /// Don't exchange routing info. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(any(target_os = "solaris"))] IFF_NORTEXCH; /// Do not provide packet information #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] IFF_NO_PI as libc::c_int; - /// TUN device (no Ethernet headers) + /// TUN device (no Ethernet headers) #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] IFF_TUN as libc::c_int; /// TAP device #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] IFF_TAP as libc::c_int; /// IPv4 interface. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(any(target_os = "solaris"))] IFF_IPV4; /// IPv6 interface. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(any(target_os = "solaris"))] IFF_IPV6; /// in.mpathd test address - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(any(target_os = "solaris"))] IFF_NOFAILOVER; /// Interface has failed - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(any(target_os = "solaris"))] IFF_FAILED; /// Interface is a hot-spare - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(any(target_os = "solaris"))] IFF_STANDBY; /// Functioning but not used - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(any(target_os = "solaris"))] IFF_INACTIVE; /// Interface is offline - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(any(target_os = "solaris"))] IFF_OFFLINE; - #[cfg(target_os = "solaris")] + #[cfg(any(target_os = "solaris"))] IFF_COS_ENABLED; /// Prefer as source addr. - #[cfg(target_os = "solaris")] + #[cfg(any(target_os = "solaris"))] IFF_PREFERRED; /// RFC3041 - #[cfg(target_os = "solaris")] + #[cfg(any(target_os = "solaris"))] IFF_TEMPORARY; /// MTU set with SIOCSLIFMTU - #[cfg(target_os = "solaris")] + #[cfg(any(target_os = "solaris"))] IFF_FIXEDMTU; /// Cannot send / receive packets - #[cfg(target_os = "solaris")] + #[cfg(any(target_os = "solaris"))] IFF_VIRTUAL; /// Local address in use - #[cfg(target_os = "solaris")] + #[cfg(any(target_os = "solaris"))] IFF_DUPLICATE; /// IPMP IP interface - #[cfg(target_os = "solaris")] + #[cfg(any(target_os = "solaris"))] IFF_IPMP; } ); - -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", -))] -mod if_nameindex { - use super::*; - - use std::ffi::CStr; - use std::fmt; - use std::marker::PhantomData; - use std::ptr::NonNull; - - /// A network interface. Has a name like "eth0" or "wlp4s0" or "wlan0", as well as an index - /// (1, 2, 3, etc) that identifies it in the OS's networking stack. - #[allow(missing_copy_implementations)] - #[repr(transparent)] - pub struct Interface(libc::if_nameindex); - - impl Interface { - /// Obtain the index of this interface. - pub fn index(&self) -> c_uint { - self.0.if_index - } - - /// Obtain the name of this interface. - pub fn name(&self) -> &CStr { - unsafe { CStr::from_ptr(self.0.if_name) } - } - } - - impl fmt::Debug for Interface { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Interface") - .field("index", &self.index()) - .field("name", &self.name()) - .finish() - } - } - - /// A list of the network interfaces available on this system. Obtained from [`if_nameindex()`]. - pub struct Interfaces { - ptr: NonNull<libc::if_nameindex>, - } - - impl Interfaces { - /// Iterate over the interfaces in this list. - #[inline] - pub fn iter(&self) -> InterfacesIter<'_> { - self.into_iter() - } - - /// Convert this to a slice of interfaces. Note that the underlying interfaces list is - /// null-terminated, so calling this calculates the length. If random access isn't needed, - /// [`Interfaces::iter()`] should be used instead. - pub fn to_slice(&self) -> &[Interface] { - let ifs = self.ptr.as_ptr() as *const Interface; - let len = self.iter().count(); - unsafe { std::slice::from_raw_parts(ifs, len) } - } - } - - impl Drop for Interfaces { - fn drop(&mut self) { - unsafe { libc::if_freenameindex(self.ptr.as_ptr()) }; - } - } - - impl fmt::Debug for Interfaces { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.to_slice().fmt(f) - } - } - - impl<'a> IntoIterator for &'a Interfaces { - type IntoIter = InterfacesIter<'a>; - type Item = &'a Interface; - #[inline] - fn into_iter(self) -> Self::IntoIter { - InterfacesIter { - ptr: self.ptr.as_ptr(), - _marker: PhantomData, - } - } - } - - /// An iterator over the interfaces in an [`Interfaces`]. - #[derive(Debug)] - pub struct InterfacesIter<'a> { - ptr: *const libc::if_nameindex, - _marker: PhantomData<&'a Interfaces>, - } - - impl<'a> Iterator for InterfacesIter<'a> { - type Item = &'a Interface; - #[inline] - fn next(&mut self) -> Option<Self::Item> { - unsafe { - if (*self.ptr).if_index == 0 { - None - } else { - let ret = &*(self.ptr as *const Interface); - self.ptr = self.ptr.add(1); - Some(ret) - } - } - } - } - - /// Retrieve a list of the network interfaces available on the local system. - /// - /// ``` - /// let interfaces = nix::net::if_::if_nameindex().unwrap(); - /// for iface in &interfaces { - /// println!("Interface #{} is called {}", iface.index(), iface.name().to_string_lossy()); - /// } - /// ``` - pub fn if_nameindex() -> Result<Interfaces> { - unsafe { - let ifs = libc::if_nameindex(); - let ptr = NonNull::new(ifs).ok_or_else(Error::last)?; - Ok(Interfaces { ptr }) - } - } -} -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", -))] -pub use if_nameindex::*; diff --git a/src/poll.rs b/src/poll.rs index 8556c1b..be5bf22 100644 --- a/src/poll.rs +++ b/src/poll.rs @@ -3,7 +3,7 @@ use crate::sys::time::TimeSpec; #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))] use crate::sys::signal::SigSet; -use std::os::unix::io::{AsRawFd, RawFd}; +use std::os::unix::io::RawFd; use crate::Result; use crate::errno::Errno; @@ -25,7 +25,7 @@ pub struct PollFd { impl PollFd { /// Creates a new `PollFd` specifying the events of interest /// for a given file descriptor. - pub const fn new(fd: RawFd, events: PollFlags) -> PollFd { + pub fn new(fd: RawFd, events: PollFlags) -> PollFd { PollFd { pollfd: libc::pollfd { fd, @@ -35,27 +35,10 @@ impl PollFd { } } - /// Returns the events that occured in the last call to `poll` or `ppoll`. Will only return - /// `None` if the kernel provides status flags that Nix does not know about. + /// Returns the events that occured in the last call to `poll` or `ppoll`. pub fn revents(self) -> Option<PollFlags> { PollFlags::from_bits(self.pollfd.revents) } - - /// The events of interest for this `PollFd`. - pub fn events(self) -> PollFlags { - PollFlags::from_bits(self.pollfd.events).unwrap() - } - - /// Modify the events of interest for this `PollFd`. - pub fn set_events(&mut self, events: PollFlags) { - self.pollfd.events = events.bits(); - } -} - -impl AsRawFd for PollFd { - fn as_raw_fd(&self) -> RawFd { - self.pollfd.fd - } } libc_bitflags! { @@ -68,12 +51,12 @@ libc_bitflags! { /// Possibilities include: /// /// * There is out-of-band data on a TCP socket (see - /// [tcp(7)](https://man7.org/linux/man-pages/man7/tcp.7.html)). + /// [tcp(7)](http://man7.org/linux/man-pages/man7/tcp.7.html)). /// * A pseudoterminal master in packet mode has seen a state /// change on the slave (see - /// [ioctl_tty(2)](https://man7.org/linux/man-pages/man2/ioctl_tty.2.html)). + /// [ioctl_tty(2)](http://man7.org/linux/man-pages/man2/ioctl_tty.2.html)). /// * A cgroup.events file has been modified (see - /// [cgroups(7)](https://man7.org/linux/man-pages/man7/cgroups.7.html)). + /// [cgroups(7)](http://man7.org/linux/man-pages/man7/cgroups.7.html)). POLLPRI; /// Writing is now possible, though a write larger that the /// available space in a socket or pipe will still block (unless @@ -113,7 +96,7 @@ libc_bitflags! { } /// `poll` waits for one of a set of file descriptors to become ready to perform I/O. -/// ([`poll(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html)) +/// ([`poll(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html)) /// /// `fds` contains all [`PollFd`](struct.PollFd.html) to poll. /// The function will return as soon as any event occur for any of these `PollFd`s. @@ -144,7 +127,7 @@ pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result<libc::c_int> { /// `ppoll()` allows an application to safely wait until either a file /// descriptor becomes ready or until a signal is caught. -/// ([`poll(2)`](https://man7.org/linux/man-pages/man2/poll.2.html)) +/// ([`poll(2)`](http://man7.org/linux/man-pages/man2/poll.2.html)) /// /// `ppoll` behaves like `poll`, but let you specify what signals may interrupt it /// with the `sigmask` argument. If you want `ppoll` to block indefinitely, @@ -10,7 +10,7 @@ use std::os::unix::prelude::*; use crate::sys::termios::Termios; use crate::unistd::{self, ForkResult, Pid}; -use crate::{Result, fcntl}; +use crate::{Result, Error, fcntl}; use crate::errno::Errno; /// Representation of a master/slave pty pair @@ -70,7 +70,7 @@ impl Drop for PtyMaster { // condition, which can cause confusing errors for future I/O // operations. let e = unistd::close(self.0); - if e == Err(Errno::EBADF) { + if e == Err(Error::Sys(Errno::EBADF)) { panic!("Closing an invalid file descriptor!"); }; } @@ -78,13 +78,13 @@ impl Drop for PtyMaster { impl io::Read for PtyMaster { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - unistd::read(self.0, buf).map_err(io::Error::from) + unistd::read(self.0, buf).map_err(|e| e.as_errno().unwrap().into()) } } impl io::Write for PtyMaster { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - unistd::write(self.0, buf).map_err(io::Error::from) + unistd::write(self.0, buf).map_err(|e| e.as_errno().unwrap().into()) } fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -92,21 +92,21 @@ impl io::Write for PtyMaster { } /// Grant access to a slave pseudoterminal (see -/// [`grantpt(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/grantpt.html)) +/// [`grantpt(3)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/grantpt.html)) /// /// `grantpt()` changes the mode and owner of the slave pseudoterminal device corresponding to the /// master pseudoterminal referred to by `fd`. This is a necessary step towards opening the slave. #[inline] pub fn grantpt(fd: &PtyMaster) -> Result<()> { if unsafe { libc::grantpt(fd.as_raw_fd()) } < 0 { - return Err(Errno::last()); + return Err(Error::last()); } Ok(()) } /// Open a pseudoterminal device (see -/// [`posix_openpt(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_openpt.html)) +/// [`posix_openpt(3)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_openpt.html)) /// /// `posix_openpt()` returns a file descriptor to an existing unused pseuterminal master device. /// @@ -145,14 +145,14 @@ pub fn posix_openpt(flags: fcntl::OFlag) -> Result<PtyMaster> { }; if fd < 0 { - return Err(Errno::last()); + return Err(Error::last()); } Ok(PtyMaster(fd)) } /// Get the name of the slave pseudoterminal (see -/// [`ptsname(3)`](https://man7.org/linux/man-pages/man3/ptsname.3.html)) +/// [`ptsname(3)`](http://man7.org/linux/man-pages/man3/ptsname.3.html)) /// /// `ptsname()` returns the name of the slave pseudoterminal device corresponding to the master /// referred to by `fd`. @@ -171,7 +171,7 @@ pub fn posix_openpt(flags: fcntl::OFlag) -> Result<PtyMaster> { pub unsafe fn ptsname(fd: &PtyMaster) -> Result<String> { let name_ptr = libc::ptsname(fd.as_raw_fd()); if name_ptr.is_null() { - return Err(Errno::last()); + return Err(Error::last()); } let name = CStr::from_ptr(name_ptr); @@ -179,7 +179,7 @@ pub unsafe fn ptsname(fd: &PtyMaster) -> Result<String> { } /// Get the name of the slave pseudoterminal (see -/// [`ptsname(3)`](https://man7.org/linux/man-pages/man3/ptsname.3.html)) +/// [`ptsname(3)`](http://man7.org/linux/man-pages/man3/ptsname.3.html)) /// /// `ptsname_r()` returns the name of the slave pseudoterminal device corresponding to the master /// referred to by `fd`. This is the threadsafe version of `ptsname()`, but it is not part of the @@ -190,22 +190,23 @@ pub unsafe fn ptsname(fd: &PtyMaster) -> Result<String> { #[cfg(any(target_os = "android", target_os = "linux"))] #[inline] pub fn ptsname_r(fd: &PtyMaster) -> Result<String> { - let mut name_buf = Vec::<libc::c_char>::with_capacity(64); - let name_buf_ptr = name_buf.as_mut_ptr(); - let cname = unsafe { - let cap = name_buf.capacity(); - if libc::ptsname_r(fd.as_raw_fd(), name_buf_ptr, cap) != 0 { - return Err(crate::Error::last()); - } - CStr::from_ptr(name_buf.as_ptr()) - }; + let mut name_buf = vec![0u8; 64]; + let name_buf_ptr = name_buf.as_mut_ptr() as *mut libc::c_char; + if unsafe { libc::ptsname_r(fd.as_raw_fd(), name_buf_ptr, name_buf.capacity()) } != 0 { + return Err(Error::last()); + } + + // Find the first null-character terminating this string. This is guaranteed to succeed if the + // return value of `libc::ptsname_r` is 0. + let null_index = name_buf.iter().position(|c| *c == b'\0').unwrap(); + name_buf.truncate(null_index); - let name = cname.to_string_lossy().into_owned(); + let name = String::from_utf8(name_buf)?; Ok(name) } /// Unlock a pseudoterminal master/slave pseudoterminal pair (see -/// [`unlockpt(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlockpt.html)) +/// [`unlockpt(3)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/unlockpt.html)) /// /// `unlockpt()` unlocks the slave pseudoterminal device corresponding to the master pseudoterminal /// referred to by `fd`. This must be called before trying to open the slave side of a @@ -213,7 +214,7 @@ pub fn ptsname_r(fd: &PtyMaster) -> Result<String> { #[inline] pub fn unlockpt(fd: &PtyMaster) -> Result<()> { if unsafe { libc::unlockpt(fd.as_raw_fd()) } < 0 { - return Err(Errno::last()); + return Err(Error::last()); } Ok(()) @@ -222,7 +223,7 @@ pub fn unlockpt(fd: &PtyMaster) -> Result<()> { /// Create a new pseudoterminal, returning the slave and master file descriptors /// in `OpenptyResult` -/// (see [`openpty`](https://man7.org/linux/man-pages/man3/openpty.3.html)). +/// (see [`openpty`](http://man7.org/linux/man-pages/man3/openpty.3.html)). /// /// If `winsize` is not `None`, the window size of the slave will be set to /// the values in `winsize`. If `termios` is not `None`, the pseudoterminal's @@ -296,24 +297,12 @@ pub fn openpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios> /// Create a new pseudoterminal, returning the master file descriptor and forked pid. /// in `ForkptyResult` -/// (see [`forkpty`](https://man7.org/linux/man-pages/man3/forkpty.3.html)). +/// (see [`forkpty`](http://man7.org/linux/man-pages/man3/forkpty.3.html)). /// /// If `winsize` is not `None`, the window size of the slave will be set to /// the values in `winsize`. If `termios` is not `None`, the pseudoterminal's /// terminal settings of the slave will be set to the values in `termios`. -/// -/// # Safety -/// -/// In a multithreaded program, only [async-signal-safe] functions like `pause` -/// and `_exit` may be called by the child (the parent isn't restricted). Note -/// that memory allocation may **not** be async-signal-safe and thus must be -/// prevented. -/// -/// Those functions are only a small subset of your operating system's API, so -/// special care must be taken to only invoke code you can control and audit. -/// -/// [async-signal-safe]: https://man7.org/linux/man-pages/man7/signal-safety.7.html -pub unsafe fn forkpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>>>( +pub fn forkpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>>>( winsize: T, termios: U, ) -> Result<ForkptyResult> { @@ -334,15 +323,20 @@ pub unsafe fn forkpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b T .map(|ws| ws as *const Winsize as *mut _) .unwrap_or(ptr::null_mut()); - let res = libc::forkpty(master.as_mut_ptr(), ptr::null_mut(), term, win); + let res = unsafe { + libc::forkpty(master.as_mut_ptr(), ptr::null_mut(), term, win) + }; let fork_result = Errno::result(res).map(|res| match res { 0 => ForkResult::Child, res => ForkResult::Parent { child: Pid::from_raw(res) }, })?; - Ok(ForkptyResult { - master: master.assume_init(), - fork_result, - }) + unsafe { + Ok(ForkptyResult { + master: master.assume_init(), + fork_result, + }) + } } + diff --git a/src/sched.rs b/src/sched.rs index c2dd7b8..3b48b4a 100644 --- a/src/sched.rs +++ b/src/sched.rs @@ -1,7 +1,3 @@ -//! Execution scheduling -//! -//! See Also -//! [sched.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sched.h.html) use crate::{Errno, Result}; #[cfg(any(target_os = "android", target_os = "linux"))] @@ -15,75 +11,38 @@ mod sched_linux_like { use std::option::Option; use std::os::unix::io::RawFd; use crate::unistd::Pid; - use crate::Result; + use crate::{Error, Result}; // For some functions taking with a parameter of type CloneFlags, // only a subset of these flags have an effect. libc_bitflags! { - /// Options for use with [`clone`] pub struct CloneFlags: c_int { - /// The calling process and the child process run in the same - /// memory space. CLONE_VM; - /// The caller and the child process share the same filesystem - /// information. CLONE_FS; - /// The calling process and the child process share the same file - /// descriptor table. CLONE_FILES; - /// The calling process and the child process share the same table - /// of signal handlers. CLONE_SIGHAND; - /// If the calling process is being traced, then trace the child - /// also. CLONE_PTRACE; - /// The execution of the calling process is suspended until the - /// child releases its virtual memory resources via a call to - /// execve(2) or _exit(2) (as with vfork(2)). CLONE_VFORK; - /// The parent of the new child (as returned by getppid(2)) - /// will be the same as that of the calling process. CLONE_PARENT; - /// The child is placed in the same thread group as the calling - /// process. CLONE_THREAD; - /// The cloned child is started in a new mount namespace. CLONE_NEWNS; - /// The child and the calling process share a single list of System - /// V semaphore adjustment values CLONE_SYSVSEM; - // Not supported by Nix due to lack of varargs support in Rust FFI - // CLONE_SETTLS; - // Not supported by Nix due to lack of varargs support in Rust FFI - // CLONE_PARENT_SETTID; - // Not supported by Nix due to lack of varargs support in Rust FFI - // CLONE_CHILD_CLEARTID; - /// Unused since Linux 2.6.2 - #[deprecated(since = "0.23.0", note = "Deprecated by Linux 2.6.2")] + CLONE_SETTLS; + CLONE_PARENT_SETTID; + CLONE_CHILD_CLEARTID; CLONE_DETACHED; - /// A tracing process cannot force `CLONE_PTRACE` on this child - /// process. CLONE_UNTRACED; - // Not supported by Nix due to lack of varargs support in Rust FFI - // CLONE_CHILD_SETTID; - /// Create the process in a new cgroup namespace. + CLONE_CHILD_SETTID; CLONE_NEWCGROUP; - /// Create the process in a new UTS namespace. CLONE_NEWUTS; - /// Create the process in a new IPC namespace. CLONE_NEWIPC; - /// Create the process in a new user namespace. CLONE_NEWUSER; - /// Create the process in a new PID namespace. CLONE_NEWPID; - /// Create the process in a new network namespace. CLONE_NEWNET; - /// The new process shares an I/O context with the calling process. CLONE_IO; } } - /// Type for the function executed by [`clone`]. pub type CloneCb<'a> = Box<dyn FnMut() -> isize + 'a>; /// CpuSet represent a bit-mask of CPUs. @@ -109,7 +68,7 @@ mod sched_linux_like { /// `field` is the CPU id to test pub fn is_set(&self, field: usize) -> Result<bool> { if field >= CpuSet::count() { - Err(Errno::EINVAL) + Err(Error::Sys(Errno::EINVAL)) } else { Ok(unsafe { libc::CPU_ISSET(field, &self.cpu_set) }) } @@ -119,7 +78,7 @@ mod sched_linux_like { /// `field` is the CPU id to add pub fn set(&mut self, field: usize) -> Result<()> { if field >= CpuSet::count() { - Err(Errno::EINVAL) + Err(Error::Sys(Errno::EINVAL)) } else { unsafe { libc::CPU_SET(field, &mut self.cpu_set); } Ok(()) @@ -130,7 +89,7 @@ mod sched_linux_like { /// `field` is the CPU id to remove pub fn unset(&mut self, field: usize) -> Result<()> { if field >= CpuSet::count() { - Err(Errno::EINVAL) + Err(Error::Sys(Errno::EINVAL)) } else { unsafe { libc::CPU_CLR(field, &mut self.cpu_set);} Ok(()) @@ -138,7 +97,7 @@ mod sched_linux_like { } /// Return the maximum number of CPU in CpuSet - pub const fn count() -> usize { + pub fn count() -> usize { 8 * mem::size_of::<libc::cpu_set_t>() } } @@ -150,7 +109,7 @@ mod sched_linux_like { } /// `sched_setaffinity` set a thread's CPU affinity mask - /// ([`sched_setaffinity(2)`](https://man7.org/linux/man-pages/man2/sched_setaffinity.2.html)) + /// ([`sched_setaffinity(2)`](http://man7.org/linux/man-pages/man2/sched_setaffinity.2.html)) /// /// `pid` is the thread ID to update. /// If pid is zero, then the calling thread is updated. @@ -183,7 +142,7 @@ mod sched_linux_like { } /// `sched_getaffinity` get a thread's CPU affinity mask - /// ([`sched_getaffinity(2)`](https://man7.org/linux/man-pages/man2/sched_getaffinity.2.html)) + /// ([`sched_getaffinity(2)`](http://man7.org/linux/man-pages/man2/sched_getaffinity.2.html)) /// /// `pid` is the thread ID to check. /// If pid is zero, then the calling thread is checked. @@ -217,14 +176,6 @@ mod sched_linux_like { Errno::result(res).and(Ok(cpuset)) } - /// `clone` create a child process - /// ([`clone(2)`](https://man7.org/linux/man-pages/man2/clone.2.html)) - /// - /// `stack` is a reference to an array which will hold the stack of the new - /// process. Unlike when calling `clone(2)` from C, the provided stack - /// address need not be the highest address of the region. Nix will take - /// care of that requirement. The user only needs to provide a reference to - /// a normally allocated buffer. pub fn clone( mut cb: CloneCb, stack: &mut [u8], @@ -253,18 +204,12 @@ mod sched_linux_like { Errno::result(res).map(Pid::from_raw) } - /// disassociate parts of the process execution context - /// - /// See also [unshare(2)](https://man7.org/linux/man-pages/man2/unshare.2.html) pub fn unshare(flags: CloneFlags) -> Result<()> { let res = unsafe { libc::unshare(flags.bits()) }; Errno::result(res).map(drop) } - /// reassociate thread with a namespace - /// - /// See also [setns(2)](https://man7.org/linux/man-pages/man2/setns.2.html) pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> { let res = unsafe { libc::setns(fd, nstype.bits()) }; @@ -274,7 +219,7 @@ mod sched_linux_like { /// Explicitly yield the processor to other threads. /// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_yield.html) +/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_yield.html) pub fn sched_yield() -> Result<()> { let res = unsafe { libc::sched_yield() }; diff --git a/src/sys/aio.rs b/src/sys/aio.rs index e64a2a8..1afdb35 100644 --- a/src/sys/aio.rs +++ b/src/sys/aio.rs @@ -21,15 +21,15 @@ //! [`aio_cancel_all`](fn.aio_cancel_all.html), though the operating system may //! not support this for all filesystems and devices. -use crate::Result; +use crate::{Error, Result}; use crate::errno::Errno; use std::os::unix::io::RawFd; use libc::{c_void, off_t, size_t}; +use std::borrow::{Borrow, BorrowMut}; use std::fmt; use std::fmt::Debug; use std::marker::PhantomData; use std::mem; -use std::pin::Pin; use std::ptr::{null, null_mut}; use crate::sys::signal::*; use std::thread; @@ -39,7 +39,6 @@ libc_enum! { /// Mode for `AioCb::fsync`. Controls whether only data or both data and /// metadata are synced. #[repr(i32)] - #[non_exhaustive] pub enum AioFsyncMode { /// do it like `fsync` O_SYNC, @@ -58,13 +57,9 @@ libc_enum! { /// given `aiocb` should be used for a read operation, a write operation, or /// ignored. Has no effect for any other aio functions. #[repr(i32)] - #[non_exhaustive] pub enum LioOpcode { - /// No operation LIO_NOP, - /// Write data as if by a call to [`AioCb::write`] LIO_WRITE, - /// Write data as if by a call to [`AioCb::read`] LIO_READ, } } @@ -95,31 +90,120 @@ pub enum AioCancelStat { AioAllDone = libc::AIO_ALLDONE, } -/// Newtype that adds Send and Sync to libc::aiocb, which contains raw pointers -#[repr(transparent)] -struct LibcAiocb(libc::aiocb); +/// Owns (uniquely or shared) a memory buffer to keep it from `Drop`ing while +/// the kernel has a pointer to it. +pub enum Buffer<'a> { + /// No buffer to own. + /// + /// Used for operations like `aio_fsync` that have no data, or for unsafe + /// operations that work with raw pointers. + None, + /// Keeps a reference to a slice + Phantom(PhantomData<&'a mut [u8]>), + /// Generic thing that keeps a buffer from dropping + BoxedSlice(Box<dyn Borrow<[u8]>>), + /// Generic thing that keeps a mutable buffer from dropping + BoxedMutSlice(Box<dyn BorrowMut<[u8]>>), +} -unsafe impl Send for LibcAiocb {} -unsafe impl Sync for LibcAiocb {} +impl<'a> Debug for Buffer<'a> { + // Note: someday it may be possible to Derive Debug for a trait object, but + // not today. + // https://github.com/rust-lang/rust/issues/1563 + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + Buffer::None => write!(fmt, "None"), + Buffer::Phantom(p) => p.fmt(fmt), + Buffer::BoxedSlice(ref bs) => { + let borrowed : &dyn Borrow<[u8]> = bs.borrow(); + write!(fmt, "BoxedSlice({:?})", + borrowed as *const dyn Borrow<[u8]>) + }, + Buffer::BoxedMutSlice(ref bms) => { + let borrowed : &dyn BorrowMut<[u8]> = bms.borrow(); + write!(fmt, "BoxedMutSlice({:?})", + borrowed as *const dyn BorrowMut<[u8]>) + } + } + } +} /// AIO Control Block. /// /// The basic structure used by all aio functions. Each `AioCb` represents one /// I/O request. pub struct AioCb<'a> { - aiocb: LibcAiocb, + aiocb: libc::aiocb, /// Tracks whether the buffer pointed to by `libc::aiocb.aio_buf` is mutable mutable: bool, /// Could this `AioCb` potentially have any in-kernel state? in_progress: bool, - _buffer: std::marker::PhantomData<&'a [u8]>, - _pin: std::marker::PhantomPinned + /// Optionally keeps a reference to the data. + /// + /// Used to keep buffers from `Drop`'ing, and may be returned once the + /// `AioCb` is completed by [`buffer`](#method.buffer). + buffer: Buffer<'a> } impl<'a> AioCb<'a> { + /// Remove the inner `Buffer` and return it + /// + /// It is an error to call this method while the `AioCb` is still in + /// progress. + pub fn buffer(&mut self) -> Buffer<'a> { + assert!(!self.in_progress); + let mut x = Buffer::None; + mem::swap(&mut self.buffer, &mut x); + x + } + + /// Remove the inner boxed slice, if any, and return it. + /// + /// The returned value will be the argument that was passed to + /// `from_boxed_slice` when this `AioCb` was created. + /// + /// It is an error to call this method while the `AioCb` is still in + /// progress. + pub fn boxed_slice(&mut self) -> Option<Box<dyn Borrow<[u8]>>> { + assert!(!self.in_progress, "Can't remove the buffer from an AioCb that's still in-progress. Did you forget to call aio_return?"); + if let Buffer::BoxedSlice(_) = self.buffer { + let mut oldbuffer = Buffer::None; + mem::swap(&mut self.buffer, &mut oldbuffer); + if let Buffer::BoxedSlice(inner) = oldbuffer { + Some(inner) + } else { + unreachable!(); + } + } else { + None + } + } + + /// Remove the inner boxed mutable slice, if any, and return it. + /// + /// The returned value will be the argument that was passed to + /// `from_boxed_mut_slice` when this `AioCb` was created. + /// + /// It is an error to call this method while the `AioCb` is still in + /// progress. + pub fn boxed_mut_slice(&mut self) -> Option<Box<dyn BorrowMut<[u8]>>> { + assert!(!self.in_progress, "Can't remove the buffer from an AioCb that's still in-progress. Did you forget to call aio_return?"); + if let Buffer::BoxedMutSlice(_) = self.buffer { + let mut oldbuffer = Buffer::None; + mem::swap(&mut self.buffer, &mut oldbuffer); + if let Buffer::BoxedMutSlice(inner) = oldbuffer { + Some(inner) + } else { + unreachable!(); + } + } else { + None + } + } + /// Returns the underlying file descriptor associated with the `AioCb` pub fn fd(&self) -> RawFd { - self.aiocb.0.aio_fildes + self.aiocb.aio_fildes } /// Constructs a new `AioCb` with no associated buffer. @@ -148,48 +232,28 @@ impl<'a> AioCb<'a> { /// # use std::{thread, time}; /// # use std::os::unix::io::AsRawFd; /// # use tempfile::tempfile; + /// # fn main() { /// let f = tempfile().unwrap(); /// let mut aiocb = AioCb::from_fd( f.as_raw_fd(), 0, SigevNone); /// aiocb.fsync(AioFsyncMode::O_SYNC).expect("aio_fsync failed early"); - /// while (aiocb.error() == Err(Errno::EINPROGRESS)) { + /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) { /// thread::sleep(time::Duration::from_millis(10)); /// } /// aiocb.aio_return().expect("aio_fsync failed late"); + /// # } /// ``` pub fn from_fd(fd: RawFd, prio: libc::c_int, - sigev_notify: SigevNotify) -> Pin<Box<AioCb<'a>>> { + sigev_notify: SigevNotify) -> AioCb<'a> { let mut a = AioCb::common_init(fd, prio, sigev_notify); - a.0.aio_offset = 0; - a.0.aio_nbytes = 0; - a.0.aio_buf = null_mut(); - - Box::pin(AioCb { - aiocb: a, - mutable: false, - in_progress: false, - _buffer: PhantomData, - _pin: std::marker::PhantomPinned - }) - } - - // Private helper - #[cfg(not(any(target_os = "ios", target_os = "macos")))] - fn from_mut_slice_unpinned(fd: RawFd, offs: off_t, buf: &'a mut [u8], - prio: libc::c_int, sigev_notify: SigevNotify, - opcode: LioOpcode) -> AioCb<'a> - { - let mut a = AioCb::common_init(fd, prio, sigev_notify); - a.0.aio_offset = offs; - a.0.aio_nbytes = buf.len() as size_t; - a.0.aio_buf = buf.as_ptr() as *mut c_void; - a.0.aio_lio_opcode = opcode as libc::c_int; + a.aio_offset = 0; + a.aio_nbytes = 0; + a.aio_buf = null_mut(); AioCb { aiocb: a, - mutable: true, + mutable: false, in_progress: false, - _buffer: PhantomData, - _pin: std::marker::PhantomPinned + buffer: Buffer::None } } @@ -198,7 +262,8 @@ impl<'a> AioCb<'a> { /// The resulting `AioCb` will be suitable for both read and write /// operations, but only if the borrow checker can guarantee that the slice /// will outlive the `AioCb`. That will usually be the case if the `AioCb` - /// is stack-allocated. + /// is stack-allocated. If the borrow checker gives you trouble, try using + /// [`from_boxed_mut_slice`](#method.from_boxed_mut_slice) instead. /// /// # Parameters /// @@ -227,6 +292,7 @@ impl<'a> AioCb<'a> { /// # use std::io::Write; /// # use std::os::unix::io::AsRawFd; /// # use tempfile::tempfile; + /// # fn main() { /// const INITIAL: &[u8] = b"abcdef123456"; /// const LEN: usize = 4; /// let mut rbuf = vec![0; LEN]; @@ -240,29 +306,220 @@ impl<'a> AioCb<'a> { /// SigevNotify::SigevNone, /// LioOpcode::LIO_NOP); /// aiocb.read().unwrap(); - /// while (aiocb.error() == Err(Errno::EINPROGRESS)) { + /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) { /// thread::sleep(time::Duration::from_millis(10)); /// } /// assert_eq!(aiocb.aio_return().unwrap() as usize, LEN); /// } /// assert_eq!(rbuf, b"cdef"); + /// # } /// ``` pub fn from_mut_slice(fd: RawFd, offs: off_t, buf: &'a mut [u8], prio: libc::c_int, sigev_notify: SigevNotify, - opcode: LioOpcode) -> Pin<Box<AioCb<'a>>> { + opcode: LioOpcode) -> AioCb<'a> { let mut a = AioCb::common_init(fd, prio, sigev_notify); - a.0.aio_offset = offs; - a.0.aio_nbytes = buf.len() as size_t; - a.0.aio_buf = buf.as_ptr() as *mut c_void; - a.0.aio_lio_opcode = opcode as libc::c_int; + a.aio_offset = offs; + a.aio_nbytes = buf.len() as size_t; + a.aio_buf = buf.as_ptr() as *mut c_void; + a.aio_lio_opcode = opcode as libc::c_int; - Box::pin(AioCb { + AioCb { aiocb: a, mutable: true, in_progress: false, - _buffer: PhantomData, - _pin: std::marker::PhantomPinned - }) + buffer: Buffer::Phantom(PhantomData), + } + } + + /// The safest and most flexible way to create an `AioCb`. + /// + /// Unlike [`from_slice`], this method returns a structure suitable for + /// placement on the heap. It may be used for write operations, but not + /// read operations. Unlike `from_ptr`, this method will ensure that the + /// buffer doesn't `drop` while the kernel is still processing it. Any + /// object that can be borrowed as a boxed slice will work. + /// + /// # Parameters + /// + /// * `fd`: File descriptor. Required for all aio functions. + /// * `offs`: File offset + /// * `buf`: A boxed slice-like object + /// * `prio`: If POSIX Prioritized IO is supported, then the + /// operation will be prioritized at the process's + /// priority level minus `prio` + /// * `sigev_notify`: Determines how you will be notified of event + /// completion. + /// * `opcode`: This field is only used for `lio_listio`. It + /// determines which operation to use for this individual + /// aiocb + /// + /// # Examples + /// + /// Create an `AioCb` from a Vector and use it for writing + /// + /// ``` + /// # use nix::errno::Errno; + /// # use nix::Error; + /// # use nix::sys::aio::*; + /// # use nix::sys::signal::SigevNotify; + /// # use std::{thread, time}; + /// # use std::io::Write; + /// # use std::os::unix::io::AsRawFd; + /// # use tempfile::tempfile; + /// # fn main() { + /// let wbuf = Box::new(Vec::from("CDEF")); + /// let expected_len = wbuf.len(); + /// let mut f = tempfile().unwrap(); + /// let mut aiocb = AioCb::from_boxed_slice( f.as_raw_fd(), + /// 2, //offset + /// wbuf, + /// 0, //priority + /// SigevNotify::SigevNone, + /// LioOpcode::LIO_NOP); + /// aiocb.write().unwrap(); + /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) { + /// thread::sleep(time::Duration::from_millis(10)); + /// } + /// assert_eq!(aiocb.aio_return().unwrap() as usize, expected_len); + /// # } + /// ``` + /// + /// Create an `AioCb` from a `Bytes` object + /// + /// ``` + /// # use bytes::Bytes; + /// # use nix::sys::aio::*; + /// # use nix::sys::signal::SigevNotify; + /// # use std::os::unix::io::AsRawFd; + /// # use tempfile::tempfile; + /// # fn main() { + /// let wbuf = Box::new(Bytes::from(&b"CDEF"[..])); + /// let mut f = tempfile().unwrap(); + /// let mut aiocb = AioCb::from_boxed_slice( f.as_raw_fd(), + /// 2, //offset + /// wbuf, + /// 0, //priority + /// SigevNotify::SigevNone, + /// LioOpcode::LIO_NOP); + /// # } + /// ``` + /// + /// If a library needs to work with buffers that aren't `Box`ed, it can + /// create a `Box`ed container for use with this method. Here's an example + /// using an un`Box`ed `Bytes` object. + /// + /// ``` + /// # use bytes::Bytes; + /// # use nix::sys::aio::*; + /// # use nix::sys::signal::SigevNotify; + /// # use std::borrow::Borrow; + /// # use std::os::unix::io::AsRawFd; + /// # use tempfile::tempfile; + /// struct BytesContainer(Bytes); + /// impl Borrow<[u8]> for BytesContainer { + /// fn borrow(&self) -> &[u8] { + /// self.0.as_ref() + /// } + /// } + /// fn main() { + /// let wbuf = Bytes::from(&b"CDEF"[..]); + /// let boxed_wbuf = Box::new(BytesContainer(wbuf)); + /// let mut f = tempfile().unwrap(); + /// let mut aiocb = AioCb::from_boxed_slice( f.as_raw_fd(), + /// 2, //offset + /// boxed_wbuf, + /// 0, //priority + /// SigevNotify::SigevNone, + /// LioOpcode::LIO_NOP); + /// } + /// ``` + /// + /// [`from_slice`]: #method.from_slice + pub fn from_boxed_slice(fd: RawFd, offs: off_t, buf: Box<dyn Borrow<[u8]>>, + prio: libc::c_int, sigev_notify: SigevNotify, + opcode: LioOpcode) -> AioCb<'a> { + let mut a = AioCb::common_init(fd, prio, sigev_notify); + { + let borrowed : &dyn Borrow<[u8]> = buf.borrow(); + let slice : &[u8] = borrowed.borrow(); + a.aio_nbytes = slice.len() as size_t; + a.aio_buf = slice.as_ptr() as *mut c_void; + } + a.aio_offset = offs; + a.aio_lio_opcode = opcode as libc::c_int; + + AioCb { + aiocb: a, + mutable: false, + in_progress: false, + buffer: Buffer::BoxedSlice(buf), + } + } + + /// The safest and most flexible way to create an `AioCb` for reading. + /// + /// Like [`from_boxed_slice`], but the slice is a mutable one. More + /// flexible than [`from_mut_slice`], because a wide range of objects can be + /// used. + /// + /// # Examples + /// + /// Create an `AioCb` from a Vector and use it for reading + /// + /// ``` + /// # use nix::errno::Errno; + /// # use nix::Error; + /// # use nix::sys::aio::*; + /// # use nix::sys::signal::SigevNotify; + /// # use std::{thread, time}; + /// # use std::io::Write; + /// # use std::os::unix::io::AsRawFd; + /// # use tempfile::tempfile; + /// # fn main() { + /// const INITIAL: &[u8] = b"abcdef123456"; + /// const LEN: usize = 4; + /// let rbuf = Box::new(vec![0; LEN]); + /// let mut f = tempfile().unwrap(); + /// f.write_all(INITIAL).unwrap(); + /// let mut aiocb = AioCb::from_boxed_mut_slice( f.as_raw_fd(), + /// 2, //offset + /// rbuf, + /// 0, //priority + /// SigevNotify::SigevNone, + /// LioOpcode::LIO_NOP); + /// aiocb.read().unwrap(); + /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) { + /// thread::sleep(time::Duration::from_millis(10)); + /// } + /// assert_eq!(aiocb.aio_return().unwrap() as usize, LEN); + /// let mut buffer = aiocb.boxed_mut_slice().unwrap(); + /// const EXPECT: &[u8] = b"cdef"; + /// assert_eq!(buffer.borrow_mut(), EXPECT); + /// # } + /// ``` + /// + /// [`from_boxed_slice`]: #method.from_boxed_slice + /// [`from_mut_slice`]: #method.from_mut_slice + pub fn from_boxed_mut_slice(fd: RawFd, offs: off_t, + mut buf: Box<dyn BorrowMut<[u8]>>, + prio: libc::c_int, sigev_notify: SigevNotify, + opcode: LioOpcode) -> AioCb<'a> { + let mut a = AioCb::common_init(fd, prio, sigev_notify); + { + let borrowed : &mut dyn BorrowMut<[u8]> = buf.borrow_mut(); + let slice : &mut [u8] = borrowed.borrow_mut(); + a.aio_nbytes = slice.len() as size_t; + a.aio_buf = slice.as_mut_ptr() as *mut c_void; + } + a.aio_offset = offs; + a.aio_lio_opcode = opcode as libc::c_int; + + AioCb { + aiocb: a, + mutable: true, + in_progress: false, + buffer: Buffer::BoxedMutSlice(buf), + } } /// Constructs a new `AioCb` from a mutable raw pointer @@ -270,7 +527,8 @@ impl<'a> AioCb<'a> { /// Unlike `from_mut_slice`, this method returns a structure suitable for /// placement on the heap. It may be used for both reads and writes. Due /// to its unsafety, this method is not recommended. It is most useful when - /// heap allocation is required. + /// heap allocation is required but for some reason the data cannot be + /// wrapped in a `struct` that implements `BorrowMut<[u8]>` /// /// # Parameters /// @@ -294,27 +552,28 @@ impl<'a> AioCb<'a> { pub unsafe fn from_mut_ptr(fd: RawFd, offs: off_t, buf: *mut c_void, len: usize, prio: libc::c_int, sigev_notify: SigevNotify, - opcode: LioOpcode) -> Pin<Box<AioCb<'a>>> { + opcode: LioOpcode) -> AioCb<'a> { let mut a = AioCb::common_init(fd, prio, sigev_notify); - a.0.aio_offset = offs; - a.0.aio_nbytes = len; - a.0.aio_buf = buf; - a.0.aio_lio_opcode = opcode as libc::c_int; + a.aio_offset = offs; + a.aio_nbytes = len; + a.aio_buf = buf; + a.aio_lio_opcode = opcode as libc::c_int; - Box::pin(AioCb { + AioCb { aiocb: a, mutable: true, in_progress: false, - _buffer: PhantomData, - _pin: std::marker::PhantomPinned, - }) + buffer: Buffer::None + } } /// Constructs a new `AioCb` from a raw pointer. /// /// Unlike `from_slice`, this method returns a structure suitable for /// placement on the heap. Due to its unsafety, this method is not - /// recommended. It is most useful when heap allocation is required. + /// recommended. It is most useful when heap allocation is required but for + /// some reason the data cannot be wrapped in a `struct` that implements + /// `Borrow<[u8]>` /// /// # Parameters /// @@ -338,49 +597,24 @@ impl<'a> AioCb<'a> { pub unsafe fn from_ptr(fd: RawFd, offs: off_t, buf: *const c_void, len: usize, prio: libc::c_int, sigev_notify: SigevNotify, - opcode: LioOpcode) -> Pin<Box<AioCb<'a>>> { + opcode: LioOpcode) -> AioCb<'a> { let mut a = AioCb::common_init(fd, prio, sigev_notify); - a.0.aio_offset = offs; - a.0.aio_nbytes = len; + a.aio_offset = offs; + a.aio_nbytes = len; // casting a const ptr to a mutable ptr here is ok, because we set the // AioCb's mutable field to false - a.0.aio_buf = buf as *mut c_void; - a.0.aio_lio_opcode = opcode as libc::c_int; - - Box::pin(AioCb { - aiocb: a, - mutable: false, - in_progress: false, - _buffer: PhantomData, - _pin: std::marker::PhantomPinned - }) - } - - // Private helper - fn from_slice_unpinned(fd: RawFd, offs: off_t, buf: &'a [u8], - prio: libc::c_int, sigev_notify: SigevNotify, - opcode: LioOpcode) -> AioCb - { - let mut a = AioCb::common_init(fd, prio, sigev_notify); - a.0.aio_offset = offs; - a.0.aio_nbytes = buf.len() as size_t; - // casting an immutable buffer to a mutable pointer looks unsafe, - // but technically its only unsafe to dereference it, not to create - // it. - a.0.aio_buf = buf.as_ptr() as *mut c_void; - assert!(opcode != LioOpcode::LIO_READ, "Can't read into an immutable buffer"); - a.0.aio_lio_opcode = opcode as libc::c_int; + a.aio_buf = buf as *mut c_void; + a.aio_lio_opcode = opcode as libc::c_int; AioCb { aiocb: a, mutable: false, in_progress: false, - _buffer: PhantomData, - _pin: std::marker::PhantomPinned + buffer: Buffer::None } } - /// Like [`AioCb::from_mut_slice`], but works on constant slices rather than + /// Like `from_mut_slice`, but works on constant slices rather than /// mutable slices. /// /// An `AioCb` created this way cannot be used with `read`, and its @@ -400,6 +634,7 @@ impl<'a> AioCb<'a> { /// # use std::{thread, time}; /// # use std::os::unix::io::AsRawFd; /// # use tempfile::tempfile; + /// # fn main() { /// const WBUF: &[u8] = b"abcdef123456"; /// let mut f = tempfile().unwrap(); /// let mut aiocb = AioCb::from_slice( f.as_raw_fd(), @@ -409,10 +644,11 @@ impl<'a> AioCb<'a> { /// SigevNotify::SigevNone, /// LioOpcode::LIO_NOP); /// aiocb.write().unwrap(); - /// while (aiocb.error() == Err(Errno::EINPROGRESS)) { + /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) { /// thread::sleep(time::Duration::from_millis(10)); /// } /// assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len()); + /// # } /// ``` // Note: another solution to the problem of writing const buffers would be // to genericize AioCb for both &mut [u8] and &[u8] buffers. AioCb::read @@ -421,14 +657,27 @@ impl<'a> AioCb<'a> { // AioCb, and they must all be of the same type. pub fn from_slice(fd: RawFd, offs: off_t, buf: &'a [u8], prio: libc::c_int, sigev_notify: SigevNotify, - opcode: LioOpcode) -> Pin<Box<AioCb>> - { - Box::pin(AioCb::from_slice_unpinned(fd, offs, buf, prio, sigev_notify, - opcode)) + opcode: LioOpcode) -> AioCb { + let mut a = AioCb::common_init(fd, prio, sigev_notify); + a.aio_offset = offs; + a.aio_nbytes = buf.len() as size_t; + // casting an immutable buffer to a mutable pointer looks unsafe, + // but technically its only unsafe to dereference it, not to create + // it. + a.aio_buf = buf.as_ptr() as *mut c_void; + assert!(opcode != LioOpcode::LIO_READ, "Can't read into an immutable buffer"); + a.aio_lio_opcode = opcode as libc::c_int; + + AioCb { + aiocb: a, + mutable: false, + in_progress: false, + buffer: Buffer::None, + } } fn common_init(fd: RawFd, prio: libc::c_int, - sigev_notify: SigevNotify) -> LibcAiocb { + sigev_notify: SigevNotify) -> libc::aiocb { // Use mem::zeroed instead of explicitly zeroing each field, because the // number and name of reserved fields is OS-dependent. On some OSes, // some reserved fields are used the kernel for state, and must be @@ -437,18 +686,12 @@ impl<'a> AioCb<'a> { a.aio_fildes = fd; a.aio_reqprio = prio; a.aio_sigevent = SigEvent::new(sigev_notify).sigevent(); - LibcAiocb(a) + a } /// Update the notification settings for an existing `aiocb` - pub fn set_sigev_notify(self: &mut Pin<Box<Self>>, - sigev_notify: SigevNotify) - { - // Safe because we don't move any of the data - let selfp = unsafe { - self.as_mut().get_unchecked_mut() - }; - selfp.aiocb.0.aio_sigevent = SigEvent::new(sigev_notify).sigevent(); + pub fn set_sigev_notify(&mut self, sigev_notify: SigevNotify) { + self.aiocb.aio_sigevent = SigEvent::new(sigev_notify).sigevent(); } /// Cancels an outstanding AIO request. @@ -474,6 +717,7 @@ impl<'a> AioCb<'a> { /// # use std::io::Write; /// # use std::os::unix::io::AsRawFd; /// # use tempfile::tempfile; + /// # fn main() { /// let wbuf = b"CDEF"; /// let mut f = tempfile().unwrap(); /// let mut aiocb = AioCb::from_slice( f.as_raw_fd(), @@ -485,43 +729,28 @@ impl<'a> AioCb<'a> { /// aiocb.write().unwrap(); /// let cs = aiocb.cancel().unwrap(); /// if cs == AioCancelStat::AioNotCanceled { - /// while (aiocb.error() == Err(Errno::EINPROGRESS)) { + /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) { /// thread::sleep(time::Duration::from_millis(10)); /// } /// } /// // Must call `aio_return`, but ignore the result /// let _ = aiocb.aio_return(); + /// # } /// ``` /// /// # References /// - /// [aio_cancel](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html) - pub fn cancel(self: &mut Pin<Box<Self>>) -> Result<AioCancelStat> { - let r = unsafe { - let selfp = self.as_mut().get_unchecked_mut(); - libc::aio_cancel(selfp.aiocb.0.aio_fildes, &mut selfp.aiocb.0) - }; - match r { + /// [aio_cancel](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html) + pub fn cancel(&mut self) -> Result<AioCancelStat> { + match unsafe { libc::aio_cancel(self.aiocb.aio_fildes, &mut self.aiocb) } { libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled), libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled), libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone), - -1 => Err(Errno::last()), + -1 => Err(Error::last()), _ => panic!("unknown aio_cancel return value") } } - fn error_unpinned(&mut self) -> Result<()> { - let r = unsafe { - libc::aio_error(&mut self.aiocb.0 as *mut libc::aiocb) - }; - match r { - 0 => Ok(()), - num if num > 0 => Err(Errno::from_i32(num)), - -1 => Err(Errno::last()), - num => panic!("unknown aio_error return value {:?}", num) - } - } - /// Retrieve error status of an asynchronous operation. /// /// If the request has not yet completed, returns `EINPROGRESS`. Otherwise, @@ -540,6 +769,7 @@ impl<'a> AioCb<'a> { /// # use std::{thread, time}; /// # use std::os::unix::io::AsRawFd; /// # use tempfile::tempfile; + /// # fn main() { /// const WBUF: &[u8] = b"abcdef123456"; /// let mut f = tempfile().unwrap(); /// let mut aiocb = AioCb::from_slice( f.as_raw_fd(), @@ -549,39 +779,37 @@ impl<'a> AioCb<'a> { /// SigevNotify::SigevNone, /// LioOpcode::LIO_NOP); /// aiocb.write().unwrap(); - /// while (aiocb.error() == Err(Errno::EINPROGRESS)) { + /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) { /// thread::sleep(time::Duration::from_millis(10)); /// } /// assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len()); + /// # } /// ``` /// /// # References /// - /// [aio_error](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_error.html) - pub fn error(self: &mut Pin<Box<Self>>) -> Result<()> { - // Safe because error_unpinned doesn't move the data - let selfp = unsafe { - self.as_mut().get_unchecked_mut() - }; - selfp.error_unpinned() + /// [aio_error](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_error.html) + pub fn error(&mut self) -> Result<()> { + match unsafe { libc::aio_error(&mut self.aiocb as *mut libc::aiocb) } { + 0 => Ok(()), + num if num > 0 => Err(Error::from_errno(Errno::from_i32(num))), + -1 => Err(Error::last()), + num => panic!("unknown aio_error return value {:?}", num) + } } /// An asynchronous version of `fsync(2)`. /// /// # References /// - /// [aio_fsync](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_fsync.html) - pub fn fsync(self: &mut Pin<Box<Self>>, mode: AioFsyncMode) -> Result<()> { - // Safe because we don't move the libc::aiocb - unsafe { - let selfp = self.as_mut().get_unchecked_mut(); - Errno::result({ - let p: *mut libc::aiocb = &mut selfp.aiocb.0; + /// [aio_fsync](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_fsync.html) + pub fn fsync(&mut self, mode: AioFsyncMode) -> Result<()> { + let p: *mut libc::aiocb = &mut self.aiocb; + Errno::result(unsafe { libc::aio_fsync(mode as libc::c_int, p) - }).map(|_| { - selfp.in_progress = true; - }) - } + }).map(|_| { + self.in_progress = true; + }) } /// Returns the `aiocb`'s `LioOpcode` field @@ -589,7 +817,7 @@ impl<'a> AioCb<'a> { /// If the value cannot be represented as an `LioOpcode`, returns `None` /// instead. pub fn lio_opcode(&self) -> Option<LioOpcode> { - match self.aiocb.0.aio_lio_opcode { + match self.aiocb.aio_lio_opcode { libc::LIO_READ => Some(LioOpcode::LIO_READ), libc::LIO_WRITE => Some(LioOpcode::LIO_WRITE), libc::LIO_NOP => Some(LioOpcode::LIO_NOP), @@ -603,49 +831,37 @@ impl<'a> AioCb<'a> { /// number of bytes actually read or written by a completed operation, use /// `aio_return` instead. pub fn nbytes(&self) -> usize { - self.aiocb.0.aio_nbytes + self.aiocb.aio_nbytes } /// Returns the file offset stored in the `AioCb` pub fn offset(&self) -> off_t { - self.aiocb.0.aio_offset + self.aiocb.aio_offset } /// Returns the priority of the `AioCb` pub fn priority(&self) -> libc::c_int { - self.aiocb.0.aio_reqprio + self.aiocb.aio_reqprio } /// Asynchronously reads from a file descriptor into a buffer /// /// # References /// - /// [aio_read](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_read.html) - pub fn read(self: &mut Pin<Box<Self>>) -> Result<()> { + /// [aio_read](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_read.html) + pub fn read(&mut self) -> Result<()> { assert!(self.mutable, "Can't read into an immutable buffer"); - // Safe because we don't move anything - let selfp = unsafe { - self.as_mut().get_unchecked_mut() - }; - Errno::result({ - let p: *mut libc::aiocb = &mut selfp.aiocb.0; - unsafe { libc::aio_read(p) } + let p: *mut libc::aiocb = &mut self.aiocb; + Errno::result(unsafe { + libc::aio_read(p) }).map(|_| { - selfp.in_progress = true; + self.in_progress = true; }) } /// Returns the `SigEvent` stored in the `AioCb` pub fn sigevent(&self) -> SigEvent { - SigEvent::from(&self.aiocb.0.aio_sigevent) - } - - fn aio_return_unpinned(&mut self) -> Result<isize> { - unsafe { - let p: *mut libc::aiocb = &mut self.aiocb.0; - self.in_progress = false; - Errno::result(libc::aio_return(p)) - } + SigEvent::from(&self.aiocb.aio_sigevent) } /// Retrieve return status of an asynchronous operation. @@ -656,33 +872,28 @@ impl<'a> AioCb<'a> { /// /// # References /// - /// [aio_return](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_return.html) + /// [aio_return](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_return.html) // Note: this should be just `return`, but that's a reserved word - pub fn aio_return(self: &mut Pin<Box<Self>>) -> Result<isize> { - // Safe because aio_return_unpinned does not move the data - let selfp = unsafe { - self.as_mut().get_unchecked_mut() - }; - selfp.aio_return_unpinned() + pub fn aio_return(&mut self) -> Result<isize> { + let p: *mut libc::aiocb = &mut self.aiocb; + self.in_progress = false; + Errno::result(unsafe { libc::aio_return(p) }) } /// Asynchronously writes from a buffer to a file descriptor /// /// # References /// - /// [aio_write](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_write.html) - pub fn write(self: &mut Pin<Box<Self>>) -> Result<()> { - // Safe because we don't move anything - let selfp = unsafe { - self.as_mut().get_unchecked_mut() - }; - Errno::result({ - let p: *mut libc::aiocb = &mut selfp.aiocb.0; - unsafe{ libc::aio_write(p) } + /// [aio_write](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_write.html) + pub fn write(&mut self) -> Result<()> { + let p: *mut libc::aiocb = &mut self.aiocb; + Errno::result(unsafe { + libc::aio_write(p) }).map(|_| { - selfp.in_progress = true; + self.in_progress = true; }) } + } /// Cancels outstanding AIO requests for a given file descriptor. @@ -701,6 +912,7 @@ impl<'a> AioCb<'a> { /// # use std::io::Write; /// # use std::os::unix::io::AsRawFd; /// # use tempfile::tempfile; +/// # fn main() { /// let wbuf = b"CDEF"; /// let mut f = tempfile().unwrap(); /// let mut aiocb = AioCb::from_slice( f.as_raw_fd(), @@ -712,23 +924,24 @@ impl<'a> AioCb<'a> { /// aiocb.write().unwrap(); /// let cs = aio_cancel_all(f.as_raw_fd()).unwrap(); /// if cs == AioCancelStat::AioNotCanceled { -/// while (aiocb.error() == Err(Errno::EINPROGRESS)) { +/// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) { /// thread::sleep(time::Duration::from_millis(10)); /// } /// } /// // Must call `aio_return`, but ignore the result /// let _ = aiocb.aio_return(); +/// # } /// ``` /// /// # References /// -/// [`aio_cancel`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html) +/// [`aio_cancel`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html) pub fn aio_cancel_all(fd: RawFd) -> Result<AioCancelStat> { match unsafe { libc::aio_cancel(fd, null_mut()) } { libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled), libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled), libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone), - -1 => Err(Errno::last()), + -1 => Err(Error::last()), _ => panic!("unknown aio_cancel return value") } } @@ -747,6 +960,7 @@ pub fn aio_cancel_all(fd: RawFd) -> Result<AioCancelStat> { /// # use nix::sys::signal::SigevNotify; /// # use std::os::unix::io::AsRawFd; /// # use tempfile::tempfile; +/// # fn main() { /// const WBUF: &[u8] = b"abcdef123456"; /// let mut f = tempfile().unwrap(); /// let mut aiocb = AioCb::from_slice( f.as_raw_fd(), @@ -756,14 +970,15 @@ pub fn aio_cancel_all(fd: RawFd) -> Result<AioCancelStat> { /// SigevNotify::SigevNone, /// LioOpcode::LIO_NOP); /// aiocb.write().unwrap(); -/// aio_suspend(&[aiocb.as_ref()], None).expect("aio_suspend failed"); +/// aio_suspend(&[&aiocb], None).expect("aio_suspend failed"); /// assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len()); +/// # } /// ``` /// # References /// -/// [`aio_suspend`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_suspend.html) -pub fn aio_suspend(list: &[Pin<&AioCb>], timeout: Option<TimeSpec>) -> Result<()> { - let plist = list as *const [Pin<&AioCb>] as *const [*const libc::aiocb]; +/// [`aio_suspend`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_suspend.html) +pub fn aio_suspend(list: &[&AioCb], timeout: Option<TimeSpec>) -> Result<()> { + let plist = list as *const [&AioCb] as *const [*const libc::aiocb]; let p = plist as *const *const libc::aiocb; let timep = match timeout { None => null::<libc::timespec>(), @@ -777,7 +992,7 @@ pub fn aio_suspend(list: &[Pin<&AioCb>], timeout: Option<TimeSpec>) -> Result<() impl<'a> Debug for AioCb<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("AioCb") - .field("aiocb", &self.aiocb.0) + .field("aiocb", &self.aiocb) .field("mutable", &self.mutable) .field("in_progress", &self.in_progress) .finish() @@ -803,9 +1018,7 @@ pub struct LioCb<'a> { /// /// [`AioCb`]: struct.AioCb.html /// [`listio`]: #method.listio - // Their locations in memory must be fixed once they are passed to the - // kernel. So this field must be non-public so the user can't swap. - aiocbs: Box<[AioCb<'a>]>, + pub aiocbs: Vec<AioCb<'a>>, /// The actual list passed to `libc::lio_listio`. /// @@ -819,24 +1032,15 @@ pub struct LioCb<'a> { results: Vec<Option<Result<isize>>> } -/// LioCb can't automatically impl Send and Sync just because of the raw -/// pointers in list. But that's stupid. There's no reason that raw pointers -/// should automatically be non-Send -#[cfg(not(any(target_os = "ios", target_os = "macos")))] -unsafe impl<'a> Send for LioCb<'a> {} -#[cfg(not(any(target_os = "ios", target_os = "macos")))] -unsafe impl<'a> Sync for LioCb<'a> {} - #[cfg(not(any(target_os = "ios", target_os = "macos")))] impl<'a> LioCb<'a> { - /// Are no [`AioCb`]s contained? - pub fn is_empty(&self) -> bool { - self.aiocbs.is_empty() - } - - /// Return the number of individual [`AioCb`]s contained. - pub fn len(&self) -> usize { - self.aiocbs.len() + /// Initialize an empty `LioCb` + pub fn with_capacity(capacity: usize) -> LioCb<'a> { + LioCb { + aiocbs: Vec::with_capacity(capacity), + list: Vec::with_capacity(capacity), + results: Vec::with_capacity(capacity) + } } /// Submits multiple asynchronous I/O requests with a single system call. @@ -862,25 +1066,25 @@ impl<'a> LioCb<'a> { /// # use nix::sys::signal::SigevNotify; /// # use std::os::unix::io::AsRawFd; /// # use tempfile::tempfile; + /// # fn main() { /// const WBUF: &[u8] = b"abcdef123456"; /// let mut f = tempfile().unwrap(); - /// let mut liocb = LioCbBuilder::with_capacity(1) - /// .emplace_slice( - /// f.as_raw_fd(), - /// 2, //offset - /// WBUF, - /// 0, //priority - /// SigevNotify::SigevNone, - /// LioOpcode::LIO_WRITE - /// ).finish(); + /// let mut liocb = LioCb::with_capacity(1); + /// liocb.aiocbs.push(AioCb::from_slice( f.as_raw_fd(), + /// 2, //offset + /// WBUF, + /// 0, //priority + /// SigevNotify::SigevNone, + /// LioOpcode::LIO_WRITE)); /// liocb.listio(LioMode::LIO_WAIT, /// SigevNotify::SigevNone).unwrap(); /// assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len()); + /// # } /// ``` /// /// # References /// - /// [`lio_listio`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/lio_listio.html) + /// [`lio_listio`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lio_listio.html) /// /// [`aio_suspend`]: fn.aio_suspend.html /// [`AioCb::error`]: struct.AioCb.html#method.error @@ -889,7 +1093,7 @@ impl<'a> LioCb<'a> { let sigev = SigEvent::new(sigev_notify); let sigevp = &mut sigev.sigevent() as *mut libc::sigevent; self.list.clear(); - for a in &mut self.aiocbs.iter_mut() { + for a in &mut self.aiocbs { a.in_progress = true; self.list.push(a as *mut AioCb<'a> as *mut libc::aiocb); @@ -920,31 +1124,31 @@ impl<'a> LioCb<'a> { /// # use std::os::unix::io::AsRawFd; /// # use std::{thread, time}; /// # use tempfile::tempfile; + /// # fn main() { /// const WBUF: &[u8] = b"abcdef123456"; /// let mut f = tempfile().unwrap(); - /// let mut liocb = LioCbBuilder::with_capacity(1) - /// .emplace_slice( - /// f.as_raw_fd(), - /// 2, //offset - /// WBUF, - /// 0, //priority - /// SigevNotify::SigevNone, - /// LioOpcode::LIO_WRITE - /// ).finish(); + /// let mut liocb = LioCb::with_capacity(1); + /// liocb.aiocbs.push(AioCb::from_slice( f.as_raw_fd(), + /// 2, //offset + /// WBUF, + /// 0, //priority + /// SigevNotify::SigevNone, + /// LioOpcode::LIO_WRITE)); /// let mut err = liocb.listio(LioMode::LIO_WAIT, SigevNotify::SigevNone); - /// while err == Err(Errno::EIO) || - /// err == Err(Errno::EAGAIN) { + /// while err == Err(Error::Sys(Errno::EIO)) || + /// err == Err(Error::Sys(Errno::EAGAIN)) { /// thread::sleep(time::Duration::from_millis(10)); /// err = liocb.listio_resubmit(LioMode::LIO_WAIT, SigevNotify::SigevNone); /// } /// assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len()); + /// # } /// ``` /// /// # References /// - /// [`lio_listio`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/lio_listio.html) + /// [`lio_listio`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lio_listio.html) /// - /// [`lio_listio`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/lio_listio.html + /// [`lio_listio`]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/lio_listio.html /// [`LioCb::aio_return`]: struct.LioCb.html#method.aio_return // Note: the addresses of any EINPROGRESS or EOK aiocbs _must_ not be // changed by this method, because the kernel relies on their addresses @@ -966,18 +1170,18 @@ impl<'a> LioCb<'a> { // Already collected final status for this operation continue; } - match a.error_unpinned() { + match a.error() { Ok(()) => { // aiocb is complete; collect its status and don't resubmit - self.results[i] = Some(a.aio_return_unpinned()); + self.results[i] = Some(a.aio_return()); }, - Err(Errno::EAGAIN) => { + Err(Error::Sys(Errno::EAGAIN)) => { self.list.push(a as *mut AioCb<'a> as *mut libc::aiocb); }, - Err(Errno::EINPROGRESS) => { + Err(Error::Sys(Errno::EINPROGRESS)) => { // aiocb is was successfully queued; no need to do anything }, - Err(Errno::EINVAL) => panic!( + Err(Error::Sys(Errno::EINVAL)) => panic!( "AioCb was never submitted, or already finalized"), _ => unreachable!() } @@ -998,7 +1202,7 @@ impl<'a> LioCb<'a> { /// [`LioCb::listio_resubmit`]: #method.listio_resubmit pub fn aio_return(&mut self, i: usize) -> Result<isize> { if i >= self.results.len() || self.results[i].is_none() { - self.aiocbs[i].aio_return_unpinned() + self.aiocbs[i].aio_return() } else { self.results[i].unwrap() } @@ -1014,7 +1218,7 @@ impl<'a> LioCb<'a> { /// [`LioCb::listio_resubmit`]: #method.listio_resubmit pub fn error(&mut self, i: usize) -> Result<()> { if i >= self.results.len() || self.results[i].is_none() { - self.aiocbs[i].error_unpinned() + self.aiocbs[i].error() } else { Ok(()) } @@ -1030,93 +1234,13 @@ impl<'a> Debug for LioCb<'a> { } } -/// Used to construct `LioCb` -// This must be a separate class from LioCb due to pinning constraints. LioCb -// must use a boxed slice of AioCbs so they will have stable storage, but -// LioCbBuilder must use a Vec to make construction possible when the final size -// is unknown. #[cfg(not(any(target_os = "ios", target_os = "macos")))] -#[derive(Debug)] -pub struct LioCbBuilder<'a> { - /// A collection of [`AioCb`]s. - /// - /// [`AioCb`]: struct.AioCb.html - pub aiocbs: Vec<AioCb<'a>>, -} - -#[cfg(not(any(target_os = "ios", target_os = "macos")))] -impl<'a> LioCbBuilder<'a> { - /// Initialize an empty `LioCb` - pub fn with_capacity(capacity: usize) -> LioCbBuilder<'a> { - LioCbBuilder { - aiocbs: Vec::with_capacity(capacity), - } - } - - /// Add a new operation on an immutable slice to the [`LioCb`] under - /// construction. - /// - /// Arguments are the same as for [`AioCb::from_slice`] - /// - /// [`LioCb`]: struct.LioCb.html - /// [`AioCb::from_slice`]: struct.AioCb.html#method.from_slice - pub fn emplace_slice(mut self, fd: RawFd, offs: off_t, buf: &'a [u8], - prio: libc::c_int, sigev_notify: SigevNotify, - opcode: LioOpcode) -> Self - { - self.aiocbs.push(AioCb::from_slice_unpinned(fd, offs, buf, prio, - sigev_notify, opcode)); - self - } - - /// Add a new operation on a mutable slice to the [`LioCb`] under - /// construction. - /// - /// Arguments are the same as for [`AioCb::from_mut_slice`] - /// - /// [`LioCb`]: struct.LioCb.html - /// [`AioCb::from_mut_slice`]: struct.AioCb.html#method.from_mut_slice - pub fn emplace_mut_slice(mut self, fd: RawFd, offs: off_t, - buf: &'a mut [u8], prio: libc::c_int, - sigev_notify: SigevNotify, opcode: LioOpcode) - -> Self - { - self.aiocbs.push(AioCb::from_mut_slice_unpinned(fd, offs, buf, prio, - sigev_notify, opcode)); - self - } - - /// Finalize this [`LioCb`]. - /// - /// Afterwards it will be possible to issue the operations with - /// [`LioCb::listio`]. Conversely, it will no longer be possible to add new - /// operations with [`LioCbBuilder::emplace_slice`] or - /// [`LioCbBuilder::emplace_mut_slice`]. - /// - /// [`LioCb::listio`]: struct.LioCb.html#method.listio - /// [`LioCb::from_mut_slice`]: struct.LioCb.html#method.from_mut_slice - /// [`LioCb::from_slice`]: struct.LioCb.html#method.from_slice - pub fn finish(self) -> LioCb<'a> { - let len = self.aiocbs.len(); +impl<'a> From<Vec<AioCb<'a>>> for LioCb<'a> { + fn from(src: Vec<AioCb<'a>>) -> LioCb<'a> { LioCb { - aiocbs: self.aiocbs.into(), - list: Vec::with_capacity(len), - results: Vec::with_capacity(len) + list: Vec::with_capacity(src.capacity()), + results: Vec::with_capacity(src.capacity()), + aiocbs: src, } } } - -#[cfg(not(any(target_os = "ios", target_os = "macos")))] -#[cfg(test)] -mod t { - use super::*; - - // It's important that `LioCb` be `UnPin`. The tokio-file crate relies on - // it. - #[test] - fn liocb_is_unpin() { - use assert_impl::assert_impl; - - assert_impl!(Unpin: LioCb); - } -} diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs index 6bc2a25..2437bbe 100644 --- a/src/sys/epoll.rs +++ b/src/sys/epoll.rs @@ -4,6 +4,7 @@ use libc::{self, c_int}; use std::os::unix::io::RawFd; use std::ptr; use std::mem; +use crate::Error; libc_bitflags!( pub struct EpollFlags: c_int { @@ -29,7 +30,6 @@ libc_bitflags!( #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[repr(i32)] -#[non_exhaustive] pub enum EpollOp { EpollCtlAdd = libc::EPOLL_CTL_ADD, EpollCtlDel = libc::EPOLL_CTL_DEL, @@ -86,7 +86,7 @@ pub fn epoll_ctl<'a, T>(epfd: RawFd, op: EpollOp, fd: RawFd, event: T) -> Result { let mut event: Option<&mut EpollEvent> = event.into(); if event.is_none() && op != EpollOp::EpollCtlDel { - Err(Errno::EINVAL) + Err(Error::Sys(Errno::EINVAL)) } else { let res = unsafe { if let Some(ref mut event) = event { diff --git a/src/sys/event.rs b/src/sys/event.rs index c648f5e..8050af3 100644 --- a/src/sys/event.rs +++ b/src/sys/event.rs @@ -6,9 +6,9 @@ use crate::{Errno, Result}; use libc::{timespec, time_t, c_int, c_long, intptr_t, uintptr_t}; #[cfg(target_os = "netbsd")] use libc::{timespec, time_t, c_long, intptr_t, uintptr_t, size_t}; -use std::convert::TryInto; use std::os::unix::io::RawFd; use std::ptr; +use std::mem; // Redefine kevent in terms of programmer-friendly enums and bitfields. #[repr(C)] @@ -36,7 +36,6 @@ type type_of_event_filter = i16; libc_enum! { #[cfg_attr(target_os = "netbsd", repr(u32))] #[cfg_attr(not(target_os = "netbsd"), repr(i16))] - #[non_exhaustive] pub enum EventFilter { EVFILT_AIO, /// Returns whenever there is no remaining data in the write buffer @@ -76,7 +75,6 @@ libc_enum! { EVFILT_VNODE, EVFILT_WRITE, } - impl TryFrom<type_of_event_filter> } #[cfg(any(target_os = "dragonfly", target_os = "freebsd", @@ -234,8 +232,8 @@ impl KEvent { self.kevent.ident } - pub fn filter(&self) -> Result<EventFilter> { - self.kevent.filter.try_into() + pub fn filter(&self) -> EventFilter { + unsafe { mem::transmute(self.kevent.filter as type_of_event_filter) } } pub fn flags(&self) -> EventFlag { @@ -314,8 +312,6 @@ pub fn ev_set(ev: &mut KEvent, #[test] fn test_struct_kevent() { - use std::mem; - let udata : intptr_t = 12345; let actual = KEvent::new(0xdead_beef, @@ -325,24 +321,10 @@ fn test_struct_kevent() { 0x1337, udata); assert_eq!(0xdead_beef, actual.ident()); - let filter = actual.kevent.filter; - assert_eq!(libc::EVFILT_READ, filter); + assert_eq!(libc::EVFILT_READ, actual.filter() as type_of_event_filter); assert_eq!(libc::EV_ONESHOT | libc::EV_ADD, actual.flags().bits()); assert_eq!(libc::NOTE_CHILD | libc::NOTE_EXIT, actual.fflags().bits()); assert_eq!(0x1337, actual.data() as type_of_data); assert_eq!(udata as type_of_udata, actual.udata() as type_of_udata); assert_eq!(mem::size_of::<libc::kevent>(), mem::size_of::<KEvent>()); } - -#[test] -fn test_kevent_filter() { - let udata : intptr_t = 12345; - - let actual = KEvent::new(0xdead_beef, - EventFilter::EVFILT_READ, - EventFlag::EV_ONESHOT | EventFlag::EV_ADD, - FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT, - 0x1337, - udata); - assert_eq!(EventFilter::EVFILT_READ, actual.filter().unwrap()); -} diff --git a/src/sys/eventfd.rs b/src/sys/eventfd.rs index c54f952..baaaa89 100644 --- a/src/sys/eventfd.rs +++ b/src/sys/eventfd.rs @@ -1,3 +1,4 @@ +use libc; use std::os::unix::io::RawFd; use crate::Result; use crate::errno::Errno; diff --git a/src/sys/inotify.rs b/src/sys/inotify.rs index 3f5ae22..4880a4a 100644 --- a/src/sys/inotify.rs +++ b/src/sys/inotify.rs @@ -2,8 +2,8 @@ //! //! Inotify is a Linux-only API to monitor filesystems events. //! -//! For more documentation, please read [inotify(7)](https://man7.org/linux/man-pages/man7/inotify.7.html). -//! +//! For more documentation, please read [inotify(7)](http://man7.org/linux/man-pages/man7/inotify.7.html). +//! //! # Examples //! //! Monitor all events happening in directory "test": @@ -86,7 +86,7 @@ pub struct Inotify { /// This object is returned when you create a new watch on an inotify instance. /// It is then returned as part of an event once triggered. It allows you to -/// know which watch triggered which event. +/// know which watch triggered which event. #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd)] pub struct WatchDescriptor { wd: i32 @@ -94,18 +94,18 @@ pub struct WatchDescriptor { /// A single inotify event. /// -/// For more documentation see, [inotify(7)](https://man7.org/linux/man-pages/man7/inotify.7.html). +/// For more documentation see, [inotify(7)](http://man7.org/linux/man-pages/man7/inotify.7.html). #[derive(Debug)] pub struct InotifyEvent { /// Watch descriptor. This field corresponds to the watch descriptor you /// were issued when calling add_watch. It allows you to know which watch - /// this event comes from. + /// this event comes from. pub wd: WatchDescriptor, /// Event mask. This field is a bitfield describing the exact event that /// occured. pub mask: AddWatchFlags, /// This cookie is a number that allows you to connect related events. For - /// now only IN_MOVED_FROM and IN_MOVED_TO can be connected. + /// now only IN_MOVED_FROM and IN_MOVED_TO can be connected. pub cookie: u32, /// Filename. This field exists only if the event was triggered for a file /// inside the watched directory. @@ -117,7 +117,7 @@ impl Inotify { /// /// Returns a Result containing an inotify instance. /// - /// For more information see, [inotify_init(2)](https://man7.org/linux/man-pages/man2/inotify_init.2.html). + /// For more information see, [inotify_init(2)](http://man7.org/linux/man-pages/man2/inotify_init.2.html). pub fn init(flags: InitFlags) -> Result<Inotify> { let res = Errno::result(unsafe { libc::inotify_init1(flags.bits()) @@ -126,14 +126,14 @@ impl Inotify { res.map(|fd| Inotify { fd }) } - /// Adds a new watch on the target file or directory. + /// Adds a new watch on the target file or directory. /// - /// Returns a watch descriptor. This is not a File Descriptor! + /// Returns a watch descriptor. This is not a File Descriptor! /// - /// For more information see, [inotify_add_watch(2)](https://man7.org/linux/man-pages/man2/inotify_add_watch.2.html). + /// For more information see, [inotify_add_watch(2)](http://man7.org/linux/man-pages/man2/inotify_add_watch.2.html). pub fn add_watch<P: ?Sized + NixPath>(self, path: &P, - mask: AddWatchFlags) + mask: AddWatchFlags) -> Result<WatchDescriptor> { let res = path.with_nix_path(|cstr| { @@ -150,7 +150,7 @@ impl Inotify { /// /// Returns an EINVAL error if the watch descriptor is invalid. /// - /// For more information see, [inotify_rm_watch(2)](https://man7.org/linux/man-pages/man2/inotify_rm_watch.2.html). + /// For more information see, [inotify_rm_watch(2)](http://man7.org/linux/man-pages/man2/inotify_rm_watch.2.html). #[cfg(target_os = "linux")] pub fn rm_watch(self, wd: WatchDescriptor) -> Result<()> { let res = unsafe { libc::inotify_rm_watch(self.fd, wd.wd) }; @@ -167,8 +167,8 @@ impl Inotify { /// Reads a collection of events from the inotify file descriptor. This call /// can either be blocking or non blocking depending on whether IN_NONBLOCK - /// was set at initialization. - /// + /// was set at initialization. + /// /// Returns as many events as available. If the call was non blocking and no /// events could be read then the EAGAIN error is returned. pub fn read_events(self) -> Result<Vec<InotifyEvent>> { @@ -194,14 +194,14 @@ impl Inotify { let name = match event.len { 0 => None, _ => { - let ptr = unsafe { + let ptr = unsafe { buffer .as_ptr() .add(offset + header_size) as *const c_char }; let cstr = unsafe { CStr::from_ptr(ptr) }; - + Some(OsStr::from_bytes(cstr.to_bytes()).to_owned()) } }; diff --git a/src/sys/ioctl/bsd.rs b/src/sys/ioctl/bsd.rs index 4ce4d33..f39c0eb 100644 --- a/src/sys/ioctl/bsd.rs +++ b/src/sys/ioctl/bsd.rs @@ -1,12 +1,6 @@ /// The datatype used for the ioctl number #[doc(hidden)] -#[cfg(not(target_os = "illumos"))] pub type ioctl_num_type = ::libc::c_ulong; - -#[doc(hidden)] -#[cfg(target_os = "illumos")] -pub type ioctl_num_type = ::libc::c_int; - /// The datatype used for the 3rd argument #[doc(hidden)] pub type ioctl_param_type = ::libc::c_int; @@ -18,7 +12,6 @@ mod consts { #[doc(hidden)] pub const OUT: ioctl_num_type = 0x4000_0000; #[doc(hidden)] - #[allow(overflowing_literals)] pub const IN: ioctl_num_type = 0x8000_0000; #[doc(hidden)] pub const INOUT: ioctl_num_type = IN|OUT; diff --git a/src/sys/ioctl/mod.rs b/src/sys/ioctl/mod.rs index 203b7d0..8858a9d 100644 --- a/src/sys/ioctl/mod.rs +++ b/src/sys/ioctl/mod.rs @@ -104,7 +104,7 @@ //! respectively. To determine the specific `write_` variant to use you'll need to find //! what the argument type is supposed to be. If it's an `int`, then `write_int` should be used, //! otherwise it should be a pointer and `write_ptr` should be used. On Linux the -//! [`ioctl_list` man page](https://man7.org/linux/man-pages/man2/ioctl_list.2.html) describes a +//! [`ioctl_list` man page](http://man7.org/linux/man-pages/man2/ioctl_list.2.html) describes a //! large number of `ioctl`s and describes their argument data type. //! //! Using "bad" `ioctl`s @@ -232,7 +232,6 @@ pub use self::linux::*; #[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "illumos", target_os = "ios", target_os = "macos", target_os = "netbsd", @@ -242,7 +241,6 @@ mod bsd; #[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "illumos", target_os = "ios", target_os = "macos", target_os = "netbsd", diff --git a/src/sys/memfd.rs b/src/sys/memfd.rs index 642676b..51b7e6b 100644 --- a/src/sys/memfd.rs +++ b/src/sys/memfd.rs @@ -1,43 +1,16 @@ -//! Interfaces for managing memory-backed files. - +use libc; use std::os::unix::io::RawFd; use crate::Result; use crate::errno::Errno; use std::ffi::CStr; libc_bitflags!( - /// Options that change the behavior of [`memfd_create`]. pub struct MemFdCreateFlag: libc::c_uint { - /// Set the close-on-exec ([`FD_CLOEXEC`]) flag on the new file descriptor. - /// - /// By default, the new file descriptor is set to remain open across an [`execve`] - /// (the `FD_CLOEXEC` flag is initially disabled). This flag can be used to change - /// this default. The file offset is set to the beginning of the file (see [`lseek`]). - /// - /// See also the description of the `O_CLOEXEC` flag in [`open(2)`]. - /// - /// [`execve`]: crate::unistd::execve - /// [`lseek`]: crate::unistd::lseek - /// [`FD_CLOEXEC`]: crate::fcntl::FdFlag::FD_CLOEXEC - /// [`open(2)`]: https://man7.org/linux/man-pages/man2/open.2.html MFD_CLOEXEC; - /// Allow sealing operations on this file. - /// - /// See also the file sealing notes given in [`memfd_create(2)`]. - /// - /// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html MFD_ALLOW_SEALING; } ); -/// Creates an anonymous file that lives in memory, and return a file-descriptor to it. -/// -/// The file behaves like a regular file, and so can be modified, truncated, memory-mapped, and so on. -/// However, unlike a regular file, it lives in RAM and has a volatile backing storage. -/// -/// For more information, see [`memfd_create(2)`]. -/// -/// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html pub fn memfd_create(name: &CStr, flags: MemFdCreateFlag) -> Result<RawFd> { let res = unsafe { libc::syscall(libc::SYS_memfd_create, name.as_ptr(), flags.bits()) diff --git a/src/sys/mman.rs b/src/sys/mman.rs index 0ef1ca8..63a0779 100644 --- a/src/sys/mman.rs +++ b/src/sys/mman.rs @@ -1,6 +1,4 @@ -//! Memory management declarations. - -use crate::Result; +use crate::{Error, Result}; #[cfg(not(target_os = "android"))] use crate::NixPath; use crate::errno::Errno; @@ -32,7 +30,7 @@ libc_bitflags!{ } libc_bitflags!{ - /// Additional parameters for [`mmap`]. + /// Additional parameters for `mmap()`. pub struct MapFlags: c_int { /// Compatibility flag. Ignored. MAP_FILE; @@ -42,13 +40,10 @@ libc_bitflags!{ MAP_PRIVATE; /// Place the mapping at exactly the address specified in `addr`. MAP_FIXED; - /// To be used with `MAP_FIXED`, to forbid the system - /// to select a different address than the one specified. - #[cfg(target_os = "freebsd")] - MAP_EXCL; /// Synonym for `MAP_ANONYMOUS`. MAP_ANON; /// The mapping is not backed by any file. + #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] MAP_ANONYMOUS; /// Put the mapping into the first 2GB of the process address space. #[cfg(any(all(any(target_os = "android", target_os = "linux"), @@ -70,8 +65,8 @@ libc_bitflags!{ MAP_LOCKED; /// Do not reserve swap space for this mapping. /// - /// This was removed in FreeBSD 11 and is unused in DragonFlyBSD. - #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd")))] + /// This was removed in FreeBSD 11. + #[cfg(not(target_os = "freebsd"))] MAP_NORESERVE; /// Populate page tables for a mapping. #[cfg(any(target_os = "android", target_os = "linux"))] @@ -127,55 +122,39 @@ libc_bitflags!{ MAP_NOSYNC; /// Rename private pages to a file. /// - /// This was removed in FreeBSD 11 and is unused in DragonFlyBSD. - #[cfg(any(target_os = "netbsd", target_os = "openbsd"))] + /// This was removed in FreeBSD 11. + #[cfg(any(target_os = "dragonfly", target_os = "netbsd", target_os = "openbsd"))] MAP_RENAME; /// Region may contain semaphores. #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] MAP_HASSEMAPHORE; /// Region grows down, like a stack. - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux", target_os = "openbsd"))] + #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))] MAP_STACK; /// Pages in this mapping are not retained in the kernel's memory cache. #[cfg(any(target_os = "ios", target_os = "macos"))] MAP_NOCACHE; - /// Allows the W/X bit on the page, it's necessary on aarch64 architecture. #[cfg(any(target_os = "ios", target_os = "macos"))] MAP_JIT; - /// Allows to use large pages, underlying alignment based on size. - #[cfg(target_os = "freebsd")] - MAP_ALIGNED_SUPER; - /// Pages will be discarded in the core dumps. - #[cfg(target_os = "openbsd")] - MAP_CONCEAL; } } -#[cfg(any(target_os = "linux", target_os = "netbsd"))] +#[cfg(target_os = "linux")] libc_bitflags!{ - /// Options for [`mremap`]. + /// Options for `mremap()`. pub struct MRemapFlags: c_int { /// Permit the kernel to relocate the mapping to a new virtual address, if necessary. - #[cfg(target_os = "linux")] MREMAP_MAYMOVE; /// Place the mapping at exactly the address specified in `new_address`. - #[cfg(target_os = "linux")] MREMAP_FIXED; - /// Permits to use the old and new address as hints to relocate the mapping. - #[cfg(target_os = "netbsd")] - MAP_FIXED; - /// Allows to duplicate the mapping to be able to apply different flags on the copy. - #[cfg(target_os = "netbsd")] - MAP_REMAPDUP; } } libc_enum!{ /// Usage information for a range of memory to allow for performance optimizations by the kernel. /// - /// Used by [`madvise`]. + /// Used by [`madvise`](./fn.madvise.html). #[repr(i32)] - #[non_exhaustive] pub enum MmapAdvise { /// No further special treatment. This is the default. MADV_NORMAL, @@ -212,8 +191,7 @@ libc_enum!{ all(target_os = "linux", any( target_arch = "aarch64", target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", + target_arch = "ppc", target_arch = "s390x", target_arch = "x86", target_arch = "x86_64", @@ -266,7 +244,7 @@ libc_enum!{ } libc_bitflags!{ - /// Configuration flags for [`msync`]. + /// Configuration flags for `msync`. pub struct MsFlags: c_int { /// Schedule an update but return immediately. MS_ASYNC; @@ -284,7 +262,7 @@ libc_bitflags!{ } libc_bitflags!{ - /// Flags for [`mlockall`]. + /// Flags for `mlockall`. pub struct MlockAllFlags: c_int { /// Lock pages that are currently mapped into the address space of the process. MCL_CURRENT; @@ -300,9 +278,7 @@ libc_bitflags!{ /// /// # Safety /// -/// `addr` must meet all the requirements described in the [`mlock(2)`] man page. -/// -/// [`mlock(2)`]: https://man7.org/linux/man-pages/man2/mlock.2.html +/// `addr` must meet all the requirements described in the `mlock(2)` man page. pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> { Errno::result(libc::mlock(addr, length)).map(drop) } @@ -312,28 +288,25 @@ pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> { /// /// # Safety /// -/// `addr` must meet all the requirements described in the [`munlock(2)`] man +/// `addr` must meet all the requirements described in the `munlock(2)` man /// page. -/// -/// [`munlock(2)`]: https://man7.org/linux/man-pages/man2/munlock.2.html pub unsafe fn munlock(addr: *const c_void, length: size_t) -> Result<()> { Errno::result(libc::munlock(addr, length)).map(drop) } /// Locks all memory pages mapped into this process' address space. /// -/// Locked pages never move to the swap area. For more information, see [`mlockall(2)`]. +/// Locked pages never move to the swap area. +/// +/// # Safety /// -/// [`mlockall(2)`]: https://man7.org/linux/man-pages/man2/mlockall.2.html +/// `addr` must meet all the requirements described in the `mlockall(2)` man +/// page. pub fn mlockall(flags: MlockAllFlags) -> Result<()> { unsafe { Errno::result(libc::mlockall(flags.bits())) }.map(drop) } /// Unlocks all memory pages mapped into this process' address space. -/// -/// For more information, see [`munlockall(2)`]. -/// -/// [`munlockall(2)`]: https://man7.org/linux/man-pages/man2/munlockall.2.html pub fn munlockall() -> Result<()> { unsafe { Errno::result(libc::munlockall()) }.map(drop) } @@ -342,14 +315,12 @@ pub fn munlockall() -> Result<()> { /// /// # Safety /// -/// See the [`mmap(2)`] man page for detailed requirements. -/// -/// [`mmap(2)`]: https://man7.org/linux/man-pages/man2/mmap.2.html +/// See the `mmap(2)` man page for detailed requirements. pub unsafe fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: MapFlags, fd: RawFd, offset: off_t) -> Result<*mut c_void> { let ret = libc::mmap(addr, length, prot.bits(), flags.bits(), fd, offset); if ret == libc::MAP_FAILED { - Err(Errno::last()) + Err(Error::Sys(Errno::last())) } else { Ok(ret) } @@ -362,7 +333,7 @@ pub unsafe fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: Ma /// /// See the `mremap(2)` [man page](https://man7.org/linux/man-pages/man2/mremap.2.html) for /// detailed requirements. -#[cfg(any(target_os = "linux", target_os = "netbsd"))] +#[cfg(target_os = "linux")] pub unsafe fn mremap( addr: *mut c_void, old_size: size_t, @@ -370,19 +341,10 @@ pub unsafe fn mremap( flags: MRemapFlags, new_address: Option<* mut c_void>, ) -> Result<*mut c_void> { - #[cfg(target_os = "linux")] let ret = libc::mremap(addr, old_size, new_size, flags.bits(), new_address.unwrap_or(std::ptr::null_mut())); - #[cfg(target_os = "netbsd")] - let ret = libc::mremap( - addr, - old_size, - new_address.unwrap_or(std::ptr::null_mut()), - new_size, - flags.bits(), - ); if ret == libc::MAP_FAILED { - Err(Errno::last()) + Err(Error::Sys(Errno::last())) } else { Ok(ret) } @@ -392,10 +354,8 @@ pub unsafe fn mremap( /// /// # Safety /// -/// `addr` must meet all the requirements described in the [`munmap(2)`] man +/// `addr` must meet all the requirements described in the `munmap(2)` man /// page. -/// -/// [`munmap(2)`]: https://man7.org/linux/man-pages/man2/munmap.2.html pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> { Errno::result(libc::munmap(addr, len)).map(drop) } @@ -404,17 +364,15 @@ pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> { /// /// # Safety /// -/// See the [`madvise(2)`] man page. Take special care when using -/// [`MmapAdvise::MADV_FREE`]. -/// -/// [`madvise(2)`]: https://man7.org/linux/man-pages/man2/madvise.2.html +/// See the `madvise(2)` man page. Take special care when using +/// `MmapAdvise::MADV_FREE`. pub unsafe fn madvise(addr: *mut c_void, length: size_t, advise: MmapAdvise) -> Result<()> { Errno::result(libc::madvise(addr, length, advise as i32)).map(drop) } /// Set protection of memory mapping. /// -/// See [`mprotect(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mprotect.html) for +/// See [`mprotect(3)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mprotect.html) for /// details. /// /// # Safety @@ -445,19 +403,12 @@ pub unsafe fn mprotect(addr: *mut c_void, length: size_t, prot: ProtFlags) -> Re /// /// # Safety /// -/// `addr` must meet all the requirements described in the [`msync(2)`] man +/// `addr` must meet all the requirements described in the `msync(2)` man /// page. -/// -/// [`msync(2)`]: https://man7.org/linux/man-pages/man2/msync.2.html pub unsafe fn msync(addr: *mut c_void, length: size_t, flags: MsFlags) -> Result<()> { Errno::result(libc::msync(addr, length, flags.bits())).map(drop) } -/// Creates and opens a new, or opens an existing, POSIX shared memory object. -/// -/// For more information, see [`shm_open(3)`]. -/// -/// [`shm_open(3)`]: https://man7.org/linux/man-pages/man3/shm_open.3.html #[cfg(not(target_os = "android"))] pub fn shm_open<P: ?Sized + NixPath>(name: &P, flag: OFlag, mode: Mode) -> Result<RawFd> { let ret = name.with_nix_path(|cstr| { @@ -474,11 +425,6 @@ pub fn shm_open<P: ?Sized + NixPath>(name: &P, flag: OFlag, mode: Mode) -> Resul Errno::result(ret) } -/// Performs the converse of [`shm_open`], removing an object previously created. -/// -/// For more information, see [`shm_unlink(3)`]. -/// -/// [`shm_unlink(3)`]: https://man7.org/linux/man-pages/man3/shm_unlink.3.html #[cfg(not(target_os = "android"))] pub fn shm_unlink<P: ?Sized + NixPath>(name: &P) -> Result<()> { let ret = name.with_nix_path(|cstr| { diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 156b0d9..02edfd7 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -1,4 +1,3 @@ -//! Mostly platform-specific functionality #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -8,7 +7,6 @@ pub mod aio; #[cfg(any(target_os = "android", target_os = "linux"))] -#[allow(missing_docs)] pub mod epoll; #[cfg(any(target_os = "dragonfly", @@ -17,11 +15,9 @@ pub mod epoll; target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] -#[allow(missing_docs)] pub mod event; -#[cfg(any(target_os = "android", target_os = "linux"))] -#[allow(missing_docs)] +#[cfg(target_os = "linux")] pub mod eventfd; #[cfg(any(target_os = "android", @@ -32,7 +28,6 @@ pub mod eventfd; target_os = "redox", target_os = "macos", target_os = "netbsd", - target_os = "illumos", target_os = "openbsd"))] #[macro_use] pub mod ioctl; @@ -41,11 +36,9 @@ pub mod ioctl; pub mod memfd; #[cfg(not(target_os = "redox"))] -#[allow(missing_docs)] pub mod mman; #[cfg(target_os = "linux")] -#[allow(missing_docs)] pub mod personality; pub mod pthread; @@ -57,19 +50,14 @@ pub mod pthread; target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] -#[allow(missing_docs)] pub mod ptrace; #[cfg(target_os = "linux")] pub mod quota; #[cfg(any(target_os = "linux"))] -#[allow(missing_docs)] pub mod reboot; -#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "illumos")))] -pub mod resource; - #[cfg(not(target_os = "redox"))] pub mod select; @@ -83,14 +71,11 @@ pub mod sendfile; pub mod signal; #[cfg(any(target_os = "android", target_os = "linux"))] -#[allow(missing_docs)] pub mod signalfd; #[cfg(not(target_os = "redox"))] -#[allow(missing_docs)] pub mod socket; -#[allow(missing_docs)] pub mod stat; #[cfg(any(target_os = "android", @@ -106,13 +91,10 @@ pub mod statfs; pub mod statvfs; #[cfg(any(target_os = "android", target_os = "linux"))] -#[allow(missing_docs)] pub mod sysinfo; -#[allow(missing_docs)] pub mod termios; -#[allow(missing_docs)] pub mod time; pub mod uio; @@ -122,9 +104,7 @@ pub mod utsname; pub mod wait; #[cfg(any(target_os = "android", target_os = "linux"))] -#[allow(missing_docs)] pub mod inotify; #[cfg(any(target_os = "android", target_os = "linux"))] -#[allow(missing_docs)] pub mod timerfd; diff --git a/src/sys/personality.rs b/src/sys/personality.rs index b15956c..6548b65 100644 --- a/src/sys/personality.rs +++ b/src/sys/personality.rs @@ -39,7 +39,7 @@ pub fn get() -> Result<Persona> { libc::personality(0xFFFFFFFF) }; - Errno::result(res).map(Persona::from_bits_truncate) + Errno::result(res).map(|r| Persona::from_bits_truncate(r)) } /// Set the current process personality. @@ -66,5 +66,5 @@ pub fn set(persona: Persona) -> Result<Persona> { libc::personality(persona.bits() as c_ulong) }; - Errno::result(res).map(Persona::from_bits_truncate) + Errno::result(res).map(|r| Persona::from_bits_truncate(r)) } diff --git a/src/sys/pthread.rs b/src/sys/pthread.rs index d42e45d..a4d9825 100644 --- a/src/sys/pthread.rs +++ b/src/sys/pthread.rs @@ -1,18 +1,9 @@ -//! Low level threading primitives - -#[cfg(not(target_os = "redox"))] -use crate::errno::Errno; -#[cfg(not(target_os = "redox"))] -use crate::Result; -#[cfg(not(target_os = "redox"))] -use crate::sys::signal::Signal; use libc::{self, pthread_t}; -/// Identifies an individual thread. pub type Pthread = pthread_t; /// Obtain ID of the calling thread (see -/// [`pthread_self(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_self.html) +/// [`pthread_self(3)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_self.html) /// /// The thread ID returned by `pthread_self()` is not the same thing as /// the kernel thread ID returned by a call to `gettid(2)`. @@ -20,19 +11,3 @@ pub type Pthread = pthread_t; pub fn pthread_self() -> Pthread { unsafe { libc::pthread_self() } } - -/// Send a signal to a thread (see [`pthread_kill(3)`]). -/// -/// If `signal` is `None`, `pthread_kill` will only preform error checking and -/// won't send any signal. -/// -/// [`pthread_kill(3)`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_kill.html -#[cfg(not(target_os = "redox"))] -pub fn pthread_kill<T: Into<Option<Signal>>>(thread: Pthread, signal: T) -> Result<()> { - let sig = match signal.into() { - Some(s) => s as libc::c_int, - None => 0, - }; - let res = unsafe { libc::pthread_kill(thread, sig) }; - Errno::result(res).map(drop) -} diff --git a/src/sys/ptrace/bsd.rs b/src/sys/ptrace/bsd.rs index a62881e..e85afc7 100644 --- a/src/sys/ptrace/bsd.rs +++ b/src/sys/ptrace/bsd.rs @@ -24,7 +24,6 @@ cfg_if! { libc_enum! { #[repr(i32)] /// Ptrace Request enum defining the action to be taken. - #[non_exhaustive] pub enum Request { PT_TRACE_ME, PT_READ_I, @@ -134,14 +133,16 @@ pub fn kill(pid: Pid) -> Result<()> { /// use nix::unistd::Pid; /// use nix::sys::signal::Signal; /// use nix::sys::wait::*; -/// // If a process changes state to the stopped state because of a SIGUSR1 -/// // signal, this will step the process forward and forward the user -/// // signal to the stopped process -/// match waitpid(Pid::from_raw(-1), None) { -/// Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => { -/// let _ = step(pid, Signal::SIGUSR1); +/// fn main() { +/// // If a process changes state to the stopped state because of a SIGUSR1 +/// // signal, this will step the process forward and forward the user +/// // signal to the stopped process +/// match waitpid(Pid::from_raw(-1), None) { +/// Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => { +/// let _ = step(pid, Signal::SIGUSR1); +/// } +/// _ => {}, /// } -/// _ => {}, /// } /// ``` #[cfg( diff --git a/src/sys/ptrace/linux.rs b/src/sys/ptrace/linux.rs index 3723679..8d1dd16 100644 --- a/src/sys/ptrace/linux.rs +++ b/src/sys/ptrace/linux.rs @@ -2,7 +2,7 @@ use cfg_if::cfg_if; use std::{mem, ptr}; -use crate::Result; +use crate::{Error, Result}; use crate::errno::Errno; use libc::{self, c_void, c_long, siginfo_t}; use crate::unistd::Pid; @@ -33,7 +33,6 @@ libc_enum!{ #[cfg_attr(not(any(target_env = "musl", target_os = "android")), repr(u32))] #[cfg_attr(any(target_env = "musl", target_os = "android"), repr(i32))] /// Ptrace Request enum defining the action to be taken. - #[non_exhaustive] pub enum Request { PTRACE_TRACEME, PTRACE_PEEKTEXT, @@ -98,9 +97,11 @@ libc_enum!{ #[cfg(all(target_os = "linux", not(any(target_arch = "mips", target_arch = "mips64"))))] PTRACE_SETREGSET, - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(any(target_arch = "mips", + target_arch = "mips64"))))] PTRACE_SEIZE, - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(any(target_arch = "mips", + target_arch = "mips64"))))] PTRACE_INTERRUPT, #[cfg(all(target_os = "linux", not(any(target_arch = "mips", target_arch = "mips64"))))] @@ -122,7 +123,6 @@ libc_enum!{ /// Using the ptrace options the tracer can configure the tracee to stop /// at certain events. This enum is used to define those events as defined /// in `man ptrace`. - #[non_exhaustive] pub enum Event { /// Event that stops before a return from fork or clone. PTRACE_EVENT_FORK, @@ -137,11 +137,9 @@ libc_enum!{ /// Event for a stop before an exit. Unlike the waitpid Exit status program. /// registers can still be examined PTRACE_EVENT_EXIT, - /// Stop triggered by a seccomp rule on a tracee. + /// STop triggered by a seccomp rule on a tracee. PTRACE_EVENT_SECCOMP, - /// Stop triggered by the `INTERRUPT` syscall, or a group stop, - /// or when a new child is attached. - PTRACE_EVENT_STOP, + // PTRACE_EVENT_STOP not provided by libc because it's defined in glibc 2.26 } } @@ -182,7 +180,7 @@ fn ptrace_peek(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data) }; match Errno::result(ret) { - Ok(..) | Err(Errno::UnknownErrno) => Ok(ret), + Ok(..) | Err(Error::Sys(Errno::UnknownErrno)) => Ok(ret), err @ Err(..) => err, } } @@ -339,7 +337,7 @@ pub fn attach(pid: Pid) -> Result<()> { /// Attach to a running process, as with `ptrace(PTRACE_SEIZE, ...)` /// /// Attaches to the process specified in pid, making it a tracee of the calling process. -#[cfg(target_os = "linux")] +#[cfg(all(target_os = "linux", not(any(target_arch = "mips", target_arch = "mips64"))))] pub fn seize(pid: Pid, options: Options) -> Result<()> { unsafe { ptrace_other( @@ -384,16 +382,6 @@ pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { } } -/// Stop a tracee, as with `ptrace(PTRACE_INTERRUPT, ...)` -/// -/// This request is equivalent to `ptrace(PTRACE_INTERRUPT, ...)` -#[cfg(target_os = "linux")] -pub fn interrupt(pid: Pid) -> Result<()> { - unsafe { - ptrace_other(Request::PTRACE_INTERRUPT, pid, ptr::null_mut(), ptr::null_mut()).map(drop) - } -} - /// Issues a kill request as with `ptrace(PTRACE_KILL, ...)` /// /// This request is equivalent to `ptrace(PTRACE_CONT, ..., SIGKILL);` @@ -403,7 +391,7 @@ pub fn kill(pid: Pid) -> Result<()> { } } -/// Move the stopped tracee process forward by a single step as with +/// Move the stopped tracee process forward by a single step as with /// `ptrace(PTRACE_SINGLESTEP, ...)` /// /// Advances the execution of the process with PID `pid` by a single step optionally delivering a @@ -413,17 +401,18 @@ pub fn kill(pid: Pid) -> Result<()> { /// ```rust /// use nix::sys::ptrace::step; /// use nix::unistd::Pid; -/// use nix::sys::signal::Signal; +/// use nix::sys::signal::Signal; /// use nix::sys::wait::*; -/// -/// // If a process changes state to the stopped state because of a SIGUSR1 -/// // signal, this will step the process forward and forward the user -/// // signal to the stopped process -/// match waitpid(Pid::from_raw(-1), None) { -/// Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => { -/// let _ = step(pid, Signal::SIGUSR1); +/// fn main() { +/// // If a process changes state to the stopped state because of a SIGUSR1 +/// // signal, this will step the process forward and forward the user +/// // signal to the stopped process +/// match waitpid(Pid::from_raw(-1), None) { +/// Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => { +/// let _ = step(pid, Signal::SIGUSR1); +/// } +/// _ => {}, /// } -/// _ => {}, /// } /// ``` pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { diff --git a/src/sys/quota.rs b/src/sys/quota.rs index 6e34e38..1933013 100644 --- a/src/sys/quota.rs +++ b/src/sys/quota.rs @@ -42,7 +42,6 @@ libc_enum!{ libc_enum!{ /// The scope of the quota. #[repr(i32)] - #[non_exhaustive] pub enum QuotaType { /// Specify a user quota USRQUOTA, @@ -54,7 +53,6 @@ libc_enum!{ libc_enum!{ /// The type of quota format to use. #[repr(i32)] - #[non_exhaustive] pub enum QuotaFmt { /// Use the original quota format. QFMT_VFS_OLD, diff --git a/src/sys/reboot.rs b/src/sys/reboot.rs index 46ab68b..e319130 100644 --- a/src/sys/reboot.rs +++ b/src/sys/reboot.rs @@ -1,7 +1,8 @@ //! Reboot/shutdown or enable/disable Ctrl-Alt-Delete. -use crate::Result; +use crate::{Error, Result}; use crate::errno::Errno; +use libc; use std::convert::Infallible; use std::mem::drop; @@ -11,7 +12,6 @@ libc_enum! { /// See [`set_cad_enabled()`](fn.set_cad_enabled.html) for /// enabling/disabling Ctrl-Alt-Delete. #[repr(i32)] - #[non_exhaustive] pub enum RebootMode { RB_HALT_SYSTEM, RB_KEXEC, @@ -26,7 +26,7 @@ pub fn reboot(how: RebootMode) -> Result<Infallible> { unsafe { libc::reboot(how as libc::c_int) }; - Err(Errno::last()) + Err(Error::Sys(Errno::last())) } /// Enable or disable the reboot keystroke (Ctrl-Alt-Delete). diff --git a/src/sys/resource.rs b/src/sys/resource.rs deleted file mode 100644 index f3bfb67..0000000 --- a/src/sys/resource.rs +++ /dev/null @@ -1,233 +0,0 @@ -//! Configure the process resource limits. -use cfg_if::cfg_if; - -use crate::errno::Errno; -use crate::Result; -pub use libc::rlim_t; -use std::mem; - -cfg_if! { - if #[cfg(all(target_os = "linux", target_env = "gnu"))]{ - use libc::{__rlimit_resource_t, rlimit, RLIM_INFINITY}; - }else if #[cfg(any( - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "macos", - target_os = "ios", - target_os = "android", - target_os = "dragonfly", - all(target_os = "linux", not(target_env = "gnu")) - ))]{ - use libc::{c_int, rlimit, RLIM_INFINITY}; - } -} - -libc_enum! { - /// The Resource enum is platform dependent. Check different platform - /// manuals for more details. Some platform links has been provided for - /// earier reference (non-exhaustive). - /// - /// * [Linux](https://man7.org/linux/man-pages/man2/getrlimit.2.html) - /// * [FreeBSD](https://www.freebsd.org/cgi/man.cgi?query=setrlimit) - - // linux-gnu uses u_int as resource enum, which is implemented in libc as - // well. - // - // https://gcc.gnu.org/legacy-ml/gcc/2015-08/msg00441.html - // https://github.com/rust-lang/libc/blob/master/src/unix/linux_like/linux/gnu/mod.rs - #[cfg_attr(all(target_os = "linux", target_env = "gnu"), repr(u32))] - #[cfg_attr(any( - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "macos", - target_os = "ios", - target_os = "android", - target_os = "dragonfly", - all(target_os = "linux", not(target_env = "gnu")) - ), repr(i32))] - #[non_exhaustive] - pub enum Resource { - #[cfg(not(any( - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd" - )))] - /// The maximum amount (in bytes) of virtual memory the process is - /// allowed to map. - RLIMIT_AS, - /// The largest size (in bytes) core(5) file that may be created. - RLIMIT_CORE, - /// The maximum amount of cpu time (in seconds) to be used by each - /// process. - RLIMIT_CPU, - /// The maximum size (in bytes) of the data segment for a process - RLIMIT_DATA, - /// The largest size (in bytes) file that may be created. - RLIMIT_FSIZE, - /// The maximum number of open files for this process. - RLIMIT_NOFILE, - /// The maximum size (in bytes) of the stack segment for a process. - RLIMIT_STACK, - - #[cfg(target_os = "freebsd")] - /// The maximum number of kqueues this user id is allowed to create. - RLIMIT_KQUEUES, - - #[cfg(any(target_os = "android", target_os = "linux"))] - /// A limit on the combined number of flock locks and fcntl leases that - /// this process may establish. - RLIMIT_LOCKS, - - #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "openbsd", target_os = "linux"))] - /// The maximum size (in bytes) which a process may lock into memory - /// using the mlock(2) system call. - RLIMIT_MEMLOCK, - - #[cfg(any(target_os = "android", target_os = "linux"))] - /// A limit on the number of bytes that can be allocated for POSIX - /// message queues for the real user ID of the calling process. - RLIMIT_MSGQUEUE, - - #[cfg(any(target_os = "android", target_os = "linux"))] - /// A ceiling to which the process's nice value can be raised using - /// setpriority or nice. - RLIMIT_NICE, - - #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "openbsd", target_os = "linux"))] - /// The maximum number of simultaneous processes for this user id. - RLIMIT_NPROC, - - #[cfg(target_os = "freebsd")] - /// The maximum number of pseudo-terminals this user id is allowed to - /// create. - RLIMIT_NPTS, - - #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "openbsd", target_os = "linux"))] - /// When there is memory pressure and swap is available, prioritize - /// eviction of a process' resident pages beyond this amount (in bytes). - RLIMIT_RSS, - - #[cfg(any(target_os = "android", target_os = "linux"))] - /// A ceiling on the real-time priority that may be set for this process - /// using sched_setscheduler and sched_set‐ param. - RLIMIT_RTPRIO, - - #[cfg(any(target_os = "linux"))] - /// A limit (in microseconds) on the amount of CPU time that a process - /// scheduled under a real-time scheduling policy may con‐ sume without - /// making a blocking system call. - RLIMIT_RTTIME, - - #[cfg(any(target_os = "android", target_os = "linux"))] - /// A limit on the number of signals that may be queued for the real - /// user ID of the calling process. - RLIMIT_SIGPENDING, - - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - /// The maximum size (in bytes) of socket buffer usage for this user. - RLIMIT_SBSIZE, - - #[cfg(target_os = "freebsd")] - /// The maximum size (in bytes) of the swap space that may be reserved - /// or used by all of this user id's processes. - RLIMIT_SWAP, - - #[cfg(target_os = "freebsd")] - /// An alias for RLIMIT_AS. - RLIMIT_VMEM, - } -} - -/// Get the current processes resource limits -/// -/// A value of `None` indicates the value equals to `RLIM_INFINITY` which means -/// there is no limit. -/// -/// # Parameters -/// -/// * `resource`: The [`Resource`] that we want to get the limits of. -/// -/// # Examples -/// -/// ``` -/// # use nix::sys::resource::{getrlimit, Resource}; -/// -/// let (soft_limit, hard_limit) = getrlimit(Resource::RLIMIT_NOFILE).unwrap(); -/// println!("current soft_limit: {:?}", soft_limit); -/// println!("current hard_limit: {:?}", hard_limit); -/// ``` -/// -/// # References -/// -/// [getrlimit(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html#tag_16_215) -/// -/// [`Resource`]: enum.Resource.html -pub fn getrlimit(resource: Resource) -> Result<(Option<rlim_t>, Option<rlim_t>)> { - let mut old_rlim = mem::MaybeUninit::<rlimit>::uninit(); - - cfg_if! { - if #[cfg(all(target_os = "linux", target_env = "gnu"))]{ - let res = unsafe { libc::getrlimit(resource as __rlimit_resource_t, old_rlim.as_mut_ptr()) }; - }else{ - let res = unsafe { libc::getrlimit(resource as c_int, old_rlim.as_mut_ptr()) }; - } - } - - Errno::result(res).map(|_| { - let rlimit { rlim_cur, rlim_max } = unsafe { old_rlim.assume_init() }; - (Some(rlim_cur), Some(rlim_max)) - }) -} - -/// Set the current processes resource limits -/// -/// # Parameters -/// -/// * `resource`: The [`Resource`] that we want to set the limits of. -/// * `soft_limit`: The value that the kernel enforces for the corresponding -/// resource. Note: `None` input will be replaced by constant `RLIM_INFINITY`. -/// * `hard_limit`: The ceiling for the soft limit. Must be lower or equal to -/// the current hard limit for non-root users. Note: `None` input will be -/// replaced by constant `RLIM_INFINITY`. -/// -/// > Note: for some os (linux_gnu), setting hard_limit to `RLIM_INFINITY` can -/// > results `EPERM` Error. So you will need to set the number explicitly. -/// -/// # Examples -/// -/// ``` -/// # use nix::sys::resource::{setrlimit, Resource}; -/// -/// let soft_limit = Some(512); -/// let hard_limit = Some(1024); -/// setrlimit(Resource::RLIMIT_NOFILE, soft_limit, hard_limit).unwrap(); -/// ``` -/// -/// # References -/// -/// [setrlimit(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html#tag_16_215) -/// -/// [`Resource`]: enum.Resource.html -/// -/// Note: `setrlimit` provides a safe wrapper to libc's `setrlimit`. -pub fn setrlimit( - resource: Resource, - soft_limit: Option<rlim_t>, - hard_limit: Option<rlim_t>, -) -> Result<()> { - let new_rlim = rlimit { - rlim_cur: soft_limit.unwrap_or(RLIM_INFINITY), - rlim_max: hard_limit.unwrap_or(RLIM_INFINITY), - }; - cfg_if! { - if #[cfg(all(target_os = "linux", target_env = "gnu"))]{ - let res = unsafe { libc::setrlimit(resource as __rlimit_resource_t, &new_rlim as *const rlimit) }; - }else{ - let res = unsafe { libc::setrlimit(resource as c_int, &new_rlim as *const rlimit) }; - } - } - - Errno::result(res).map(drop) -} diff --git a/src/sys/select.rs b/src/sys/select.rs index 4d7576a..a576c7e 100644 --- a/src/sys/select.rs +++ b/src/sys/select.rs @@ -1,5 +1,3 @@ -//! Portably monitor a group of file descriptors for readiness. -use std::convert::TryFrom; use std::iter::FusedIterator; use std::mem; use std::ops::Range; @@ -13,20 +11,11 @@ use crate::sys::time::{TimeSpec, TimeVal}; pub use libc::FD_SETSIZE; -/// Contains a set of file descriptors used by [`select`] #[repr(transparent)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct FdSet(libc::fd_set); -fn assert_fd_valid(fd: RawFd) { - assert!( - usize::try_from(fd).map_or(false, |fd| fd < FD_SETSIZE), - "fd must be in the range 0..FD_SETSIZE", - ); -} - impl FdSet { - /// Create an empty `FdSet` pub fn new() -> FdSet { let mut fdset = mem::MaybeUninit::uninit(); unsafe { @@ -35,25 +24,18 @@ impl FdSet { } } - /// Add a file descriptor to an `FdSet` pub fn insert(&mut self, fd: RawFd) { - assert_fd_valid(fd); unsafe { libc::FD_SET(fd, &mut self.0) }; } - /// Remove a file descriptor from an `FdSet` pub fn remove(&mut self, fd: RawFd) { - assert_fd_valid(fd); unsafe { libc::FD_CLR(fd, &mut self.0) }; } - /// Test an `FdSet` for the presence of a certain file descriptor. - pub fn contains(&self, fd: RawFd) -> bool { - assert_fd_valid(fd); - unsafe { libc::FD_ISSET(fd, &self.0) } + pub fn contains(&mut self, fd: RawFd) -> bool { + unsafe { libc::FD_ISSET(fd, &mut self.0) } } - /// Remove all file descriptors from this `FdSet`. pub fn clear(&mut self) { unsafe { libc::FD_ZERO(&mut self.0) }; } @@ -68,19 +50,21 @@ impl FdSet { /// /// ``` /// # use nix::sys::select::FdSet; + /// # fn main() { /// let mut set = FdSet::new(); /// set.insert(4); /// set.insert(9); /// assert_eq!(set.highest(), Some(9)); + /// # } /// ``` /// /// [`select`]: fn.select.html - pub fn highest(&self) -> Option<RawFd> { + pub fn highest(&mut self) -> Option<RawFd> { self.fds(None).next_back() } /// Returns an iterator over the file descriptors in the set. - /// + /// /// For performance, it takes an optional higher bound: the iterator will /// not return any elements of the set greater than the given file /// descriptor. @@ -97,7 +81,7 @@ impl FdSet { /// assert_eq!(fds, vec![4, 9]); /// ``` #[inline] - pub fn fds(&self, highest: Option<RawFd>) -> Fds { + pub fn fds(&mut self, highest: Option<RawFd>) -> Fds { Fds { set: self, range: 0..highest.map(|h| h as usize + 1).unwrap_or(FD_SETSIZE), @@ -114,7 +98,7 @@ impl Default for FdSet { /// Iterator over `FdSet`. #[derive(Debug)] pub struct Fds<'a> { - set: &'a FdSet, + set: &'a mut FdSet, range: Range<usize>, } @@ -122,7 +106,7 @@ impl<'a> Iterator for Fds<'a> { type Item = RawFd; fn next(&mut self) -> Option<RawFd> { - for i in &mut self.range { + while let Some(i) = self.range.next() { if self.set.contains(i as RawFd) { return Some(i as RawFd); } @@ -171,7 +155,7 @@ impl<'a> FusedIterator for Fds<'a> {} /// /// # References /// -/// [select(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html) +/// [select(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html) /// /// [`FdSet::highest`]: struct.FdSet.html#method.highest pub fn select<'a, N, R, W, E, T>(nfds: N, @@ -237,7 +221,7 @@ where /// /// # References /// -/// [pselect(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pselect.html) +/// [pselect(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pselect.html) /// /// [The new pselect() system call](https://lwn.net/Articles/176911/) /// diff --git a/src/sys/sendfile.rs b/src/sys/sendfile.rs index 7a210c6..84fe2a9 100644 --- a/src/sys/sendfile.rs +++ b/src/sys/sendfile.rs @@ -1,5 +1,3 @@ -//! Send data from a file to a socket, bypassing userland. - use cfg_if::cfg_if; use std::os::unix::io::RawFd; use std::ptr; @@ -20,7 +18,7 @@ use crate::errno::Errno; /// /// `in_fd` must support `mmap`-like operations and therefore cannot be a socket. /// -/// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html) +/// For more information, see [the sendfile(2) man page.](http://man7.org/linux/man-pages/man2/sendfile.2.html) #[cfg(any(target_os = "android", target_os = "linux"))] pub fn sendfile( out_fd: RawFd, @@ -35,32 +33,6 @@ pub fn sendfile( Errno::result(ret).map(|r| r as usize) } -/// Copy up to `count` bytes to `out_fd` from `in_fd` starting at `offset`. -/// -/// Returns a `Result` with the number of bytes written. -/// -/// If `offset` is `None`, `sendfile` will begin reading at the current offset of `in_fd`and will -/// update the offset of `in_fd`. If `offset` is `Some`, `sendfile` will begin at the specified -/// offset and will not update the offset of `in_fd`. Instead, it will mutate `offset` to point to -/// the byte after the last byte copied. -/// -/// `in_fd` must support `mmap`-like operations and therefore cannot be a socket. -/// -/// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html) -#[cfg(target_os = "linux")] -pub fn sendfile64( - out_fd: RawFd, - in_fd: RawFd, - offset: Option<&mut libc::off64_t>, - count: usize, -) -> Result<usize> { - let offset = offset - .map(|offset| offset as *mut _) - .unwrap_or(ptr::null_mut()); - let ret = unsafe { libc::sendfile64(out_fd, in_fd, offset, count) }; - Errno::result(ret).map(|r| r as usize) -} - cfg_if! { if #[cfg(any(target_os = "freebsd", target_os = "ios", diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 61bdc74..2f8b5fa 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -1,11 +1,12 @@ // Portions of this file are Copyright 2014 The Rust Project Developers. -// See https://www.rust-lang.org/policies/licenses. +// See http://rust-lang.org/COPYRIGHT. -//! Operating system signals. +///! Operating system signals. use crate::{Error, Result}; use crate::errno::Errno; use crate::unistd::Pid; +use std::convert::TryFrom; use std::mem; use std::fmt; use std::str::FromStr; @@ -17,94 +18,58 @@ use std::ptr; pub use self::sigevent::*; libc_enum!{ - /// Types of operating system signals // Currently there is only one definition of c_int in libc, as well as only one // type for signal constants. // We would prefer to use the libc::c_int alias in the repr attribute. Unfortunately // this is not (yet) possible. #[repr(i32)] - #[non_exhaustive] pub enum Signal { - /// Hangup SIGHUP, - /// Interrupt SIGINT, - /// Quit SIGQUIT, - /// Illegal instruction (not reset when caught) SIGILL, - /// Trace trap (not reset when caught) SIGTRAP, - /// Abort SIGABRT, - /// Bus error SIGBUS, - /// Floating point exception SIGFPE, - /// Kill (cannot be caught or ignored) SIGKILL, - /// User defined signal 1 SIGUSR1, - /// Segmentation violation SIGSEGV, - /// User defined signal 2 SIGUSR2, - /// Write on a pipe with no one to read it SIGPIPE, - /// Alarm clock SIGALRM, - /// Software termination signal from kill SIGTERM, - /// Stack fault (obsolete) #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux"), not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))] SIGSTKFLT, - /// To parent on child stop or exit SIGCHLD, - /// Continue a stopped process SIGCONT, - /// Sendable stop signal not from tty SIGSTOP, - /// Stop signal from tty SIGTSTP, - /// To readers pgrp upon background tty read SIGTTIN, - /// Like TTIN if (tp->t_local<OSTOP) SIGTTOU, - /// Urgent condition on IO channel SIGURG, - /// Exceeded CPU time limit SIGXCPU, - /// Exceeded file size limit SIGXFSZ, - /// Virtual time alarm SIGVTALRM, - /// Profiling time alarm SIGPROF, - /// Window size changes SIGWINCH, - /// Input/output possible signal SIGIO, #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux"))] - /// Power failure imminent. SIGPWR, - /// Bad system call SIGSYS, #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux", target_os = "redox")))] - /// Emulator trap SIGEMT, #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux", target_os = "redox")))] - /// Information request SIGINFO, } - impl TryFrom<i32> } impl FromStr for Signal { @@ -156,7 +121,7 @@ impl FromStr for Signal { target_os = "fuchsia", target_os = "linux", target_os = "redox")))] "SIGINFO" => Signal::SIGINFO, - _ => return Err(Errno::EINVAL), + _ => return Err(Error::invalid_argument()), }) } } @@ -167,7 +132,7 @@ impl Signal { /// This function is equivalent to `<Signal as AsRef<str>>::as_ref()`, /// with difference that returned string is `'static` /// and not bound to `self`'s lifetime. - pub const fn as_str(self) -> &'static str { + pub fn as_str(self) -> &'static str { match self { Signal::SIGHUP => "SIGHUP", Signal::SIGINT => "SIGINT", @@ -369,8 +334,9 @@ const SIGNALS: [Signal; 31] = [ SIGEMT, SIGINFO]; +pub const NSIG: libc::c_int = 32; + #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -/// Iterate through all signals defined by this operating system pub struct SignalIterator { next: usize, } @@ -390,17 +356,25 @@ impl Iterator for SignalIterator { } impl Signal { - /// Iterate through all signals defined by this OS - pub const fn iterator() -> SignalIterator { + pub fn iterator() -> SignalIterator { SignalIterator{next: 0} } } -/// Alias for [`SIGABRT`] +impl TryFrom<libc::c_int> for Signal { + type Error = Error; + + fn try_from(signum: libc::c_int) -> Result<Signal> { + if 0 < signum && signum < NSIG { + Ok(unsafe { mem::transmute(signum) }) + } else { + Err(Error::invalid_argument()) + } + } +} + pub const SIGIOT : Signal = SIGABRT; -/// Alias for [`SIGIO`] pub const SIGPOLL : Signal = SIGIO; -/// Alias for [`SIGSYS`] pub const SIGUNUSED : Signal = SIGSYS; #[cfg(not(target_os = "redox"))] @@ -409,48 +383,26 @@ type SaFlags_t = libc::c_int; type SaFlags_t = libc::c_ulong; libc_bitflags!{ - /// Controls the behavior of a [`SigAction`] pub struct SaFlags: SaFlags_t { - /// When catching a [`Signal::SIGCHLD`] signal, the signal will be - /// generated only when a child process exits, not when a child process - /// stops. SA_NOCLDSTOP; - /// When catching a [`Signal::SIGCHLD`] signal, the system will not - /// create zombie processes when children of the calling process exit. SA_NOCLDWAIT; - /// Further occurrences of the delivered signal are not masked during - /// the execution of the handler. SA_NODEFER; - /// The system will deliver the signal to the process on a signal stack, - /// specified by each thread with sigaltstack(2). SA_ONSTACK; - /// The handler is reset back to the default at the moment the signal is - /// delivered. SA_RESETHAND; - /// Requests that certain system calls restart if interrupted by this - /// signal. See the man page for complete details. SA_RESTART; - /// This flag is controlled internally by Nix. SA_SIGINFO; } } libc_enum! { - /// Specifies how certain functions should manipulate a signal mask #[repr(i32)] - #[non_exhaustive] pub enum SigmaskHow { - /// The new mask is the union of the current mask and the specified set. SIG_BLOCK, - /// The new mask is the intersection of the current mask and the - /// complement of the specified set. SIG_UNBLOCK, - /// The current mask is replaced by the specified set. SIG_SETMASK, } } -/// Specifies a set of [`Signal`]s that may be blocked, waited for, etc. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct SigSet { sigset: libc::sigset_t @@ -458,7 +410,6 @@ pub struct SigSet { impl SigSet { - /// Initialize to include all signals. pub fn all() -> SigSet { let mut sigset = mem::MaybeUninit::uninit(); let _ = unsafe { libc::sigfillset(sigset.as_mut_ptr()) }; @@ -466,7 +417,6 @@ impl SigSet { unsafe{ SigSet { sigset: sigset.assume_init() } } } - /// Initialize to include nothing. pub fn empty() -> SigSet { let mut sigset = mem::MaybeUninit::uninit(); let _ = unsafe { libc::sigemptyset(sigset.as_mut_ptr()) }; @@ -474,22 +424,18 @@ impl SigSet { unsafe{ SigSet { sigset: sigset.assume_init() } } } - /// Add the specified signal to the set. pub fn add(&mut self, signal: Signal) { unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) }; } - /// Remove all signals from this set. pub fn clear(&mut self) { unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) }; } - /// Remove the specified signal from this set. pub fn remove(&mut self, signal: Signal) { unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) }; } - /// Return whether this set includes the specified signal. pub fn contains(&self, signal: Signal) -> bool { let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) }; @@ -500,8 +446,6 @@ impl SigSet { } } - /// Merge all of `other`'s signals into this set. - // TODO: use libc::sigorset on supported operating systems. pub fn extend(&mut self, other: &SigSet) { for signal in Signal::iterator() { if other.contains(signal) { @@ -543,8 +487,6 @@ impl SigSet { /// signal mask becomes pending, and returns the accepted signal. #[cfg(not(target_os = "redox"))] // RedoxFS does not yet support sigwait pub fn wait(&self) -> Result<Signal> { - use std::convert::TryFrom; - let mut signum = mem::MaybeUninit::uninit(); let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, signum.as_mut_ptr()) }; @@ -640,31 +582,9 @@ impl SigAction { match self.sigaction.sa_sigaction { libc::SIG_DFL => SigHandler::SigDfl, libc::SIG_IGN => SigHandler::SigIgn, - p if self.flags().contains(SaFlags::SA_SIGINFO) => - SigHandler::SigAction( - // Safe for one of two reasons: - // * The SigHandler was created by SigHandler::new, in which - // case the pointer is correct, or - // * The SigHandler was created by signal or sigaction, which - // are unsafe functions, so the caller should've somehow - // ensured that it is correctly initialized. - unsafe{ - *(&p as *const usize - as *const extern fn(_, _, _)) - } - as extern fn(_, _, _)), - p => SigHandler::Handler( - // Safe for one of two reasons: - // * The SigHandler was created by SigHandler::new, in which - // case the pointer is correct, or - // * The SigHandler was created by signal or sigaction, which - // are unsafe functions, so the caller should've somehow - // ensured that it is correctly initialized. - unsafe{ - *(&p as *const usize - as *const extern fn(libc::c_int)) - } - as extern fn(libc::c_int)), + f if self.flags().contains(SaFlags::SA_SIGINFO) => + SigHandler::SigAction( unsafe { mem::transmute(f) } ), + f => SigHandler::Handler( unsafe { mem::transmute(f) } ), } } @@ -674,18 +594,7 @@ impl SigAction { match self.sigaction.sa_handler { libc::SIG_DFL => SigHandler::SigDfl, libc::SIG_IGN => SigHandler::SigIgn, - p => SigHandler::Handler( - // Safe for one of two reasons: - // * The SigHandler was created by SigHandler::new, in which - // case the pointer is correct, or - // * The SigHandler was created by signal or sigaction, which - // are unsafe functions, so the caller should've somehow - // ensured that it is correctly initialized. - unsafe{ - *(&p as *const usize - as *const extern fn(libc::c_int)) - } - as extern fn(libc::c_int)), + f => SigHandler::Handler( unsafe { mem::transmute(f) } ), } } } @@ -697,16 +606,9 @@ impl SigAction { /// /// # Safety /// -/// * Signal handlers may be called at any point during execution, which limits -/// what is safe to do in the body of the signal-catching function. Be certain -/// to only make syscalls that are explicitly marked safe for signal handlers -/// and only share global data using atomics. -/// -/// * There is also no guarantee that the old signal handler was installed -/// correctly. If it was installed by this crate, it will be. But if it was -/// installed by, for example, C code, then there is no guarantee its function -/// pointer is valid. In that case, this function effectively dereferences a -/// raw pointer of unknown provenance. +/// Signal handlers may be called at any point during execution, which limits what is safe to do in +/// the body of the signal-catching function. Be certain to only make syscalls that are explicitly +/// marked safe for signal handlers and only share global data using atomics. pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> { let mut oldact = mem::MaybeUninit::<libc::sigaction>::uninit(); @@ -717,7 +619,7 @@ pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigActi Errno::result(res).map(|_| SigAction { sigaction: oldact.assume_init() }) } -/// Signal management (see [signal(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html)) +/// Signal management (see [signal(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html)) /// /// Installs `handler` for the given `signal`, returning the previous signal /// handler. `signal` should only be used following another call to `signal` or @@ -762,7 +664,7 @@ pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigActi /// /// # Errors /// -/// Returns [`Error(Errno::EOPNOTSUPP)`] if `handler` is +/// Returns [`Error::UnsupportedOperation`] if `handler` is /// [`SigAction`][SigActionStruct]. Use [`sigaction`][SigActionFn] instead. /// /// `signal` also returns any error from `libc::signal`, such as when an attempt @@ -779,16 +681,13 @@ pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> SigHandler::SigIgn => libc::signal(signal, libc::SIG_IGN), SigHandler::Handler(handler) => libc::signal(signal, handler as libc::sighandler_t), #[cfg(not(target_os = "redox"))] - SigHandler::SigAction(_) => return Err(Errno::ENOTSUP), + SigHandler::SigAction(_) => return Err(Error::UnsupportedOperation), }; Errno::result(res).map(|oldhandler| { match oldhandler { libc::SIG_DFL => SigHandler::SigDfl, libc::SIG_IGN => SigHandler::SigIgn, - p => SigHandler::Handler( - *(&p as *const usize - as *const extern fn(libc::c_int)) - as extern fn(libc::c_int)), + f => SigHandler::Handler(mem::transmute(f)), } }) } @@ -825,8 +724,8 @@ fn do_pthread_sigmask(how: SigmaskHow, /// /// If both `set` and `oldset` is None, this function is a no-op. /// -/// For more information, visit the [`pthread_sigmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html), -/// or [`sigprocmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html) man pages. +/// For more information, visit the [`pthread_sigmask`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html), +/// or [`sigprocmask`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html) man pages. pub fn pthread_sigmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> @@ -837,7 +736,7 @@ pub fn pthread_sigmask(how: SigmaskHow, /// Examine and change blocked signals. /// /// For more informations see the [`sigprocmask` man -/// pages](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html). +/// pages](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html). pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> { if set.is_none() && oldset.is_none() { return Ok(()) @@ -855,24 +754,6 @@ pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut Si Errno::result(res).map(drop) } -/// Send a signal to a process -/// -/// # Arguments -/// -/// * `pid` - Specifies which processes should receive the signal. -/// - If positive, specifies an individual process -/// - If zero, the signal will be sent to all processes whose group -/// ID is equal to the process group ID of the sender. This is a -/// variant of [`killpg`]. -/// - If `-1` and the process has super-user privileges, the signal -/// is sent to all processes exclusing system processes. -/// - If less than `-1`, the signal is sent to all processes whose -/// process group ID is equal to the absolute value of `pid`. -/// * `signal` - Signal to send. If `None`, error checking is performed -/// but no signal is actually sent. -/// -/// See Also -/// [`kill(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html) pub fn kill<T: Into<Option<Signal>>>(pid: Pid, signal: T) -> Result<()> { let res = unsafe { libc::kill(pid.into(), match signal.into() { @@ -883,16 +764,12 @@ pub fn kill<T: Into<Option<Signal>>>(pid: Pid, signal: T) -> Result<()> { Errno::result(res).map(drop) } -/// Send a signal to a process group +/// Send a signal to a process group [(see +/// killpg(3))](http://pubs.opengroup.org/onlinepubs/9699919799/functions/killpg.html). /// -/// # Arguments -/// -/// * `pgrp` - Process group to signal. If less then or equal 1, the behavior -/// is platform-specific. -/// * `signal` - Signal to send. If `None`, `killpg` will only preform error -/// checking and won't send any signal. -/// -/// See Also [killpg(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/killpg.html). +/// 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(), @@ -904,9 +781,6 @@ pub fn killpg<T: Into<Option<Signal>>>(pgrp: Pid, signal: T) -> Result<()> { Errno::result(res).map(drop) } -/// Send a signal to the current thread -/// -/// See Also [raise(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/raise.html) pub fn raise(signal: Signal) -> Result<()> { let res = unsafe { libc::raise(signal as libc::c_int) }; @@ -914,51 +788,36 @@ pub fn raise(signal: Signal) -> Result<()> { } -/// Identifies a thread for [`SigevNotify::SigevThreadId`] #[cfg(target_os = "freebsd")] pub type type_of_thread_id = libc::lwpid_t; -/// Identifies a thread for [`SigevNotify::SigevThreadId`] #[cfg(target_os = "linux")] pub type type_of_thread_id = libc::pid_t; -/// Specifies the notification method used by a [`SigEvent`] +/// Used to request asynchronous notification of certain events, for example, +/// with POSIX AIO, POSIX message queues, and POSIX timers. // sigval is actually a union of a int and a void*. But it's never really used // as a pointer, because neither libc nor the kernel ever dereference it. nix // therefore presents it as an intptr_t, which is how kevent uses it. -#[cfg(not(any(target_os = "openbsd", target_os = "redox")))] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum SigevNotify { /// No notification will be delivered SigevNone, - /// Notify by delivering a signal to the process. - SigevSignal { - /// Signal to deliver - signal: Signal, - /// Will be present in the `si_value` field of the [`libc::siginfo_t`] - /// structure of the queued signal. - si_value: libc::intptr_t - }, + /// The signal given by `signal` will be delivered to the process. The + /// value in `si_value` will be present in the `si_value` field of the + /// `siginfo_t` structure of the queued signal. + SigevSignal { signal: Signal, si_value: libc::intptr_t }, // Note: SIGEV_THREAD is not implemented because libc::sigevent does not // expose a way to set the union members needed by SIGEV_THREAD. - /// Notify by delivering an event to a kqueue. + /// A new `kevent` is posted to the kqueue `kq`. The `kevent`'s `udata` + /// field will contain the value in `udata`. #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - SigevKevent { - /// File descriptor of the kqueue to notify. - kq: RawFd, - /// Will be contained in the kevent's `udata` field. - udata: libc::intptr_t - }, - /// Notify by delivering a signal to a thread. + SigevKevent { kq: RawFd, udata: libc::intptr_t }, + /// The signal `signal` is queued to the thread whose LWP ID is given in + /// `thread_id`. The value stored in `si_value` will be present in the + /// `si_value` of the `siginfo_t` structure of the queued signal. #[cfg(any(target_os = "freebsd", target_os = "linux"))] - SigevThreadId { - /// Signal to send - signal: Signal, - /// LWP ID of the thread to notify - thread_id: type_of_thread_id, - /// Will be present in the `si_value` field of the [`libc::siginfo_t`] - /// structure of the queued signal. - si_value: libc::intptr_t - }, + SigevThreadId { signal: Signal, thread_id: type_of_thread_id, + si_value: libc::intptr_t }, } #[cfg(not(any(target_os = "openbsd", target_os = "redox")))] @@ -991,10 +850,10 @@ mod sigevent { /// Linux, Solaris, and portable programs should prefer `SIGEV_THREAD_ID` or /// `SIGEV_SIGNAL`. That field is part of a union that shares space with the /// more genuinely useful `sigev_notify_thread_id` - // Allow invalid_value warning on Fuchsia only. - // See https://github.com/nix-rust/nix/issues/1441 - #[cfg_attr(target_os = "fuchsia", allow(invalid_value))] pub fn new(sigev_notify: SigevNotify) -> SigEvent { + // 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, @@ -1040,7 +899,6 @@ mod sigevent { fn set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify) { } - /// Return a copy of the inner structure pub fn sigevent(&self) -> libc::sigevent { self.sigevent } @@ -1091,7 +949,7 @@ mod tests { #[test] fn test_from_str_invalid_value() { - let errval = Err(Errno::EINVAL); + let errval = Err(Error::Sys(Errno::EINVAL)); assert_eq!("NOSIGNAL".parse::<Signal>(), errval); assert_eq!("kill".parse::<Signal>(), errval); assert_eq!("9".parse::<Signal>(), errval); diff --git a/src/sys/signalfd.rs b/src/sys/signalfd.rs index bc4a452..c43b450 100644 --- a/src/sys/signalfd.rs +++ b/src/sys/signalfd.rs @@ -15,8 +15,9 @@ //! //! Please note that signal discarding is not specific to `signalfd`, but also happens with regular //! signal handlers. +use libc; use crate::unistd; -use crate::Result; +use crate::{Error, Result}; use crate::errno::Errno; pub use crate::sys::signal::{self, SigSet}; pub use libc::signalfd_siginfo as siginfo; @@ -33,8 +34,7 @@ libc_bitflags!{ } pub const SIGNALFD_NEW: RawFd = -1; -#[deprecated(since = "0.23.0", note = "use mem::size_of::<siginfo>() instead")] -pub const SIGNALFD_SIGINFO_SIZE: usize = mem::size_of::<siginfo>(); +pub const SIGNALFD_SIGINFO_SIZE: usize = 128; /// Creates a new file descriptor for reading signals. /// @@ -46,7 +46,7 @@ pub const SIGNALFD_SIGINFO_SIZE: usize = mem::size_of::<siginfo>(); /// A signal must be blocked on every thread in a process, otherwise it won't be visible from /// signalfd (the default handler will be invoked instead). /// -/// See [the signalfd man page for more information](https://man7.org/linux/man-pages/man2/signalfd.2.html) +/// See [the signalfd man page for more information](http://man7.org/linux/man-pages/man2/signalfd.2.html) pub fn signalfd(fd: RawFd, mask: &SigSet, flags: SfdFlags) -> Result<RawFd> { unsafe { Errno::result(libc::signalfd(fd as libc::c_int, mask.as_ref(), flags.bits())) @@ -98,16 +98,17 @@ impl SignalFd { } pub fn read_signal(&mut self) -> Result<Option<siginfo>> { - let mut buffer = mem::MaybeUninit::<siginfo>::uninit(); + let mut buffer = mem::MaybeUninit::<[u8; SIGNALFD_SIGINFO_SIZE]>::uninit(); - let size = mem::size_of_val(&buffer); let res = Errno::result(unsafe { - libc::read(self.0, buffer.as_mut_ptr() as *mut libc::c_void, size) + libc::read(self.0, + buffer.as_mut_ptr() as *mut libc::c_void, + SIGNALFD_SIGINFO_SIZE as libc::size_t) }).map(|r| r as usize); match res { - Ok(x) if x == size => Ok(Some(unsafe { buffer.assume_init() })), + Ok(SIGNALFD_SIGINFO_SIZE) => Ok(Some(unsafe { mem::transmute(buffer.assume_init()) })), Ok(_) => unreachable!("partial read on signalfd"), - Err(Errno::EAGAIN) => Ok(None), + Err(Error::Sys(Errno::EAGAIN)) => Ok(None), Err(error) => Err(error) } } @@ -116,7 +117,7 @@ impl SignalFd { impl Drop for SignalFd { fn drop(&mut self) { let e = unistd::close(self.0); - if !std::thread::panicking() && e == Err(Errno::EBADF) { + if !std::thread::panicking() && e == Err(Error::Sys(Errno::EBADF)) { panic!("Closing an invalid file descriptor!"); }; } @@ -143,6 +144,14 @@ impl Iterator for SignalFd { #[cfg(test)] mod tests { use super::*; + use std::mem; + use libc; + + + #[test] + fn check_siginfo_size() { + assert_eq!(mem::size_of::<libc::signalfd_siginfo>(), SIGNALFD_SIGINFO_SIZE); + } #[test] fn create_signalfd() { diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index b119642..2299c57 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -1,7 +1,6 @@ use super::sa_family_t; -use crate::{Result, NixPath}; +use crate::{Error, Result, NixPath}; use crate::errno::Errno; -use memoffset::offset_of; use std::{fmt, mem, net, ptr, slice}; use std::ffi::OsStr; use std::hash::{Hash, Hasher}; @@ -21,7 +20,6 @@ use crate::sys::socket::addr::sys_control::SysControlAddr; target_os = "ios", target_os = "linux", target_os = "macos", - target_os = "illumos", target_os = "netbsd", target_os = "openbsd", target_os = "fuchsia"))] @@ -32,24 +30,19 @@ pub use self::vsock::VsockAddr; /// These constants specify the protocol family to be used /// in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html) #[repr(i32)] -#[non_exhaustive] #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub enum AddressFamily { - /// Local communication (see [`unix(7)`](https://man7.org/linux/man-pages/man7/unix.7.html)) + /// Local communication (see [`unix(7)`](http://man7.org/linux/man-pages/man7/unix.7.html)) Unix = libc::AF_UNIX, - /// IPv4 Internet protocols (see [`ip(7)`](https://man7.org/linux/man-pages/man7/ip.7.html)) + /// IPv4 Internet protocols (see [`ip(7)`](http://man7.org/linux/man-pages/man7/ip.7.html)) Inet = libc::AF_INET, - /// IPv6 Internet protocols (see [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html)) + /// IPv6 Internet protocols (see [`ipv6(7)`](http://man7.org/linux/man-pages/man7/ipv6.7.html)) Inet6 = libc::AF_INET6, - /// Kernel user interface device (see [`netlink(7)`](https://man7.org/linux/man-pages/man7/netlink.7.html)) + /// Kernel user interface device (see [`netlink(7)`](http://man7.org/linux/man-pages/man7/netlink.7.html)) #[cfg(any(target_os = "android", target_os = "linux"))] Netlink = libc::AF_NETLINK, - /// Low level packet interface (see [`packet(7)`](https://man7.org/linux/man-pages/man7/packet.7.html)) - #[cfg(any(target_os = "android", - target_os = "linux", - target_os = "illumos", - target_os = "fuchsia", - target_os = "solaris"))] + /// 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", target_os = "fuchsia"))] Packet = libc::AF_PACKET, /// KEXT Controls and Notifications #[cfg(any(target_os = "ios", target_os = "macos"))] @@ -68,7 +61,7 @@ pub enum AddressFamily { /// Access to raw ATM PVCs #[cfg(any(target_os = "android", target_os = "linux"))] AtmPvc = libc::AF_ATMPVC, - /// ITU-T X.25 / ISO-8208 protocol (see [`x25(7)`](https://man7.org/linux/man-pages/man7/x25.7.html)) + /// ITU-T X.25 / ISO-8208 protocol (see [`x25(7)`](http://man7.org/linux/man-pages/man7/x25.7.html)) #[cfg(any(target_os = "android", target_os = "linux"))] X25 = libc::AF_X25, #[cfg(any(target_os = "android", target_os = "linux"))] @@ -105,16 +98,12 @@ pub enum AddressFamily { Can = libc::AF_CAN, #[cfg(any(target_os = "android", target_os = "linux"))] Tipc = libc::AF_TIPC, - #[cfg(not(any(target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "solaris")))] + #[cfg(not(any(target_os = "ios", target_os = "macos")))] Bluetooth = libc::AF_BLUETOOTH, #[cfg(any(target_os = "android", target_os = "linux"))] Iucv = libc::AF_IUCV, #[cfg(any(target_os = "android", target_os = "linux"))] RxRpc = libc::AF_RXRPC, - #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] Isdn = libc::AF_ISDN, #[cfg(any(target_os = "android", target_os = "linux"))] Phonet = libc::AF_PHONET, @@ -201,7 +190,6 @@ pub enum AddressFamily { target_os = "freebsd", target_os = "ios", target_os = "macos", - target_os = "illumos", target_os = "netbsd", target_os = "openbsd"))] Link = libc::AF_LINK, @@ -226,7 +214,7 @@ pub enum AddressFamily { target_os = "netbsd", target_os = "openbsd"))] Natm = libc::AF_NATM, - /// Unspecified address family, (see [`getaddrinfo(3)`](https://man7.org/linux/man-pages/man3/getaddrinfo.3.html)) + /// Unspecified address family, (see [`getaddrinfo(3)`](http://man7.org/linux/man-pages/man3/getaddrinfo.3.html)) #[cfg(any(target_os = "android", target_os = "linux"))] Unspec = libc::AF_UNSPEC, } @@ -237,7 +225,7 @@ impl AddressFamily { /// /// Currently only supports these address families: Unix, Inet (v4 & v6), Netlink, Link/Packet /// and System. Returns None for unsupported or unknown address families. - pub const fn from_i32(family: i32) -> Option<AddressFamily> { + pub fn from_i32(family: i32) -> Option<AddressFamily> { match family { libc::AF_UNIX => Some(AddressFamily::Unix), libc::AF_INET => Some(AddressFamily::Inet), @@ -253,7 +241,6 @@ impl AddressFamily { target_os = "ios", target_os = "macos", target_os = "netbsd", - target_os = "illumos", target_os = "openbsd"))] libc::AF_LINK => Some(AddressFamily::Link), #[cfg(any(target_os = "android", target_os = "linux"))] @@ -270,7 +257,6 @@ pub enum InetAddr { } impl InetAddr { - #[allow(clippy::needless_update)] // It isn't needless on all OSes pub fn from_std(std: &net::SocketAddr) -> InetAddr { match *std { net::SocketAddr::V4(ref addr) => { @@ -294,7 +280,6 @@ impl InetAddr { } } - #[allow(clippy::needless_update)] // It isn't needless on all OSes pub fn new(ip: IpAddr, port: u16) -> InetAddr { match ip { IpAddr::V4(ref ip) => { @@ -316,7 +301,7 @@ impl InetAddr { } } /// Gets the IP address associated with this socket address. - pub const fn ip(&self) -> IpAddr { + pub fn ip(&self) -> IpAddr { match *self { InetAddr::V4(ref sa) => IpAddr::V4(Ipv4Addr(sa.sin_addr)), InetAddr::V6(ref sa) => IpAddr::V6(Ipv6Addr(sa.sin6_addr)), @@ -324,7 +309,7 @@ impl InetAddr { } /// Gets the port number associated with this socket address - pub const fn port(&self) -> u16 { + pub fn port(&self) -> u16 { match *self { InetAddr::V6(ref sa) => u16::from_be(sa.sin6_port), InetAddr::V4(ref sa) => u16::from_be(sa.sin_port), @@ -346,7 +331,6 @@ impl InetAddr { } } - #[deprecated(since = "0.23.0", note = "use .to_string() instead")] pub fn to_str(&self) -> String { format!("{}", self) } @@ -376,7 +360,7 @@ impl IpAddr { /// Create a new IpAddr that contains an IPv4 address. /// /// The result will represent the IP address a.b.c.d - pub const fn new_v4(a: u8, b: u8, c: u8, d: u8) -> IpAddr { + pub fn new_v4(a: u8, b: u8, c: u8, d: u8) -> IpAddr { IpAddr::V4(Ipv4Addr::new(a, b, c, d)) } @@ -385,7 +369,7 @@ impl IpAddr { /// The result will represent the IP address a:b:c:d:e:f #[allow(clippy::many_single_char_names)] #[allow(clippy::too_many_arguments)] - pub const fn new_v6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> IpAddr { + pub fn new_v6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> IpAddr { IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h)) } @@ -396,7 +380,7 @@ impl IpAddr { } } - pub const fn to_std(&self) -> net::IpAddr { + pub fn to_std(&self) -> net::IpAddr { match *self { IpAddr::V4(ref ip) => net::IpAddr::V4(ip.to_std()), IpAddr::V6(ref ip) => net::IpAddr::V6(ip.to_std()), @@ -424,11 +408,11 @@ pub struct Ipv4Addr(pub libc::in_addr); impl Ipv4Addr { #[allow(clippy::identity_op)] // More readable this way - pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { - let ip = (((a as u32) << 24) | - ((b as u32) << 16) | - ((c as u32) << 8) | - ((d as u32) << 0)).to_be(); + pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { + let ip = ((u32::from(a) << 24) | + (u32::from(b) << 16) | + (u32::from(c) << 8) | + (u32::from(d) << 0)).to_be(); Ipv4Addr(libc::in_addr { s_addr: ip }) } @@ -440,16 +424,16 @@ impl Ipv4Addr { Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3]) } - pub const fn any() -> Ipv4Addr { + pub fn any() -> Ipv4Addr { Ipv4Addr(libc::in_addr { s_addr: libc::INADDR_ANY }) } - pub const fn octets(self) -> [u8; 4] { + pub fn octets(self) -> [u8; 4] { let bits = u32::from_be(self.0.s_addr); [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8] } - pub const fn to_std(self) -> net::Ipv4Addr { + pub fn to_std(self) -> net::Ipv4Addr { let bits = self.octets(); net::Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3]) } @@ -490,7 +474,7 @@ macro_rules! to_u16_array { impl Ipv6Addr { #[allow(clippy::many_single_char_names)] #[allow(clippy::too_many_arguments)] - pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { + pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { Ipv6Addr(libc::in6_addr{s6_addr: to_u8_array!(a,b,c,d,e,f,g,h)}) } @@ -500,11 +484,11 @@ impl Ipv6Addr { } /// Return the eight 16-bit segments that make up this address - pub const fn segments(&self) -> [u16; 8] { + pub fn segments(&self) -> [u16; 8] { to_u16_array!(self, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15) } - pub const fn to_std(&self) -> net::Ipv6Addr { + pub fn to_std(&self) -> net::Ipv6Addr { let s = self.segments(); net::Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7]) } @@ -517,42 +501,15 @@ impl fmt::Display for Ipv6Addr { } /// A wrapper around `sockaddr_un`. +/// +/// This also tracks the length of `sun_path` address (excluding +/// a terminating null), because it may not be null-terminated. For example, +/// unconnected and Linux abstract sockets are never null-terminated, and POSIX +/// does not require that `sun_len` include the terminating null even for normal +/// sockets. Note that the actual sockaddr length is greater by +/// `offset_of!(libc::sockaddr_un, sun_path)` #[derive(Clone, Copy, Debug)] -pub struct UnixAddr { - // INVARIANT: sun & path_len are valid as defined by docs for from_raw_parts - sun: libc::sockaddr_un, - path_len: usize, -} - -// linux man page unix(7) says there are 3 kinds of unix socket: -// pathname: addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(sun_path) + 1 -// unnamed: addrlen = sizeof(sa_family_t) -// abstract: addren > sizeof(sa_family_t), name = sun_path[..(addrlen - sizeof(sa_family_t))] -// -// what we call path_len = addrlen - offsetof(struct sockaddr_un, sun_path) -#[derive(PartialEq, Eq, Hash)] -enum UnixAddrKind<'a> { - Pathname(&'a Path), - Unnamed, - #[cfg(any(target_os = "android", target_os = "linux"))] - Abstract(&'a [u8]), -} -impl<'a> UnixAddrKind<'a> { - /// Safety: sun & path_len must be valid - unsafe fn get(sun: &'a libc::sockaddr_un, path_len: usize) -> Self { - if path_len == 0 { - return Self::Unnamed; - } - #[cfg(any(target_os = "android", target_os = "linux"))] - if sun.sun_path[0] == 0 { - let name = - slice::from_raw_parts(sun.sun_path.as_ptr().add(1) as *const u8, path_len - 1); - return Self::Abstract(name); - } - let pathname = slice::from_raw_parts(sun.sun_path.as_ptr() as *const u8, path_len - 1); - Self::Pathname(Path::new(OsStr::from_bytes(pathname))) - } -} +pub struct UnixAddr(pub libc::sockaddr_un, pub usize); impl UnixAddr { /// Create a new sockaddr_un representing a filesystem path. @@ -566,15 +523,15 @@ impl UnixAddr { let bytes = cstr.to_bytes(); - if bytes.len() >= ret.sun_path.len() { - return Err(Errno::ENAMETOOLONG); + if bytes.len() > ret.sun_path.len() { + return Err(Error::Sys(Errno::ENAMETOOLONG)); } ptr::copy_nonoverlapping(bytes.as_ptr(), ret.sun_path.as_mut_ptr() as *mut u8, bytes.len()); - Ok(UnixAddr::from_raw_parts(ret, bytes.len() + 1)) + Ok(UnixAddr(ret, bytes.len())) } })? } @@ -593,8 +550,8 @@ impl UnixAddr { .. mem::zeroed() }; - if path.len() >= ret.sun_path.len() { - return Err(Errno::ENAMETOOLONG); + if path.len() + 1 > ret.sun_path.len() { + return Err(Error::Sys(Errno::ENAMETOOLONG)); } // Abstract addresses are represented by sun_path[0] == @@ -603,39 +560,28 @@ impl UnixAddr { ret.sun_path.as_mut_ptr().offset(1) as *mut u8, path.len()); - Ok(UnixAddr::from_raw_parts(ret, path.len() + 1)) + Ok(UnixAddr(ret, path.len() + 1)) } } - /// Create a UnixAddr from a raw `sockaddr_un` struct and a size. `path_len` is the "addrlen" - /// of this address, but minus `offsetof(struct sockaddr_un, sun_path)`. Basically the length - /// of the data in `sun_path`. - /// - /// # Safety - /// This pair of sockaddr_un & path_len must be a valid unix addr, which means: - /// - path_len <= sockaddr_un.sun_path.len() - /// - if this is a unix addr with a pathname, sun.sun_path is a nul-terminated fs path and - /// sun.sun_path[path_len - 1] == 0 || sun.sun_path[path_len] == 0 - pub(crate) unsafe fn from_raw_parts(sun: libc::sockaddr_un, mut path_len: usize) -> UnixAddr { - if let UnixAddrKind::Pathname(_) = UnixAddrKind::get(&sun, path_len) { - if sun.sun_path[path_len - 1] != 0 { - assert_eq!(sun.sun_path[path_len], 0); - path_len += 1 - } - } - UnixAddr { sun, path_len } - } - - fn kind(&self) -> UnixAddrKind<'_> { - // SAFETY: our sockaddr is always valid because of the invariant on the struct - unsafe { UnixAddrKind::get(&self.sun, self.path_len) } + fn sun_path(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.0.sun_path.as_ptr() as *const u8, self.1) } } /// If this address represents a filesystem path, return that path. pub fn path(&self) -> Option<&Path> { - match self.kind() { - UnixAddrKind::Pathname(path) => Some(path), - _ => None, + if self.1 == 0 || self.0.sun_path[0] == 0 { + // unnamed or abstract + None + } else { + let p = self.sun_path(); + // POSIX only requires that `sun_len` be at least long enough to + // contain the pathname, and it need not be null-terminated. So we + // need to create a string that is the shorter of the + // null-terminated length or the full length. + let ptr = &self.0.sun_path as *const libc::c_char; + let reallen = unsafe { libc::strnlen(ptr, p.len()) }; + Some(Path::new(<OsStr as OsStrExt>::from_bytes(&p[..reallen]))) } } @@ -645,55 +591,31 @@ impl UnixAddr { /// leading null byte. `None` is returned for unnamed or path-backed sockets. #[cfg(any(target_os = "android", target_os = "linux"))] pub fn as_abstract(&self) -> Option<&[u8]> { - match self.kind() { - UnixAddrKind::Abstract(name) => Some(name), - _ => None, + if self.1 >= 1 && self.0.sun_path[0] == 0 { + Some(&self.sun_path()[1..]) + } else { + // unnamed or filesystem path + None } } - - /// Returns the addrlen of this socket - `offsetof(struct sockaddr_un, sun_path)` - #[inline] - pub fn path_len(&self) -> usize { - self.path_len - } - /// Returns a pointer to the raw `sockaddr_un` struct - #[inline] - pub fn as_ptr(&self) -> *const libc::sockaddr_un { - &self.sun - } - /// Returns a mutable pointer to the raw `sockaddr_un` struct - #[inline] - pub fn as_mut_ptr(&mut self) -> *mut libc::sockaddr_un { - &mut self.sun - } -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -fn fmt_abstract(abs: &[u8], f: &mut fmt::Formatter) -> fmt::Result { - use fmt::Write; - f.write_str("@\"")?; - for &b in abs { - use fmt::Display; - char::from(b).escape_default().fmt(f)?; - } - f.write_char('"')?; - Ok(()) } impl fmt::Display for UnixAddr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.kind() { - UnixAddrKind::Pathname(path) => path.display().fmt(f), - UnixAddrKind::Unnamed => f.pad("<unbound UNIX socket>"), - #[cfg(any(target_os = "android", target_os = "linux"))] - UnixAddrKind::Abstract(name) => fmt_abstract(name, f), + if self.1 == 0 { + f.write_str("<unbound UNIX socket>") + } else if let Some(path) = self.path() { + path.display().fmt(f) + } else { + let display = String::from_utf8_lossy(&self.sun_path()[1..]); + write!(f, "@{}", display) } } } impl PartialEq for UnixAddr { fn eq(&self, other: &UnixAddr) -> bool { - self.kind() == other.kind() + self.sun_path() == other.sun_path() } } @@ -701,13 +623,12 @@ impl Eq for UnixAddr {} impl Hash for UnixAddr { fn hash<H: Hasher>(&self, s: &mut H) { - self.kind().hash(s) + ( self.0.sun_family, self.sun_path() ).hash(s) } } /// Represents a socket address #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[non_exhaustive] pub enum SockAddr { Inet(InetAddr), Unix(UnixAddr), @@ -724,7 +645,6 @@ pub enum SockAddr { target_os = "ios", target_os = "linux", target_os = "macos", - target_os = "illumos", target_os = "netbsd", target_os = "openbsd"))] Link(LinkAddr), @@ -753,7 +673,7 @@ impl SockAddr { #[cfg(any(target_os = "ios", target_os = "macos"))] pub fn new_sys_control(sockfd: RawFd, name: &str, unit: u32) -> Result<SockAddr> { - SysControlAddr::from_name(sockfd, name, unit).map(SockAddr::SysControl) + SysControlAddr::from_name(sockfd, name, unit).map(|a| SockAddr::SysControl(a)) } #[cfg(any(target_os = "android", target_os = "linux"))] @@ -779,7 +699,6 @@ impl SockAddr { target_os = "ios", target_os = "macos", target_os = "netbsd", - target_os = "illumos", target_os = "openbsd"))] SockAddr::Link(..) => AddressFamily::Link, #[cfg(any(target_os = "android", target_os = "linux"))] @@ -787,7 +706,6 @@ impl SockAddr { } } - #[deprecated(since = "0.23.0", note = "use .to_string() instead")] pub fn to_str(&self) -> String { format!("{}", self) } @@ -826,7 +744,6 @@ impl SockAddr { target_os = "ios", target_os = "macos", target_os = "netbsd", - target_os = "illumos", target_os = "openbsd"))] Some(AddressFamily::Link) => { let ether_addr = LinkAddr(*(addr as *const libc::sockaddr_dl)); @@ -869,12 +786,12 @@ impl SockAddr { }, mem::size_of_val(addr) as libc::socklen_t ), - SockAddr::Unix(UnixAddr { ref sun, path_len }) => ( + SockAddr::Unix(UnixAddr(ref addr, len)) => ( // This cast is always allowed in C unsafe { - &*(sun as *const libc::sockaddr_un as *const libc::sockaddr) + &*(addr as *const libc::sockaddr_un as *const libc::sockaddr) }, - (path_len + offset_of!(libc::sockaddr_un, sun_path)) as libc::socklen_t + (len + offset_of!(libc::sockaddr_un, sun_path)) as libc::socklen_t ), #[cfg(any(target_os = "android", target_os = "linux"))] SockAddr::Netlink(NetlinkAddr(ref sa)) => ( @@ -913,7 +830,6 @@ impl SockAddr { target_os = "freebsd", target_os = "ios", target_os = "macos", - target_os = "illumos", target_os = "netbsd", target_os = "openbsd"))] SockAddr::Link(LinkAddr(ref addr)) => ( @@ -953,7 +869,6 @@ impl fmt::Display for SockAddr { target_os = "linux", target_os = "macos", target_os = "netbsd", - target_os = "illumos", target_os = "openbsd"))] SockAddr::Link(ref ether_addr) => ether_addr.fmt(f), #[cfg(any(target_os = "android", target_os = "linux"))] @@ -981,11 +896,11 @@ pub mod netlink { NetlinkAddr(addr) } - pub const fn pid(&self) -> u32 { + pub fn pid(&self) -> u32 { self.0.nl_pid } - pub const fn groups(&self) -> u32 { + pub fn groups(&self) -> u32 { self.0.nl_groups } } @@ -1066,7 +981,7 @@ pub mod sys_control { use libc::{self, c_uchar}; use std::{fmt, mem}; use std::os::unix::io::RawFd; - use crate::{Errno, Result}; + use crate::{Errno, Error, Result}; // FIXME: Move type into `libc` #[repr(C)] @@ -1077,7 +992,7 @@ pub mod sys_control { pub ctl_name: [c_uchar; MAX_KCTL_NAME], } - const CTL_IOC_MAGIC: u8 = b'N'; + const CTL_IOC_MAGIC: u8 = 'N' as u8; const CTL_IOC_INFO: u8 = 3; const MAX_KCTL_NAME: usize = 96; @@ -1088,7 +1003,7 @@ pub mod sys_control { pub struct SysControlAddr(pub libc::sockaddr_ctl); impl SysControlAddr { - pub const fn new(id: u32, unit: u32) -> SysControlAddr { + pub fn new(id: u32, unit: u32) -> SysControlAddr { let addr = libc::sockaddr_ctl { sc_len: mem::size_of::<libc::sockaddr_ctl>() as c_uchar, sc_family: AddressFamily::System as c_uchar, @@ -1103,7 +1018,7 @@ pub mod sys_control { pub fn from_name(sockfd: RawFd, name: &str, unit: u32) -> Result<SysControlAddr> { if name.len() > MAX_KCTL_NAME { - return Err(Errno::ENAMETOOLONG); + return Err(Error::Sys(Errno::ENAMETOOLONG)); } let mut ctl_name = [0; MAX_KCTL_NAME]; @@ -1115,11 +1030,11 @@ pub mod sys_control { Ok(SysControlAddr::new(info.ctl_id, unit)) } - pub const fn id(&self) -> u32 { + pub fn id(&self) -> u32 { self.0.sc_id } - pub const fn unit(&self) -> u32 { + pub fn unit(&self) -> u32 { self.0.sc_unit } } @@ -1203,7 +1118,6 @@ mod datalink { target_os = "freebsd", target_os = "ios", target_os = "macos", - target_os = "illumos", target_os = "netbsd", target_os = "openbsd"))] mod datalink { @@ -1215,7 +1129,6 @@ mod datalink { impl LinkAddr { /// Total length of sockaddr - #[cfg(not(target_os = "illumos"))] pub fn len(&self) -> usize { self.0.sdl_len as usize } @@ -1367,7 +1280,6 @@ mod tests { target_os = "linux", target_os = "macos", target_os = "netbsd", - target_os = "illumos", target_os = "openbsd"))] use super::*; @@ -1412,36 +1324,17 @@ mod tests { }; } - #[cfg(target_os = "illumos")] - #[test] - fn test_illumos_tap_datalink_addr() { - let bytes = [25u8, 0, 0, 0, 6, 0, 6, 0, 24, 101, 144, 221, 76, 176]; - let ptr = bytes.as_ptr(); - let sa = ptr as *const libc::sockaddr; - let _sock_addr = unsafe { SockAddr::from_libc_sockaddr(sa) }; - - assert!(_sock_addr.is_some()); - - let sock_addr = _sock_addr.unwrap(); - - assert_eq!(sock_addr.family(), AddressFamily::Link); - - match sock_addr { - SockAddr::Link(ether_addr) => { - assert_eq!(ether_addr.addr(), [24u8, 101, 144, 221, 76, 176]); - }, - _ => { unreachable!() } - }; - } - #[cfg(any(target_os = "android", target_os = "linux"))] #[test] fn test_abstract_sun_path() { let name = String::from("nix\0abstract\0test"); let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap(); - let sun_path1 = unsafe { &(*addr.as_ptr()).sun_path[..addr.path_len()] }; - let sun_path2 = [0, 110, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116]; - assert_eq!(sun_path1, sun_path2); + let sun_path1 = addr.sun_path(); + let sun_path2 = [0u8, 110, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116]; + assert_eq!(sun_path1.len(), sun_path2.len()); + for i in 0..sun_path1.len() { + assert_eq!(sun_path1[i], sun_path2[i]); + } } } diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 97eea3d..11ed329 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1,20 +1,16 @@ //! Socket interface functions //! -//! [Further reading](https://man7.org/linux/man-pages/man7/socket.7.html) +//! [Further reading](http://man7.org/linux/man-pages/man7/socket.7.html) use cfg_if::cfg_if; -use crate::{Result, errno::Errno}; +use crate::{Error, Result, errno::Errno}; use libc::{self, c_void, c_int, iovec, socklen_t, size_t, CMSG_FIRSTHDR, CMSG_NXTHDR, CMSG_DATA, CMSG_LEN}; -use memoffset::offset_of; use std::{mem, ptr, slice}; use std::os::unix::io::RawFd; -#[cfg(all(target_os = "linux"))] -use crate::sys::time::TimeSpec; use crate::sys::time::TimeVal; use crate::sys::uio::IoVec; mod addr; -#[deny(missing_docs)] pub mod sockopt; /* @@ -23,7 +19,6 @@ pub mod sockopt; * */ -#[cfg(not(any(target_os = "illumos", target_os = "solaris")))] pub use self::addr::{ AddressFamily, SockAddr, @@ -34,17 +29,6 @@ pub use self::addr::{ Ipv6Addr, LinkAddr, }; -#[cfg(any(target_os = "illumos", target_os = "solaris"))] -pub use self::addr::{ - AddressFamily, - SockAddr, - InetAddr, - UnixAddr, - IpAddr, - Ipv4Addr, - Ipv6Addr, -}; - #[cfg(any(target_os = "android", target_os = "linux"))] pub use crate::sys::socket::addr::netlink::NetlinkAddr; #[cfg(any(target_os = "android", target_os = "linux"))] @@ -71,7 +55,6 @@ pub use libc::{c_uint, CMSG_SPACE}; /// when creating a socket with [`socket()`](fn.socket.html) #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[repr(i32)] -#[non_exhaustive] pub enum SockType { /// Provides sequenced, reliable, two-way, connection- /// based byte streams. An out-of-band data transmission @@ -96,11 +79,10 @@ pub enum SockType { /// to specify the protocol to use. #[repr(i32)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[non_exhaustive] pub enum SockProtocol { - /// TCP protocol ([ip(7)](https://man7.org/linux/man-pages/man7/ip.7.html)) + /// TCP protocol ([ip(7)](http://man7.org/linux/man-pages/man7/ip.7.html)) Tcp = libc::IPPROTO_TCP, - /// UDP protocol ([ip(7)](https://man7.org/linux/man-pages/man7/ip.7.html)) + /// UDP protocol ([ip(7)](http://man7.org/linux/man-pages/man7/ip.7.html)) Udp = libc::IPPROTO_UDP, /// Allows applications and other KEXTs to be notified when certain kernel events occur /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html)) @@ -177,7 +159,6 @@ libc_bitflags!{ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "illumos", target_os = "linux", target_os = "netbsd", target_os = "openbsd"))] @@ -186,7 +167,6 @@ libc_bitflags!{ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "illumos", target_os = "linux", target_os = "netbsd", target_os = "openbsd"))] @@ -222,7 +202,7 @@ libc_bitflags!{ /// (via the [`fcntl`](../../fcntl/fn.fcntl.html) /// `F_SETFL` operation), but differs in that `MSG_DONTWAIT` is a per- /// call option, whereas `O_NONBLOCK` is a setting on the open file - /// description (see [open(2)](https://man7.org/linux/man-pages/man2/open.2.html)), + /// description (see [open(2)](http://man7.org/linux/man-pages/man2/open.2.html)), /// which will affect all threads in /// the calling process and as well as other processes that hold /// file descriptors referring to the same open file description. @@ -250,7 +230,7 @@ libc_bitflags!{ /// file descriptor using the `SCM_RIGHTS` operation (described in /// [unix(7)](https://linux.die.net/man/7/unix)). /// This flag is useful for the same reasons as the `O_CLOEXEC` flag of - /// [open(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html). + /// [open(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html). /// /// Only used in [`recvmsg`](fn.recvmsg.html) function. #[cfg(any(target_os = "android", @@ -311,9 +291,9 @@ cfg_if! { } } - impl From<UnixCredentials> for libc::ucred { - fn from(uc: UnixCredentials) -> Self { - uc.0 + impl Into<libc::ucred> for UnixCredentials { + fn into(self) -> libc::ucred { + self.0 } } } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] { @@ -359,38 +339,6 @@ cfg_if! { } } -cfg_if!{ - if #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "ios" - ))] { - /// Return type of [`LocalPeerCred`](crate::sys::socket::sockopt::LocalPeerCred) - #[repr(transparent)] - #[derive(Clone, Copy, Debug, Eq, PartialEq)] - pub struct XuCred(libc::xucred); - - impl XuCred { - /// Structure layout version - pub fn version(&self) -> u32 { - self.0.cr_version - } - - /// Effective user ID - pub fn uid(&self) -> libc::uid_t { - self.0.cr_uid - } - - /// Returns a list of group identifiers (the first one being the - /// effective GID) - pub fn groups(&self) -> &[libc::gid_t] { - &self.0.cr_groups - } - } - } -} - /// Request for multicast socket operations /// /// This is a wrapper type around `ip_mreq`. @@ -419,7 +367,7 @@ pub struct Ipv6MembershipRequest(libc::ipv6_mreq); impl Ipv6MembershipRequest { /// Instantiate a new `Ipv6MembershipRequest` - pub const fn new(group: Ipv6Addr) -> Self { + pub fn new(group: Ipv6Addr) -> Self { Ipv6MembershipRequest(libc::ipv6_mreq { ipv6mr_multiaddr: group.0, ipv6mr_interface: 0, @@ -453,11 +401,13 @@ impl Ipv6MembershipRequest { macro_rules! cmsg_space { ( $( $x:ty ),* ) => { { + use nix::sys::socket::{c_uint, CMSG_SPACE}; + use std::mem; let mut space = 0; $( // CMSG_SPACE is always safe space += unsafe { - $crate::sys::socket::CMSG_SPACE(::std::mem::size_of::<$x>() as $crate::sys::socket::c_uint) + CMSG_SPACE(mem::size_of::<$x>() as c_uint) } as usize; )* Vec::<u8>::with_capacity(space) @@ -517,7 +467,7 @@ impl<'a> Iterator for CmsgIterator<'a> { /// A type-safe wrapper around a single control message, as used with /// [`recvmsg`](#fn.recvmsg). /// -/// [Further reading](https://man7.org/linux/man-pages/man3/cmsg.3.html) +/// [Further reading](http://man7.org/linux/man-pages/man3/cmsg.3.html) // Nix version 0.13.0 and earlier used ControlMessage for both recvmsg and // sendmsg. However, on some platforms the messages returned by recvmsg may be // unaligned. ControlMessageOwned takes those messages by copy, obviating any @@ -525,14 +475,16 @@ impl<'a> Iterator for CmsgIterator<'a> { // // See https://github.com/nix-rust/nix/issues/999 #[derive(Clone, Debug, Eq, PartialEq)] -#[non_exhaustive] pub enum ControlMessageOwned { - /// Received version of [`ControlMessage::ScmRights`] + /// Received version of + /// [`ControlMessage::ScmRights`][#enum.ControlMessage.html#variant.ScmRights] ScmRights(Vec<RawFd>), - /// Received version of [`ControlMessage::ScmCredentials`] + /// Received version of + /// [`ControlMessage::ScmCredentials`][#enum.ControlMessage.html#variant.ScmCredentials] #[cfg(any(target_os = "android", target_os = "linux"))] ScmCredentials(UnixCredentials), - /// Received version of [`ControlMessage::ScmCreds`] + /// Received version of + /// [`ControlMessage::ScmCreds`][#enum.ControlMessage.html#variant.ScmCreds] #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] ScmCreds(UnixCredentials), /// A message of type `SCM_TIMESTAMP`, containing the time the @@ -543,7 +495,6 @@ pub enum ControlMessageOwned { /// /// # Examples /// - /// ``` /// # #[macro_use] extern crate nix; /// # use nix::sys::socket::*; /// # use nix::sys::uio::IoVec; @@ -591,11 +542,6 @@ pub enum ControlMessageOwned { /// # } /// ``` ScmTimestamp(TimeVal), - /// Nanoseconds resolution timestamp - /// - /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) - #[cfg(all(target_os = "linux"))] - ScmTimestampns(TimeSpec), #[cfg(any( target_os = "android", target_os = "ios", @@ -643,24 +589,6 @@ pub enum ControlMessageOwned { #[cfg(target_os = "linux")] UdpGroSegments(u16), - /// SO_RXQ_OVFL indicates that an unsigned 32 bit value - /// ancilliary msg (cmsg) should be attached to recieved - /// skbs indicating the number of packets dropped by the - /// socket between the last recieved packet and this - /// received packet. - /// - /// `RxqOvfl` socket option should be enabled on a socket - /// to allow receiving the drop counter. - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - RxqOvfl(u32), - - /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag. - #[cfg(any(target_os = "android", target_os = "linux"))] - Ipv4RecvErr(libc::sock_extended_err, Option<sockaddr_in>), - /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag. - #[cfg(any(target_os = "android", target_os = "linux"))] - Ipv6RecvErr(libc::sock_extended_err, Option<sockaddr_in6>), - /// Catch-all variant for unimplemented cmsg types. #[doc(hidden)] Unknown(UnknownCmsg), @@ -705,11 +633,6 @@ impl ControlMessageOwned { let tv: libc::timeval = ptr::read_unaligned(p as *const _); ControlMessageOwned::ScmTimestamp(TimeVal::from(tv)) }, - #[cfg(all(target_os = "linux"))] - (libc::SOL_SOCKET, libc::SCM_TIMESTAMPNS) => { - let ts: libc::timespec = ptr::read_unaligned(p as *const _); - ControlMessageOwned::ScmTimestampns(TimeSpec::from(ts)) - } #[cfg(any( target_os = "android", target_os = "freebsd", @@ -759,61 +682,27 @@ impl ControlMessageOwned { let gso_size: u16 = ptr::read_unaligned(p as *const _); ControlMessageOwned::UdpGroSegments(gso_size) }, - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - (libc::SOL_SOCKET, libc::SO_RXQ_OVFL) => { - let drop_counter = ptr::read_unaligned(p as *const u32); - ControlMessageOwned::RxqOvfl(drop_counter) - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - (libc::IPPROTO_IP, libc::IP_RECVERR) => { - let (err, addr) = Self::recv_err_helper::<sockaddr_in>(p, len); - ControlMessageOwned::Ipv4RecvErr(err, addr) - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - (libc::IPPROTO_IPV6, libc::IPV6_RECVERR) => { - let (err, addr) = Self::recv_err_helper::<sockaddr_in6>(p, len); - ControlMessageOwned::Ipv6RecvErr(err, addr) - }, (_, _) => { let sl = slice::from_raw_parts(p, len); - let ucmsg = UnknownCmsg(*header, Vec::<u8>::from(sl)); + let ucmsg = UnknownCmsg(*header, Vec::<u8>::from(&sl[..])); ControlMessageOwned::Unknown(ucmsg) } } } - - #[cfg(any(target_os = "android", target_os = "linux"))] - unsafe fn recv_err_helper<T>(p: *mut libc::c_uchar, len: usize) -> (libc::sock_extended_err, Option<T>) { - let ee = p as *const libc::sock_extended_err; - let err = ptr::read_unaligned(ee); - - // For errors originating on the network, SO_EE_OFFENDER(ee) points inside the p[..len] - // CMSG_DATA buffer. For local errors, there is no address included in the control - // message, and SO_EE_OFFENDER(ee) points beyond the end of the buffer. So, we need to - // validate that the address object is in-bounds before we attempt to copy it. - let addrp = libc::SO_EE_OFFENDER(ee) as *const T; - - if addrp.offset(1) as usize - (p as usize) > len { - (err, None) - } else { - (err, Some(ptr::read_unaligned(addrp))) - } - } } /// A type-safe zero-copy wrapper around a single control message, as used wih /// [`sendmsg`](#fn.sendmsg). More types may be added to this enum; do not /// exhaustively pattern-match it. /// -/// [Further reading](https://man7.org/linux/man-pages/man3/cmsg.3.html) +/// [Further reading](http://man7.org/linux/man-pages/man3/cmsg.3.html) #[derive(Clone, Copy, Debug, Eq, PartialEq)] -#[non_exhaustive] pub enum ControlMessage<'a> { /// A message of type `SCM_RIGHTS`, containing an array of file /// descriptors passed between processes. /// /// See the description in the "Ancillary messages" section of the - /// [unix(7) man page](https://man7.org/linux/man-pages/man7/unix.7.html). + /// [unix(7) man page](http://man7.org/linux/man-pages/man7/unix.7.html). /// /// Using multiple `ScmRights` messages for a single `sendmsg` call isn't /// recommended since it causes platform-dependent behaviour: It might @@ -830,7 +719,7 @@ pub enum ControlMessage<'a> { /// processes are verified by the kernel. /// /// For further information, please refer to the - /// [`unix(7)`](https://man7.org/linux/man-pages/man7/unix.7.html) man page. + /// [`unix(7)`](http://man7.org/linux/man-pages/man7/unix.7.html) man page. #[cfg(any(target_os = "android", target_os = "linux"))] ScmCredentials(&'a UnixCredentials), /// A message of type `SCM_CREDS`, containing the pid, uid, euid, gid and groups of @@ -841,7 +730,7 @@ pub enum ControlMessage<'a> { /// /// Credentials are always overwritten by the kernel, so this variant does have /// any data, unlike the receive-side - /// [`ControlMessageOwned::ScmCreds`]. + /// [`ControlMessageOwned::ScmCreds`][#enum.ControlMessageOwned.html#variant.ScmCreds]. /// /// For further information, please refer to the /// [`unix(4)`](https://www.freebsd.org/cgi/man.cgi?query=unix) man page. @@ -892,7 +781,7 @@ pub enum ControlMessage<'a> { /// Configure the sending addressing and interface for v4 /// /// For further information, please refer to the - /// [`ip(7)`](https://man7.org/linux/man-pages/man7/ip.7.html) man page. + /// [`ip(7)`](http://man7.org/linux/man-pages/man7/ip.7.html) man page. #[cfg(any(target_os = "linux", target_os = "macos", target_os = "netbsd", @@ -903,7 +792,7 @@ pub enum ControlMessage<'a> { /// Configure the sending addressing and interface for v6 /// /// For further information, please refer to the - /// [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html) man page. + /// [`ipv6(7)`](http://man7.org/linux/man-pages/man7/ipv6.7.html) man page. #[cfg(any(target_os = "linux", target_os = "macos", target_os = "netbsd", @@ -911,14 +800,6 @@ pub enum ControlMessage<'a> { target_os = "android", target_os = "ios",))] Ipv6PacketInfo(&'a libc::in6_pktinfo), - - /// SO_RXQ_OVFL indicates that an unsigned 32 bit value - /// ancilliary msg (cmsg) should be attached to recieved - /// skbs indicating the number of packets dropped by the - /// socket between the last recieved packet and this - /// received packet. - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - RxqOvfl(&'a u32), } // An opaque structure used to prevent cmsghdr from being a public type @@ -1009,10 +890,6 @@ impl<'a> ControlMessage<'a> { target_os = "netbsd", target_os = "freebsd", target_os = "android", target_os = "ios",))] ControlMessage::Ipv6PacketInfo(info) => info as *const _ as *const u8, - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - ControlMessage::RxqOvfl(drop_count) => { - drop_count as *const _ as *const u8 - }, }; unsafe { ptr::copy_nonoverlapping( @@ -1061,10 +938,6 @@ impl<'a> ControlMessage<'a> { target_os = "netbsd", target_os = "freebsd", target_os = "android", target_os = "ios",))] ControlMessage::Ipv6PacketInfo(info) => mem::size_of_val(info), - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - ControlMessage::RxqOvfl(drop_count) => { - mem::size_of_val(drop_count) - }, } } @@ -1089,8 +962,6 @@ impl<'a> ControlMessage<'a> { target_os = "netbsd", target_os = "freebsd", target_os = "android", target_os = "ios",))] ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6, - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - ControlMessage::RxqOvfl(_) => libc::SOL_SOCKET, } } @@ -1126,10 +997,6 @@ impl<'a> ControlMessage<'a> { target_os = "netbsd", target_os = "freebsd", target_os = "android", target_os = "ios",))] ControlMessage::Ipv6PacketInfo(_) => libc::IPV6_PKTINFO, - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - ControlMessage::RxqOvfl(_) => { - libc::SO_RXQ_OVFL - }, } } @@ -1222,22 +1089,23 @@ pub fn sendmmsg<'a, I, C>( let mut output = Vec::<libc::mmsghdr>::with_capacity(reserve_items); - let mut cmsgs_buffers = Vec::<Vec<u8>>::with_capacity(reserve_items); + let mut cmsgs_buffer = vec![0u8; 0]; for d in iter { - let capacity: usize = d.cmsgs.as_ref().iter().map(|c| c.space()).sum(); - let mut cmsgs_buffer = vec![0u8; capacity]; + let cmsgs_start = cmsgs_buffer.len(); + let cmsgs_required_capacity: usize = d.cmsgs.as_ref().iter().map(|c| c.space()).sum(); + let cmsgs_buffer_need_capacity = cmsgs_start + cmsgs_required_capacity; + cmsgs_buffer.resize(cmsgs_buffer_need_capacity, 0); output.push(libc::mmsghdr { msg_hdr: pack_mhdr_to_send( - &mut cmsgs_buffer, + &mut cmsgs_buffer[cmsgs_start..], &d.iov, &d.cmsgs, d.addr.as_ref() ), msg_len: 0, }); - cmsgs_buffers.push(cmsgs_buffer); }; let ret = unsafe { libc::sendmmsg(fd, output.as_mut_ptr(), output.len() as _, flags.bits() as _) }; @@ -1300,7 +1168,6 @@ pub struct RecvMmsgData<'a, I> target_os = "freebsd", target_os = "netbsd", ))] -#[allow(clippy::needless_collect)] // Complicated false positive pub fn recvmmsg<'a, I>( fd: RawFd, data: impl std::iter::IntoIterator<Item=&'a mut RecvMmsgData<'a, I>, @@ -1511,7 +1378,7 @@ fn pack_mhdr_to_send<'a, I, C>( /// * `flags`: Optional flags passed directly to the operating system. /// /// # References -/// [recvmsg(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html) +/// [recvmsg(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html) pub fn recvmsg<'a>(fd: RawFd, iov: &[IoVec<&mut [u8]>], mut cmsg_buffer: Option<&'a mut Vec<u8>>, flags: MsgFlags) -> Result<RecvMsg<'a>> @@ -1539,7 +1406,7 @@ pub fn recvmsg<'a>(fd: RawFd, iov: &[IoVec<&mut [u8]>], /// protocols may exist, in which case a particular protocol must be /// specified in this manner. /// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html) +/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html) pub fn socket<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType, flags: SockFlag, protocol: T) -> Result<RawFd> { let protocol = match protocol.into() { None => 0, @@ -1559,7 +1426,7 @@ pub fn socket<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType /// Create a pair of connected sockets /// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html) +/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html) pub fn socketpair<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType, protocol: T, flags: SockFlag) -> Result<(RawFd, RawFd)> { let protocol = match protocol.into() { @@ -1583,7 +1450,7 @@ pub fn socketpair<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: Sock /// Listen for connections on a socket /// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html) +/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html) pub fn listen(sockfd: RawFd, backlog: usize) -> Result<()> { let res = unsafe { libc::listen(sockfd, backlog as c_int) }; @@ -1592,7 +1459,7 @@ pub fn listen(sockfd: RawFd, backlog: usize) -> Result<()> { /// Bind a name to a socket /// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html) +/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html) pub fn bind(fd: RawFd, addr: &SockAddr) -> Result<()> { let res = unsafe { let (ptr, len) = addr.as_ffi_pair(); @@ -1604,7 +1471,7 @@ pub fn bind(fd: RawFd, addr: &SockAddr) -> Result<()> { /// Accept a connection on a socket /// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html) +/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html) pub fn accept(sockfd: RawFd) -> Result<RawFd> { let res = unsafe { libc::accept(sockfd, ptr::null_mut(), ptr::null_mut()) }; @@ -1613,15 +1480,8 @@ pub fn accept(sockfd: RawFd) -> Result<RawFd> { /// Accept a connection on a socket /// -/// [Further reading](https://man7.org/linux/man-pages/man2/accept.2.html) -#[cfg(any(all( - target_os = "android", - any( - target_arch = "aarch64", - target_arch = "x86", - target_arch = "x86_64" - ) - ), +/// [Further reading](http://man7.org/linux/man-pages/man2/accept.2.html) +#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux", target_os = "openbsd"))] @@ -1633,7 +1493,7 @@ pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> { /// Initiate a connection on a socket /// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html) +/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html) pub fn connect(fd: RawFd, addr: &SockAddr) -> Result<()> { let res = unsafe { let (ptr, len) = addr.as_ffi_pair(); @@ -1646,7 +1506,7 @@ pub fn connect(fd: RawFd, addr: &SockAddr) -> Result<()> { /// Receive data from a connection-oriented socket. Returns the number of /// bytes read /// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html) +/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html) pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> { unsafe { let ret = libc::recv( @@ -1663,7 +1523,7 @@ pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> { /// the number of bytes read and, for connectionless sockets, the socket /// address of the sender. /// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html) +/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html) pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) -> Result<(usize, Option<SockAddr>)> { @@ -1680,7 +1540,7 @@ pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) &mut len as *mut socklen_t))? as usize; match sockaddr_storage_to_addr(&addr, len as usize) { - Err(Errno::ENOTCONN) => Ok((ret, None)), + Err(Error::Sys(Errno::ENOTCONN)) => Ok((ret, None)), Ok(addr) => Ok((ret, Some(addr))), Err(e) => Err(e) } @@ -1689,7 +1549,7 @@ pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) /// Send a message to a socket /// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html) +/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html) pub fn sendto(fd: RawFd, buf: &[u8], addr: &SockAddr, flags: MsgFlags) -> Result<usize> { let ret = unsafe { let (ptr, len) = addr.as_ffi_pair(); @@ -1701,7 +1561,7 @@ pub fn sendto(fd: RawFd, buf: &[u8], addr: &SockAddr, flags: MsgFlags) -> Result /// Send data to a connection-oriented socket. Returns the number of bytes read /// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html) +/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html) pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result<usize> { let ret = unsafe { libc::send(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, flags.bits()) @@ -1716,32 +1576,34 @@ pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result<usize> { * */ -/// Represents a socket option that can be retrieved. +/// Represents a socket option that can be accessed or set. Used as an argument +/// to `getsockopt` pub trait GetSockOpt : Copy { type Val; - /// Look up the value of this socket option on the given socket. + #[doc(hidden)] fn get(&self, fd: RawFd) -> Result<Self::Val>; } -/// Represents a socket option that can be set. +/// Represents a socket option that can be accessed or set. Used as an argument +/// to `setsockopt` pub trait SetSockOpt : Clone { type Val; - /// Set the value of this socket option on the given socket. + #[doc(hidden)] fn set(&self, fd: RawFd, val: &Self::Val) -> Result<()>; } /// Get the current value for the requested socket option /// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html) +/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html) pub fn getsockopt<O: GetSockOpt>(fd: RawFd, opt: O) -> Result<O::Val> { opt.get(fd) } /// Sets the value for the requested socket option /// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html) +/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html) /// /// # Examples /// @@ -1762,7 +1624,7 @@ pub fn setsockopt<O: SetSockOpt>(fd: RawFd, opt: O, val: &O::Val) -> Result<()> /// Get the address of the peer connected to the socket `fd`. /// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html) +/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html) pub fn getpeername(fd: RawFd) -> Result<SockAddr> { unsafe { let mut addr = mem::MaybeUninit::uninit(); @@ -1782,7 +1644,7 @@ pub fn getpeername(fd: RawFd) -> Result<SockAddr> { /// Get the current address to which the socket `fd` is bound. /// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html) +/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html) pub fn getsockname(fd: RawFd) -> Result<SockAddr> { unsafe { let mut addr = mem::MaybeUninit::uninit(); @@ -1812,21 +1674,21 @@ pub fn sockaddr_storage_to_addr( addr: &sockaddr_storage, len: usize) -> Result<SockAddr> { - assert!(len <= mem::size_of::<sockaddr_storage>()); + assert!(len <= mem::size_of::<sockaddr_un>()); if len < mem::size_of_val(&addr.ss_family) { - return Err(Errno::ENOTCONN); + return Err(Error::Sys(Errno::ENOTCONN)); } match c_int::from(addr.ss_family) { libc::AF_INET => { - assert!(len as usize >= mem::size_of::<sockaddr_in>()); + assert_eq!(len as usize, mem::size_of::<sockaddr_in>()); let sin = unsafe { *(addr as *const sockaddr_storage as *const sockaddr_in) }; Ok(SockAddr::Inet(InetAddr::V4(sin))) } libc::AF_INET6 => { - assert!(len as usize >= mem::size_of::<sockaddr_in6>()); + assert_eq!(len as usize, mem::size_of::<sockaddr_in6>()); let sin6 = unsafe { *(addr as *const _ as *const sockaddr_in6) }; @@ -1834,18 +1696,15 @@ pub fn sockaddr_storage_to_addr( } libc::AF_UNIX => { let pathlen = len - offset_of!(sockaddr_un, sun_path); - unsafe { - let sun = *(addr as *const _ as *const sockaddr_un); - Ok(SockAddr::Unix(UnixAddr::from_raw_parts(sun, pathlen))) - } + let sun = unsafe { + *(addr as *const _ as *const sockaddr_un) + }; + Ok(SockAddr::Unix(UnixAddr(sun, pathlen))) } #[cfg(any(target_os = "android", target_os = "linux"))] libc::AF_PACKET => { use libc::sockaddr_ll; - // Don't assert anything about the size. - // Apparently the Linux kernel can return smaller sizes when - // the value in the last element of sockaddr_ll (`sll_addr`) is - // smaller than the declared size of that field + assert_eq!(len as usize, mem::size_of::<sockaddr_ll>()); let sll = unsafe { *(addr as *const _ as *const sockaddr_ll) }; @@ -1892,7 +1751,7 @@ pub enum Shutdown { /// Shut down part of a full-duplex connection. /// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html) +/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html) pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> { unsafe { use libc::shutdown; @@ -1906,11 +1765,3 @@ pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> { Errno::result(shutdown(df, how)).map(drop) } } - -#[cfg(test)] -mod tests { - #[test] - fn can_use_cmsg_space() { - let _ = cmsg_space!(u8); - } -} diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index fcb4be8..5b7b4fe 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -1,4 +1,3 @@ -//! Socket options as used by `setsockopt` and `getsockopt`. use cfg_if::cfg_if; use super::{GetSockOpt, SetSockOpt}; use crate::Result; @@ -31,7 +30,7 @@ const TCP_CA_NAME_MAX: usize = 16; /// # Arguments /// /// * `$name:ident`: name of the type you want to implement `SetSockOpt` for. -/// * `$level:expr` : socket layer, or a `protocol level`: could be *raw sockets* +/// * `$level:path` : socket layer, or a `protocol level`: could be *raw sockets* /// (`libc::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), /// and more. Please refer to your system manual for more options. Will be passed as the second /// argument (`level`) to the `setsockopt` call. @@ -42,7 +41,7 @@ const TCP_CA_NAME_MAX: usize = 16; /// * Type that implements the `Set` trait for the type from the previous item (like `SetBool` for /// `bool`, `SetUsize` for `usize`, etc.). macro_rules! setsockopt_impl { - ($name:ident, $level:expr, $flag:path, $ty:ty, $setter:ty) => { + ($name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => { impl SetSockOpt for $name { type Val = $ty; @@ -83,7 +82,7 @@ macro_rules! setsockopt_impl { /// * Type that implements the `Get` trait for the type from the previous item (`GetBool` for /// `bool`, `GetUsize` for `usize`, etc.). macro_rules! getsockopt_impl { - ($name:ident, $level:expr, $flag:path, $ty:ty, $getter:ty) => { + ($name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => { impl GetSockOpt for $name { type Val = $ty; @@ -118,7 +117,7 @@ macro_rules! getsockopt_impl { /// * `GetOnly`, `SetOnly` or `Both`: whether you want to implement only getter, only setter or /// both of them. /// * `$name:ident`: name of type `GetSockOpt`/`SetSockOpt` will be implemented for. -/// * `$level:expr` : socket layer, or a `protocol level`: could be *raw sockets* +/// * `$level:path` : socket layer, or a `protocol level`: could be *raw sockets* /// (`lic::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), /// and more. Please refer to your system manual for more options. Will be passed as the second /// argument (`level`) to the `getsockopt`/`setsockopt` call. @@ -129,99 +128,73 @@ macro_rules! getsockopt_impl { /// * `$getter:ty`: `Get` implementation; optional; only for `GetOnly` and `Both`. /// * `$setter:ty`: `Set` implementation; optional; only for `SetOnly` and `Both`. macro_rules! sockopt_impl { - ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, bool) => { - sockopt_impl!($(#[$attr])* - $name, GetOnly, $level, $flag, bool, GetBool); + (GetOnly, $name:ident, $level:path, $flag:path, bool) => { + sockopt_impl!(GetOnly, $name, $level, $flag, bool, GetBool); }; - ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, u8) => { - sockopt_impl!($(#[$attr])* $name, GetOnly, $level, $flag, u8, GetU8); + (GetOnly, $name:ident, $level:path, $flag:path, u8) => { + sockopt_impl!(GetOnly, $name, $level, $flag, u8, GetU8); }; - ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, usize) => - { - sockopt_impl!($(#[$attr])* - $name, GetOnly, $level, $flag, usize, GetUsize); + (GetOnly, $name:ident, $level:path, $flag:path, usize) => { + sockopt_impl!(GetOnly, $name, $level, $flag, usize, GetUsize); }; - ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, bool) => { - sockopt_impl!($(#[$attr])* - $name, SetOnly, $level, $flag, bool, SetBool); + (SetOnly, $name:ident, $level:path, $flag:path, bool) => { + sockopt_impl!(SetOnly, $name, $level, $flag, bool, SetBool); }; - ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, u8) => { - sockopt_impl!($(#[$attr])* $name, SetOnly, $level, $flag, u8, SetU8); + (SetOnly, $name:ident, $level:path, $flag:path, u8) => { + sockopt_impl!(SetOnly, $name, $level, $flag, u8, SetU8); }; - ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, usize) => - { - sockopt_impl!($(#[$attr])* - $name, SetOnly, $level, $flag, usize, SetUsize); + (SetOnly, $name:ident, $level:path, $flag:path, usize) => { + sockopt_impl!(SetOnly, $name, $level, $flag, usize, SetUsize); }; - ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, bool) => { - sockopt_impl!($(#[$attr])* - $name, Both, $level, $flag, bool, GetBool, SetBool); + (Both, $name:ident, $level:path, $flag:path, bool) => { + sockopt_impl!(Both, $name, $level, $flag, bool, GetBool, SetBool); }; - ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, u8) => { - sockopt_impl!($(#[$attr])* - $name, Both, $level, $flag, u8, GetU8, SetU8); + (Both, $name:ident, $level:path, $flag:path, u8) => { + sockopt_impl!(Both, $name, $level, $flag, u8, GetU8, SetU8); }; - ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, usize) => { - sockopt_impl!($(#[$attr])* - $name, Both, $level, $flag, usize, GetUsize, SetUsize); + (Both, $name:ident, $level:path, $flag:path, usize) => { + sockopt_impl!(Both, $name, $level, $flag, usize, GetUsize, SetUsize); }; - ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, - OsString<$array:ty>) => - { - sockopt_impl!($(#[$attr])* - $name, Both, $level, $flag, OsString, GetOsString<$array>, - SetOsString); + (Both, $name:ident, $level:path, $flag:path, OsString<$array:ty>) => { + sockopt_impl!(Both, $name, $level, $flag, OsString, GetOsString<$array>, SetOsString); }; /* * Matchers with generic getter types must be placed at the end, so * they'll only match _after_ specialized matchers fail */ - ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty) => - { - sockopt_impl!($(#[$attr])* - $name, GetOnly, $level, $flag, $ty, GetStruct<$ty>); + (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => { + sockopt_impl!(GetOnly, $name, $level, $flag, $ty, GetStruct<$ty>); }; - ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty, - $getter:ty) => - { - $(#[$attr])* + (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => { #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct $name; getsockopt_impl!($name, $level, $flag, $ty, $getter); }; - ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty) => - { - sockopt_impl!($(#[$attr])* - $name, SetOnly, $level, $flag, $ty, SetStruct<$ty>); + (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => { + sockopt_impl!(SetOnly, $name, $level, $flag, $ty, SetStruct<$ty>); }; - ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty, - $setter:ty) => - { - $(#[$attr])* + (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => { #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct $name; setsockopt_impl!($name, $level, $flag, $ty, $setter); }; - ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty, - $getter:ty, $setter:ty) => - { - $(#[$attr])* + (Both, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty, $setter:ty) => { #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct $name; @@ -229,10 +202,8 @@ macro_rules! sockopt_impl { getsockopt_impl!($name, $level, $flag, $ty, $getter); }; - ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty) => { - sockopt_impl!($(#[$attr])* - $name, Both, $level, $flag, $ty, GetStruct<$ty>, - SetStruct<$ty>); + (Both, $name:ident, $level:path, $flag:path, $ty:ty) => { + sockopt_impl!(Both, $name, $level, $flag, $ty, GetStruct<$ty>, SetStruct<$ty>); }; } @@ -242,232 +213,74 @@ macro_rules! sockopt_impl { * */ -sockopt_impl!( - /// Enables local address reuse - ReuseAddr, Both, libc::SOL_SOCKET, libc::SO_REUSEADDR, bool -); -#[cfg(not(any(target_os = "illumos", target_os = "solaris")))] -sockopt_impl!( - /// Permits multiple AF_INET or AF_INET6 sockets to be bound to an - /// identical socket address. - ReusePort, Both, libc::SOL_SOCKET, libc::SO_REUSEPORT, bool); -sockopt_impl!( - /// Under most circumstances, TCP sends data when it is presented; when - /// outstanding data has not yet been acknowledged, it gathers small amounts - /// of output to be sent in a single packet once an acknowledgement is - /// received. For a small number of clients, such as window systems that - /// send a stream of mouse events which receive no replies, this - /// packetization may cause significant delays. The boolean option - /// TCP_NODELAY defeats this algorithm. - TcpNoDelay, Both, libc::IPPROTO_TCP, libc::TCP_NODELAY, bool); -sockopt_impl!( - /// When enabled, a close(2) or shutdown(2) will not return until all - /// queued messages for the socket have been successfully sent or the - /// linger timeout has been reached. - Linger, Both, libc::SOL_SOCKET, libc::SO_LINGER, libc::linger); -sockopt_impl!( - /// Join a multicast group - IpAddMembership, SetOnly, libc::IPPROTO_IP, libc::IP_ADD_MEMBERSHIP, - super::IpMembershipRequest); -sockopt_impl!( - /// Leave a multicast group. - IpDropMembership, SetOnly, libc::IPPROTO_IP, libc::IP_DROP_MEMBERSHIP, - super::IpMembershipRequest); +sockopt_impl!(Both, ReuseAddr, libc::SOL_SOCKET, libc::SO_REUSEADDR, bool); +sockopt_impl!(Both, ReusePort, libc::SOL_SOCKET, libc::SO_REUSEPORT, bool); +sockopt_impl!(Both, TcpNoDelay, libc::IPPROTO_TCP, libc::TCP_NODELAY, bool); +sockopt_impl!(Both, Linger, libc::SOL_SOCKET, libc::SO_LINGER, libc::linger); +sockopt_impl!(SetOnly, IpAddMembership, libc::IPPROTO_IP, libc::IP_ADD_MEMBERSHIP, super::IpMembershipRequest); +sockopt_impl!(SetOnly, IpDropMembership, libc::IPPROTO_IP, libc::IP_DROP_MEMBERSHIP, super::IpMembershipRequest); cfg_if! { if #[cfg(any(target_os = "android", target_os = "linux"))] { - sockopt_impl!( - /// Join an IPv6 multicast group. - Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_ADD_MEMBERSHIP, super::Ipv6MembershipRequest); - sockopt_impl!( - /// Leave an IPv6 multicast group. - Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest); + sockopt_impl!(SetOnly, Ipv6AddMembership, libc::IPPROTO_IPV6, libc::IPV6_ADD_MEMBERSHIP, super::Ipv6MembershipRequest); + sockopt_impl!(SetOnly, Ipv6DropMembership, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest); } else if #[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "illumos", target_os = "ios", target_os = "macos", target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] { - sockopt_impl!( - /// Join an IPv6 multicast group. - Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6, - libc::IPV6_JOIN_GROUP, super::Ipv6MembershipRequest); - sockopt_impl!( - /// Leave an IPv6 multicast group. - Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6, - libc::IPV6_LEAVE_GROUP, super::Ipv6MembershipRequest); + target_os = "openbsd"))] { + sockopt_impl!(SetOnly, Ipv6AddMembership, libc::IPPROTO_IPV6, libc::IPV6_JOIN_GROUP, super::Ipv6MembershipRequest); + sockopt_impl!(SetOnly, Ipv6DropMembership, libc::IPPROTO_IPV6, libc::IPV6_LEAVE_GROUP, super::Ipv6MembershipRequest); } } -sockopt_impl!( - /// Set or read the time-to-live value of outgoing multicast packets for - /// this socket. - IpMulticastTtl, Both, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, u8); -sockopt_impl!( - /// Set or read a boolean integer argument that determines whether sent - /// multicast packets should be looped back to the local sockets. - IpMulticastLoop, Both, libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP, bool); -#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] -sockopt_impl!( - /// If enabled, this boolean option allows binding to an IP address that - /// is nonlocal or does not (yet) exist. - IpFreebind, Both, libc::IPPROTO_IP, libc::IP_FREEBIND, bool); -sockopt_impl!( - /// Specify the receiving timeout until reporting an error. - ReceiveTimeout, Both, libc::SOL_SOCKET, libc::SO_RCVTIMEO, TimeVal); -sockopt_impl!( - /// Specify the sending timeout until reporting an error. - SendTimeout, Both, libc::SOL_SOCKET, libc::SO_SNDTIMEO, TimeVal); -sockopt_impl!( - /// Set or get the broadcast flag. - Broadcast, Both, libc::SOL_SOCKET, libc::SO_BROADCAST, bool); -sockopt_impl!( - /// If this option is enabled, out-of-band data is directly placed into - /// the receive data stream. - OobInline, Both, libc::SOL_SOCKET, libc::SO_OOBINLINE, bool); -sockopt_impl!( - /// Get and clear the pending socket error. - SocketError, GetOnly, libc::SOL_SOCKET, libc::SO_ERROR, i32); -sockopt_impl!( - /// Enable sending of keep-alive messages on connection-oriented sockets. - KeepAlive, Both, libc::SOL_SOCKET, libc::SO_KEEPALIVE, bool); -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "ios" -))] -sockopt_impl!( - /// Get the credentials of the peer process of a connected unix domain - /// socket. - LocalPeerCred, GetOnly, 0, libc::LOCAL_PEERCRED, super::XuCred); +sockopt_impl!(Both, IpMulticastTtl, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, u8); +sockopt_impl!(Both, IpMulticastLoop, libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP, bool); +sockopt_impl!(Both, ReceiveTimeout, libc::SOL_SOCKET, libc::SO_RCVTIMEO, TimeVal); +sockopt_impl!(Both, SendTimeout, libc::SOL_SOCKET, libc::SO_SNDTIMEO, TimeVal); +sockopt_impl!(Both, Broadcast, libc::SOL_SOCKET, libc::SO_BROADCAST, bool); +sockopt_impl!(Both, OobInline, libc::SOL_SOCKET, libc::SO_OOBINLINE, bool); +sockopt_impl!(GetOnly, SocketError, libc::SOL_SOCKET, libc::SO_ERROR, i32); +sockopt_impl!(Both, KeepAlive, libc::SOL_SOCKET, libc::SO_KEEPALIVE, bool); #[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - /// Return the credentials of the foreign process connected to this socket. - PeerCredentials, GetOnly, libc::SOL_SOCKET, libc::SO_PEERCRED, super::UnixCredentials); +sockopt_impl!(GetOnly, PeerCredentials, libc::SOL_SOCKET, libc::SO_PEERCRED, super::UnixCredentials); #[cfg(any(target_os = "ios", target_os = "macos"))] -sockopt_impl!( - /// Specify the amount of time, in seconds, that the connection must be idle - /// before keepalive probes (if enabled) are sent. - TcpKeepAlive, Both, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, u32); +sockopt_impl!(Both, TcpKeepAlive, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, u32); #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux", target_os = "nacl"))] -sockopt_impl!( - /// The time (in seconds) the connection needs to remain idle before TCP - /// starts sending keepalive probes - TcpKeepIdle, Both, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, u32); -cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { - sockopt_impl!( - /// The maximum segment size for outgoing TCP packets. - TcpMaxSeg, Both, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32); - } else { - sockopt_impl!( - /// The maximum segment size for outgoing TCP packets. - TcpMaxSeg, GetOnly, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32); - } -} +sockopt_impl!(Both, TcpKeepIdle, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, u32); #[cfg(not(target_os = "openbsd"))] -sockopt_impl!( - /// The maximum number of keepalive probes TCP should send before - /// dropping the connection. - TcpKeepCount, Both, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, u32); -#[cfg(any(target_os = "android", - target_os = "fuchsia", - target_os = "linux"))] -sockopt_impl!( - #[allow(missing_docs)] - // Not documented by Linux! - TcpRepair, Both, libc::IPPROTO_TCP, libc::TCP_REPAIR, u32); +sockopt_impl!(Both, TcpKeepCount, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, u32); #[cfg(not(target_os = "openbsd"))] -sockopt_impl!( - /// The time (in seconds) between individual keepalive probes. - TcpKeepInterval, Both, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, u32); -#[cfg(any(target_os = "fuchsia", target_os = "linux"))] -sockopt_impl!( - /// Specifies the maximum amount of time in milliseconds that transmitted - /// data may remain unacknowledged before TCP will forcibly close the - /// corresponding connection - TcpUserTimeout, Both, libc::IPPROTO_TCP, libc::TCP_USER_TIMEOUT, u32); -sockopt_impl!( - /// Sets or gets the maximum socket receive buffer in bytes. - RcvBuf, Both, libc::SOL_SOCKET, libc::SO_RCVBUF, usize); -sockopt_impl!( - /// Sets or gets the maximum socket send buffer in bytes. - SndBuf, Both, libc::SOL_SOCKET, libc::SO_SNDBUF, usize); -#[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - /// Using this socket option, a privileged (`CAP_NET_ADMIN`) process can - /// perform the same task as `SO_RCVBUF`, but the `rmem_max limit` can be - /// overridden. - RcvBufForce, SetOnly, libc::SOL_SOCKET, libc::SO_RCVBUFFORCE, usize); +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); #[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - /// Using this socket option, a privileged (`CAP_NET_ADMIN`) process can - /// perform the same task as `SO_SNDBUF`, but the `wmem_max` limit can be - /// overridden. - SndBufForce, SetOnly, libc::SOL_SOCKET, libc::SO_SNDBUFFORCE, usize); -sockopt_impl!( - /// Gets the socket type as an integer. - SockType, GetOnly, libc::SOL_SOCKET, libc::SO_TYPE, super::SockType); -sockopt_impl!( - /// Returns a value indicating whether or not this socket has been marked to - /// accept connections with `listen(2)`. - AcceptConn, GetOnly, libc::SOL_SOCKET, libc::SO_ACCEPTCONN, bool); +sockopt_impl!(SetOnly, RcvBufForce, libc::SOL_SOCKET, libc::SO_RCVBUFFORCE, usize); #[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - /// Bind this socket to a particular device like “eth0”. - BindToDevice, Both, libc::SOL_SOCKET, libc::SO_BINDTODEVICE, OsString<[u8; libc::IFNAMSIZ]>); +sockopt_impl!(SetOnly, SndBufForce, libc::SOL_SOCKET, libc::SO_SNDBUFFORCE, usize); +sockopt_impl!(GetOnly, SockType, libc::SOL_SOCKET, libc::SO_TYPE, super::SockType); +sockopt_impl!(GetOnly, AcceptConn, libc::SOL_SOCKET, libc::SO_ACCEPTCONN, bool); #[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - #[allow(missing_docs)] - // Not documented by Linux! - OriginalDst, GetOnly, libc::SOL_IP, libc::SO_ORIGINAL_DST, libc::sockaddr_in); +sockopt_impl!(Both, BindToDevice, libc::SOL_SOCKET, libc::SO_BINDTODEVICE, OsString<[u8; libc::IFNAMSIZ]>); #[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - #[allow(missing_docs)] - // Not documented by Linux! - Ip6tOriginalDst, GetOnly, libc::SOL_IPV6, libc::IP6T_SO_ORIGINAL_DST, libc::sockaddr_in6); -sockopt_impl!( - /// Enable or disable the receiving of the `SO_TIMESTAMP` control message. - ReceiveTimestamp, Both, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool); -#[cfg(all(target_os = "linux"))] -sockopt_impl!( - /// Enable or disable the receiving of the `SO_TIMESTAMPNS` control message. - ReceiveTimestampns, Both, libc::SOL_SOCKET, libc::SO_TIMESTAMPNS, bool); +sockopt_impl!(GetOnly, OriginalDst, libc::SOL_IP, libc::SO_ORIGINAL_DST, libc::sockaddr_in); +sockopt_impl!(Both, ReceiveTimestamp, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool); #[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - /// Setting this boolean option enables transparent proxying on this socket. - IpTransparent, Both, libc::SOL_IP, libc::IP_TRANSPARENT, bool); +sockopt_impl!(Both, IpTransparent, libc::SOL_IP, libc::IP_TRANSPARENT, bool); #[cfg(target_os = "openbsd")] -sockopt_impl!( - /// Allows the socket to be bound to addresses which are not local to the - /// machine, so it can be used to make a transparent proxy. - BindAny, Both, libc::SOL_SOCKET, libc::SO_BINDANY, bool); +sockopt_impl!(Both, BindAny, libc::SOL_SOCKET, libc::SO_BINDANY, bool); #[cfg(target_os = "freebsd")] -sockopt_impl!( - /// Can `bind(2)` to any address, even one not bound to any available - /// network interface in the system. - BindAny, Both, libc::IPPROTO_IP, libc::IP_BINDANY, bool); +sockopt_impl!(Both, BindAny, libc::IPPROTO_IP, libc::IP_BINDANY, bool); #[cfg(target_os = "linux")] -sockopt_impl!( - /// Set the mark for each packet sent through this socket (similar to the - /// netfilter MARK target but socket-based). - Mark, Both, libc::SOL_SOCKET, libc::SO_MARK, u32); +sockopt_impl!(Both, Mark, libc::SOL_SOCKET, libc::SO_MARK, u32); #[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - /// Enable or disable the receiving of the `SCM_CREDENTIALS` control - /// message. - PassCred, Both, libc::SOL_SOCKET, libc::SO_PASSCRED, bool); +sockopt_impl!(Both, PassCred, libc::SOL_SOCKET, libc::SO_PASSCRED, bool); #[cfg(any(target_os = "freebsd", target_os = "linux"))] -sockopt_impl!( - /// This option allows the caller to set the TCP congestion control - /// algorithm to be used, on a per-socket basis. - TcpCongestion, Both, libc::IPPROTO_TCP, libc::TCP_CONGESTION, OsString<[u8; TCP_CA_NAME_MAX]>); +sockopt_impl!(Both, TcpCongestion, libc::IPPROTO_TCP, libc::TCP_CONGESTION, OsString<[u8; TCP_CA_NAME_MAX]>); #[cfg(any( target_os = "android", target_os = "ios", @@ -475,10 +288,7 @@ sockopt_impl!( target_os = "macos", target_os = "netbsd", ))] -sockopt_impl!( - /// Pass an `IP_PKTINFO` ancillary message that contains a pktinfo - /// structure that supplies some information about the incoming packet. - Ipv4PacketInfo, Both, libc::IPPROTO_IP, libc::IP_PKTINFO, bool); +sockopt_impl!(Both, Ipv4PacketInfo, libc::IPPROTO_IP, libc::IP_PKTINFO, bool); #[cfg(any( target_os = "android", target_os = "freebsd", @@ -488,10 +298,7 @@ sockopt_impl!( target_os = "netbsd", target_os = "openbsd", ))] -sockopt_impl!( - /// Set delivery of the `IPV6_PKTINFO` control message on incoming - /// datagrams. - Ipv6RecvPacketInfo, Both, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO, bool); +sockopt_impl!(Both, Ipv6RecvPacketInfo, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO, bool); #[cfg(any( target_os = "freebsd", target_os = "ios", @@ -499,10 +306,7 @@ sockopt_impl!( target_os = "netbsd", target_os = "openbsd", ))] -sockopt_impl!( - /// The `recvmsg(2)` call returns a `struct sockaddr_dl` corresponding to - /// the interface on which the packet was received. - Ipv4RecvIf, Both, libc::IPPROTO_IP, libc::IP_RECVIF, bool); +sockopt_impl!(Both, Ipv4RecvIf, libc::IPPROTO_IP, libc::IP_RECVIF, bool); #[cfg(any( target_os = "freebsd", target_os = "ios", @@ -510,49 +314,12 @@ sockopt_impl!( target_os = "netbsd", target_os = "openbsd", ))] -sockopt_impl!( - /// The `recvmsg(2)` call will return the destination IP address for a UDP - /// datagram. - Ipv4RecvDstAddr, Both, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, bool); +sockopt_impl!(Both, Ipv4RecvDstAddr, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, bool); #[cfg(target_os = "linux")] -sockopt_impl!( - #[allow(missing_docs)] - // Not documented by Linux! - UdpGsoSegment, Both, libc::SOL_UDP, libc::UDP_SEGMENT, libc::c_int); +sockopt_impl!(Both, UdpGsoSegment, libc::SOL_UDP, libc::UDP_SEGMENT, libc::c_int); #[cfg(target_os = "linux")] -sockopt_impl!( - #[allow(missing_docs)] - // Not documented by Linux! - UdpGroSegment, Both, libc::IPPROTO_UDP, libc::UDP_GRO, bool); -#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] -sockopt_impl!( - /// Indicates that an unsigned 32-bit value ancillary message (cmsg) should - /// be attached to received skbs indicating the number of packets dropped by - /// the socket since its creation. - RxqOvfl, Both, libc::SOL_SOCKET, libc::SO_RXQ_OVFL, libc::c_int); -sockopt_impl!( - /// The socket is restricted to sending and receiving IPv6 packets only. - Ipv6V6Only, Both, libc::IPPROTO_IPV6, libc::IPV6_V6ONLY, bool); -#[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - /// Enable extended reliable error message passing. - Ipv4RecvErr, Both, libc::IPPROTO_IP, libc::IP_RECVERR, bool); -#[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - /// Control receiving of asynchronous error options. - Ipv6RecvErr, Both, libc::IPPROTO_IPV6, libc::IPV6_RECVERR, bool); -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] -sockopt_impl!( - /// Set or retrieve the current time-to-live field that is used in every - /// packet sent from this socket. - Ipv4Ttl, Both, libc::IPPROTO_IP, libc::IP_TTL, libc::c_int); -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] -sockopt_impl!( - /// Set the unicast hop limit for the socket. - Ipv6Ttl, Both, libc::IPPROTO_IPV6, libc::IPV6_UNICAST_HOPS, libc::c_int); - -#[allow(missing_docs)] -// Not documented by Linux! +sockopt_impl!(Both, UdpGroSegment, libc::IPPROTO_UDP, libc::UDP_GRO, bool); + #[cfg(any(target_os = "android", target_os = "linux"))] #[derive(Copy, Clone, Debug)] pub struct AlgSetAeadAuthSize; @@ -575,8 +342,6 @@ impl SetSockOpt for AlgSetAeadAuthSize { } } -#[allow(missing_docs)] -// Not documented by Linux! #[cfg(any(target_os = "android", target_os = "linux"))] #[derive(Clone, Debug)] pub struct AlgSetKey<T>(::std::marker::PhantomData<T>); @@ -611,9 +376,9 @@ impl<T> SetSockOpt for AlgSetKey<T> where T: AsRef<[u8]> + Clone { */ /// Helper trait that describes what is expected from a `GetSockOpt` getter. -trait Get<T> { +unsafe trait Get<T> { /// Returns an uninitialized value. - fn uninit() -> Self; + unsafe fn uninit() -> Self; /// Returns a pointer to the stored value. This pointer will be passed to the system's /// `getsockopt` call (`man 3p getsockopt`, argument `option_value`). fn ffi_ptr(&mut self) -> *mut c_void; @@ -625,7 +390,7 @@ trait Get<T> { } /// Helper trait that describes what is expected from a `SetSockOpt` setter. -trait Set<'a, T> { +unsafe trait Set<'a, T> { /// Initialize the setter with a given value. fn new(val: &'a T) -> Self; /// Returns a pointer to the stored value. This pointer will be passed to the system's @@ -642,8 +407,8 @@ struct GetStruct<T> { val: MaybeUninit<T>, } -impl<T> Get<T> for GetStruct<T> { - fn uninit() -> Self { +unsafe impl<T> Get<T> for GetStruct<T> { + unsafe fn uninit() -> Self { GetStruct { len: mem::size_of::<T>() as socklen_t, val: MaybeUninit::uninit(), @@ -669,7 +434,7 @@ struct SetStruct<'a, T: 'static> { ptr: &'a T, } -impl<'a, T> Set<'a, T> for SetStruct<'a, T> { +unsafe impl<'a, T> Set<'a, T> for SetStruct<'a, T> { fn new(ptr: &'a T) -> SetStruct<'a, T> { SetStruct { ptr } } @@ -689,8 +454,8 @@ struct GetBool { val: MaybeUninit<c_int>, } -impl Get<bool> for GetBool { - fn uninit() -> Self { +unsafe impl Get<bool> for GetBool { + unsafe fn uninit() -> Self { GetBool { len: mem::size_of::<c_int>() as socklen_t, val: MaybeUninit::uninit(), @@ -716,7 +481,7 @@ struct SetBool { val: c_int, } -impl<'a> Set<'a, bool> for SetBool { +unsafe impl<'a> Set<'a, bool> for SetBool { fn new(val: &'a bool) -> SetBool { SetBool { val: if *val { 1 } else { 0 } } } @@ -736,8 +501,8 @@ struct GetU8 { val: MaybeUninit<u8>, } -impl Get<u8> for GetU8 { - fn uninit() -> Self { +unsafe impl Get<u8> for GetU8 { + unsafe fn uninit() -> Self { GetU8 { len: mem::size_of::<u8>() as socklen_t, val: MaybeUninit::uninit(), @@ -763,7 +528,7 @@ struct SetU8 { val: u8, } -impl<'a> Set<'a, u8> for SetU8 { +unsafe impl<'a> Set<'a, u8> for SetU8 { fn new(val: &'a u8) -> SetU8 { SetU8 { val: *val as u8 } } @@ -783,8 +548,8 @@ struct GetUsize { val: MaybeUninit<c_int>, } -impl Get<usize> for GetUsize { - fn uninit() -> Self { +unsafe impl Get<usize> for GetUsize { + unsafe fn uninit() -> Self { GetUsize { len: mem::size_of::<c_int>() as socklen_t, val: MaybeUninit::uninit(), @@ -810,7 +575,7 @@ struct SetUsize { val: c_int, } -impl<'a> Set<'a, usize> for SetUsize { +unsafe impl<'a> Set<'a, usize> for SetUsize { fn new(val: &'a usize) -> SetUsize { SetUsize { val: *val as c_int } } @@ -830,8 +595,8 @@ struct GetOsString<T: AsMut<[u8]>> { val: MaybeUninit<T>, } -impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> { - fn uninit() -> Self { +unsafe impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> { + unsafe fn uninit() -> Self { GetOsString { len: mem::size_of::<T>() as socklen_t, val: MaybeUninit::uninit(), @@ -858,7 +623,7 @@ struct SetOsString<'a> { val: &'a OsStr, } -impl<'a> Set<'a, OsString> for SetOsString<'a> { +unsafe impl<'a> Set<'a, OsString> for SetOsString<'a> { fn new(val: &'a OsString) -> SetOsString { SetOsString { val: val.as_os_str() } } diff --git a/src/sys/stat.rs b/src/sys/stat.rs index c8f1041..df81a2c 100644 --- a/src/sys/stat.rs +++ b/src/sys/stat.rs @@ -9,7 +9,6 @@ use std::os::unix::io::RawFd; use crate::sys::time::{TimeSpec, TimeVal}; libc_bitflags!( - /// "File type" flags for `mknod` and related functions. pub struct SFlag: mode_t { S_IFIFO; S_IFCHR; @@ -23,7 +22,6 @@ libc_bitflags!( ); libc_bitflags! { - /// "File mode / permissions" flags. pub struct Mode: mode_t { S_IRWXU; S_IRUSR; @@ -43,45 +41,30 @@ libc_bitflags! { } } -/// Create a special or ordinary file, by pathname. pub fn mknod<P: ?Sized + NixPath>(path: &P, kind: SFlag, perm: Mode, dev: dev_t) -> Result<()> { - let res = path.with_nix_path(|cstr| unsafe { - libc::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev) - })?; - - Errno::result(res).map(drop) -} - -/// Create a special or ordinary file, relative to a given directory. -#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))] -pub fn mknodat<P: ?Sized + NixPath>( - dirfd: RawFd, - path: &P, - kind: SFlag, - perm: Mode, - dev: dev_t, -) -> Result<()> { - let res = path.with_nix_path(|cstr| unsafe { - libc::mknodat(dirfd, cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev) + let res = path.with_nix_path(|cstr| { + unsafe { + libc::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev) + } })?; Errno::result(res).map(drop) } #[cfg(target_os = "linux")] -pub const fn major(dev: dev_t) -> u64 { +pub fn major(dev: dev_t) -> u64 { ((dev >> 32) & 0xffff_f000) | ((dev >> 8) & 0x0000_0fff) } #[cfg(target_os = "linux")] -pub const fn minor(dev: dev_t) -> u64 { +pub fn minor(dev: dev_t) -> u64 { ((dev >> 12) & 0xffff_ff00) | ((dev ) & 0x0000_00ff) } #[cfg(target_os = "linux")] -pub const fn makedev(major: u64, minor: u64) -> dev_t { +pub fn makedev(major: u64, minor: u64) -> dev_t { ((major & 0xffff_f000) << 32) | ((major & 0x0000_0fff) << 8) | ((minor & 0xffff_ff00) << 12) | @@ -144,7 +127,7 @@ pub fn fstatat<P: ?Sized + NixPath>(dirfd: RawFd, pathname: &P, f: AtFlags) -> R /// /// # References /// -/// [fchmod(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmod.html). +/// [fchmod(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmod.html). pub fn fchmod(fd: RawFd, mode: Mode) -> Result<()> { let res = unsafe { libc::fchmod(fd, mode.bits() as mode_t) }; @@ -173,7 +156,7 @@ pub enum FchmodatFlags { /// /// # References /// -/// [fchmodat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html). +/// [fchmodat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html). #[cfg(not(target_os = "redox"))] pub fn fchmodat<P: ?Sized + NixPath>( dirfd: Option<RawFd>, @@ -207,7 +190,7 @@ pub fn fchmodat<P: ?Sized + NixPath>( /// /// # References /// -/// [utimes(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimes.html). +/// [utimes(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/utimes.html). pub fn utimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> { let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()]; let res = path.with_nix_path(|cstr| unsafe { @@ -226,7 +209,7 @@ pub fn utimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) - /// /// # References /// -/// [lutimes(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/lutimes.html). +/// [lutimes(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lutimes.html). #[cfg(any(target_os = "linux", target_os = "haiku", target_os = "ios", @@ -246,7 +229,7 @@ pub fn lutimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) /// /// # References /// -/// [futimens(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html). +/// [futimens(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html). #[inline] pub fn futimens(fd: RawFd, atime: &TimeSpec, mtime: &TimeSpec) -> Result<()> { let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()]; @@ -256,7 +239,6 @@ pub fn futimens(fd: RawFd, atime: &TimeSpec, mtime: &TimeSpec) -> Result<()> { } /// Flags for `utimensat` function. -// TODO: replace with fcntl::AtFlags #[derive(Clone, Copy, Debug)] pub enum UtimensatFlags { FollowSymlink, @@ -278,7 +260,7 @@ pub enum UtimensatFlags { /// /// # References /// -/// [utimensat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimens.html). +/// [utimensat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/utimens.html). #[cfg(not(target_os = "redox"))] pub fn utimensat<P: ?Sized + NixPath>( dirfd: Option<RawFd>, diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs index 829be57..27b7259 100644 --- a/src/sys/statfs.rs +++ b/src/sys/statfs.rs @@ -1,6 +1,3 @@ -//! Get filesystem statistics, non-portably -//! -//! See [`statvfs`](crate::sys::statvfs) for a portable alternative. use std::fmt::{self, Debug}; use std::mem; use std::os::unix::io::AsRawFd; @@ -9,14 +6,11 @@ use std::ffi::CStr; use crate::{NixPath, Result, errno::Errno}; -/// Identifies a mounted file system #[cfg(target_os = "android")] pub type fsid_t = libc::__fsid_t; -/// Identifies a mounted file system #[cfg(not(target_os = "android"))] pub type fsid_t = libc::fsid_t; -/// Describes a mounted file system #[derive(Clone, Copy)] #[repr(transparent)] pub struct Statfs(libc::statfs); @@ -32,7 +26,6 @@ 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; -/// Describes the file system type as known by the operating system. #[cfg(any( target_os = "freebsd", target_os = "android", @@ -43,94 +36,63 @@ type fs_type_t = libc::__fsword_t; #[derive(Eq, Copy, Clone, PartialEq, Debug)] pub struct FsType(pub fs_type_t); -// These constants are defined without documentation in the Linux headers, so we -// can't very well document them here. #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const ADFS_SUPER_MAGIC: FsType = FsType(libc::ADFS_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const AFFS_SUPER_MAGIC: FsType = FsType(libc::AFFS_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const CODA_SUPER_MAGIC: FsType = FsType(libc::CODA_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const CRAMFS_MAGIC: FsType = FsType(libc::CRAMFS_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const EFS_SUPER_MAGIC: FsType = FsType(libc::EFS_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const EXT2_SUPER_MAGIC: FsType = FsType(libc::EXT2_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const EXT3_SUPER_MAGIC: FsType = FsType(libc::EXT3_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const EXT4_SUPER_MAGIC: FsType = FsType(libc::EXT4_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const HPFS_SUPER_MAGIC: FsType = FsType(libc::HPFS_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const HUGETLBFS_MAGIC: FsType = FsType(libc::HUGETLBFS_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const ISOFS_SUPER_MAGIC: FsType = FsType(libc::ISOFS_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const JFFS2_SUPER_MAGIC: FsType = FsType(libc::JFFS2_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const MINIX_SUPER_MAGIC: FsType = FsType(libc::MINIX_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const MINIX_SUPER_MAGIC2: FsType = FsType(libc::MINIX_SUPER_MAGIC2 as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const MINIX2_SUPER_MAGIC: FsType = FsType(libc::MINIX2_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const MINIX2_SUPER_MAGIC2: FsType = FsType(libc::MINIX2_SUPER_MAGIC2 as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const MSDOS_SUPER_MAGIC: FsType = FsType(libc::MSDOS_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const NCP_SUPER_MAGIC: FsType = FsType(libc::NCP_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const NFS_SUPER_MAGIC: FsType = FsType(libc::NFS_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const OPENPROM_SUPER_MAGIC: FsType = FsType(libc::OPENPROM_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const OVERLAYFS_SUPER_MAGIC: FsType = FsType(libc::OVERLAYFS_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const PROC_SUPER_MAGIC: FsType = FsType(libc::PROC_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const QNX4_SUPER_MAGIC: FsType = FsType(libc::QNX4_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const REISERFS_SUPER_MAGIC: FsType = FsType(libc::REISERFS_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const SMB_SUPER_MAGIC: FsType = FsType(libc::SMB_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const TMPFS_MAGIC: FsType = FsType(libc::TMPFS_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const USBDEVICE_SUPER_MAGIC: FsType = FsType(libc::USBDEVICE_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const CGROUP_SUPER_MAGIC: FsType = FsType(libc::CGROUP_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] -#[allow(missing_docs)] pub const CGROUP2_SUPER_MAGIC: FsType = FsType(libc::CGROUP2_SUPER_MAGIC as fs_type_t); @@ -489,14 +451,6 @@ impl Debug for Statfs { } } -/// Describes a mounted file system. -/// -/// The result is OS-dependent. For a portabable alternative, see -/// [`statvfs`](crate::sys::statvfs::statvfs). -/// -/// # Arguments -/// -/// `path` - Path to any file within the file system to describe pub fn statfs<P: ?Sized + NixPath>(path: &P) -> Result<Statfs> { unsafe { let mut stat = mem::MaybeUninit::<libc::statfs>::uninit(); @@ -505,14 +459,6 @@ pub fn statfs<P: ?Sized + NixPath>(path: &P) -> Result<Statfs> { } } -/// Describes a mounted file system. -/// -/// The result is OS-dependent. For a portabable alternative, see -/// [`fstatvfs`](crate::sys::statvfs::fstatvfs). -/// -/// # Arguments -/// -/// `fd` - File descriptor of any open file within the file system to describe pub fn fstatfs<T: AsRawFd>(fd: &T) -> Result<Statfs> { unsafe { let mut stat = mem::MaybeUninit::<libc::statfs>::uninit(); diff --git a/src/sys/statvfs.rs b/src/sys/statvfs.rs index 15e7a7d..9bea973 100644 --- a/src/sys/statvfs.rs +++ b/src/sys/statvfs.rs @@ -1,6 +1,6 @@ //! Get filesystem statistics //! -//! See [the man pages](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatvfs.html) +//! See [the man pages](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatvfs.html) //! for more details. use std::mem; use std::os::unix::io::AsRawFd; @@ -54,7 +54,7 @@ libc_bitflags!( /// Wrapper around the POSIX `statvfs` struct /// -/// For more information see the [`statvfs(3)` man pages](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_statvfs.h.html). +/// For more information see the [`statvfs(3)` man pages](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_statvfs.h.html). #[repr(transparent)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct Statvfs(libc::statvfs); @@ -150,7 +150,7 @@ mod test { #[test] fn statvfs_call() { - statvfs(&b"/"[..]).unwrap(); + statvfs("/".as_bytes()).unwrap(); } #[test] diff --git a/src/sys/sysinfo.rs b/src/sys/sysinfo.rs index dc943c1..222a2fc 100644 --- a/src/sys/sysinfo.rs +++ b/src/sys/sysinfo.rs @@ -71,7 +71,7 @@ impl SysInfo { /// Returns system information. /// -/// [See `sysinfo(2)`](https://man7.org/linux/man-pages/man2/sysinfo.2.html). +/// [See `sysinfo(2)`](http://man7.org/linux/man-pages/man2/sysinfo.2.html). pub fn sysinfo() -> Result<SysInfo> { let mut info = mem::MaybeUninit::uninit(); let res = unsafe { libc::sysinfo(info.as_mut_ptr()) }; diff --git a/src/sys/termios.rs b/src/sys/termios.rs index 01d4608..c30de80 100644 --- a/src/sys/termios.rs +++ b/src/sys/termios.rs @@ -5,7 +5,7 @@ //! types here or exported directly. //! //! If you are unfamiliar with the `termios` API, you should first read the -//! [API documentation](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/termios.h.html) and +//! [API documentation](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/termios.h.html) and //! then come back to understand how `nix` safely wraps it. //! //! It should be noted that this API incurs some runtime overhead above the base `libc` definitions. @@ -152,11 +152,11 @@ //! # } //! ``` use cfg_if::cfg_if; -use crate::Result; +use crate::{Error, Result}; use crate::errno::Errno; use libc::{self, c_int, tcflag_t}; use std::cell::{Ref, RefCell}; -use std::convert::From; +use std::convert::{From, TryFrom}; use std::mem; use std::os::unix::io::RawFd; @@ -256,7 +256,6 @@ libc_enum!{ /// B0 is special and will disable the port. #[cfg_attr(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64"), repr(u64))] #[cfg_attr(not(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64")), repr(u32))] - #[non_exhaustive] pub enum BaudRate { B0, B50, @@ -300,17 +299,11 @@ libc_enum!{ target_os = "openbsd"))] B76800, B115200, - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - B153600, B230400, - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - B307200, #[cfg(any(target_os = "android", target_os = "freebsd", - target_os = "illumos", target_os = "linux", - target_os = "netbsd", - target_os = "solaris"))] + target_os = "netbsd"))] B460800, #[cfg(any(target_os = "android", target_os = "linux"))] B500000, @@ -318,10 +311,8 @@ libc_enum!{ B576000, #[cfg(any(target_os = "android", target_os = "freebsd", - target_os = "illumos", target_os = "linux", - target_os = "netbsd", - target_os = "solaris"))] + target_os = "netbsd"))] B921600, #[cfg(any(target_os = "android", target_os = "linux"))] B1000000, @@ -340,7 +331,107 @@ libc_enum!{ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] B4000000, } - impl TryFrom<libc::speed_t> +} + +impl TryFrom<libc::speed_t> for BaudRate { + type Error = Error; + + fn try_from(s: libc::speed_t) -> Result<BaudRate> { + use libc::{B0, B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800, B2400, B4800, + B9600, B19200, B38400, B57600, B115200, B230400}; + #[cfg(any(target_os = "android", target_os = "linux"))] + use libc::{B500000, B576000, B1000000, B1152000, B1500000, B2000000}; + #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] + use libc::{B2500000, B3000000, B3500000, B4000000}; + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + use libc::{B7200, B14400, B28800, B76800}; + #[cfg(any(target_os = "android", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd"))] + use libc::{B460800, B921600}; + + match s { + B0 => Ok(BaudRate::B0), + B50 => Ok(BaudRate::B50), + B75 => Ok(BaudRate::B75), + B110 => Ok(BaudRate::B110), + B134 => Ok(BaudRate::B134), + B150 => Ok(BaudRate::B150), + B200 => Ok(BaudRate::B200), + B300 => Ok(BaudRate::B300), + B600 => Ok(BaudRate::B600), + B1200 => Ok(BaudRate::B1200), + B1800 => Ok(BaudRate::B1800), + B2400 => Ok(BaudRate::B2400), + B4800 => Ok(BaudRate::B4800), + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + B7200 => Ok(BaudRate::B7200), + B9600 => Ok(BaudRate::B9600), + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + B14400 => Ok(BaudRate::B14400), + B19200 => Ok(BaudRate::B19200), + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + B28800 => Ok(BaudRate::B28800), + B38400 => Ok(BaudRate::B38400), + B57600 => Ok(BaudRate::B57600), + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + B76800 => Ok(BaudRate::B76800), + B115200 => Ok(BaudRate::B115200), + B230400 => Ok(BaudRate::B230400), + #[cfg(any(target_os = "android", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd"))] + B460800 => Ok(BaudRate::B460800), + #[cfg(any(target_os = "android", target_os = "linux"))] + B500000 => Ok(BaudRate::B500000), + #[cfg(any(target_os = "android", target_os = "linux"))] + B576000 => Ok(BaudRate::B576000), + #[cfg(any(target_os = "android", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd"))] + B921600 => Ok(BaudRate::B921600), + #[cfg(any(target_os = "android", target_os = "linux"))] + B1000000 => Ok(BaudRate::B1000000), + #[cfg(any(target_os = "android", target_os = "linux"))] + B1152000 => Ok(BaudRate::B1152000), + #[cfg(any(target_os = "android", target_os = "linux"))] + B1500000 => Ok(BaudRate::B1500000), + #[cfg(any(target_os = "android", target_os = "linux"))] + B2000000 => Ok(BaudRate::B2000000), + #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] + B2500000 => Ok(BaudRate::B2500000), + #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] + B3000000 => Ok(BaudRate::B3000000), + #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] + B3500000 => Ok(BaudRate::B3500000), + #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] + B4000000 => Ok(BaudRate::B4000000), + _ => Err(Error::invalid_argument()) + } + } } #[cfg(any(target_os = "freebsd", @@ -361,7 +452,6 @@ libc_enum! { /// /// Used as an argument to `tcsetattr()` #[repr(i32)] - #[non_exhaustive] pub enum SetArg { /// The change will occur immediately TCSANOW, @@ -377,7 +467,6 @@ libc_enum! { /// /// Used as an argument to `tcflush()`. #[repr(i32)] - #[non_exhaustive] pub enum FlushArg { /// Flush data that was received but not read TCIFLUSH, @@ -393,7 +482,6 @@ libc_enum! { /// /// Used as an argument to `tcflow()`. #[repr(i32)] - #[non_exhaustive] pub enum FlowArg { /// Suspend transmission TCOOFF, @@ -410,51 +498,41 @@ libc_enum! { libc_enum! { /// Indices into the `termios.c_cc` array for special characters. #[repr(usize)] - #[non_exhaustive] pub enum SpecialCharacterIndices { VDISCARD, #[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "illumos", target_os = "macos", target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] + target_os = "openbsd"))] VDSUSP, VEOF, VEOL, VEOL2, VERASE, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "solaris"))] + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] VERASE2, VINTR, VKILL, VLNEXT, - #[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"), - target_os = "illumos", target_os = "solaris")))] + #[cfg(not(all(target_os = "linux", target_arch = "sparc64")))] VMIN, VQUIT, VREPRINT, VSTART, #[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "illumos", target_os = "macos", target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] + target_os = "openbsd"))] VSTATUS, VSTOP, VSUSP, #[cfg(target_os = "linux")] VSWTC, - #[cfg(any(target_os = "haiku", target_os = "illumos", target_os = "solaris"))] + #[cfg(target_os = "haiku")] VSWTCH, - #[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"), - target_os = "illumos", target_os = "solaris")))] + #[cfg(not(all(target_os = "linux", target_arch = "sparc64")))] VTIME, VWERASE, #[cfg(target_os = "dragonfly")] @@ -462,8 +540,7 @@ libc_enum! { } } -#[cfg(any(all(target_os = "linux", target_arch = "sparc64"), - target_os = "illumos", target_os = "solaris"))] +#[cfg(all(target_os = "linux", target_arch = "sparc64"))] impl SpecialCharacterIndices { pub const VMIN: SpecialCharacterIndices = SpecialCharacterIndices::VEOF; pub const VTIME: SpecialCharacterIndices = SpecialCharacterIndices::VEOL; @@ -492,9 +569,7 @@ libc_bitflags! { ICRNL; IXON; IXOFF; - #[cfg(not(target_os = "redox"))] IXANY; - #[cfg(not(target_os = "redox"))] IMAXBEL; #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] IUTF8; @@ -801,7 +876,7 @@ cfg_if!{ target_os = "netbsd", target_os = "openbsd"))] { /// Get input baud rate (see - /// [cfgetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)). + /// [cfgetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)). /// /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure. pub fn cfgetispeed(termios: &Termios) -> u32 { @@ -810,7 +885,7 @@ cfg_if!{ } /// Get output baud rate (see - /// [cfgetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)). + /// [cfgetospeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)). /// /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure. pub fn cfgetospeed(termios: &Termios) -> u32 { @@ -819,7 +894,7 @@ cfg_if!{ } /// Set input baud rate (see - /// [cfsetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)). + /// [cfsetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)). /// /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure. pub fn cfsetispeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> { @@ -830,7 +905,7 @@ cfg_if!{ } /// Set output baud rate (see - /// [cfsetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html)). + /// [cfsetospeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html)). /// /// `cfsetospeed()` sets the output baud rate in the given termios structure. pub fn cfsetospeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> { @@ -855,7 +930,7 @@ cfg_if!{ use std::convert::TryInto; /// Get input baud rate (see - /// [cfgetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)). + /// [cfgetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)). /// /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure. pub fn cfgetispeed(termios: &Termios) -> BaudRate { @@ -864,7 +939,7 @@ cfg_if!{ } /// Get output baud rate (see - /// [cfgetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)). + /// [cfgetospeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)). /// /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure. pub fn cfgetospeed(termios: &Termios) -> BaudRate { @@ -873,7 +948,7 @@ cfg_if!{ } /// Set input baud rate (see - /// [cfsetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)). + /// [cfsetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)). /// /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure. pub fn cfsetispeed(termios: &mut Termios, baud: BaudRate) -> Result<()> { @@ -884,7 +959,7 @@ cfg_if!{ } /// Set output baud rate (see - /// [cfsetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html)). + /// [cfsetospeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html)). /// /// `cfsetospeed()` sets the output baud rate in the given `Termios` structure. pub fn cfsetospeed(termios: &mut Termios, baud: BaudRate) -> Result<()> { @@ -909,7 +984,7 @@ cfg_if!{ } /// Configures the port to something like the "raw" mode of the old Version 7 terminal driver (see -/// [termios(3)](https://man7.org/linux/man-pages/man3/termios.3.html)). +/// [termios(3)](http://man7.org/linux/man-pages/man3/termios.3.html)). /// /// `cfmakeraw()` configures the termios structure such that input is available character-by- /// character, echoing is disabled, and all special input and output processing is disabled. Note @@ -936,7 +1011,7 @@ pub fn cfmakesane(termios: &mut Termios) { } /// Return the configuration of a port -/// [tcgetattr(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetattr.html)). +/// [tcgetattr(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetattr.html)). /// /// `tcgetattr()` returns a `Termios` structure with the current configuration for a port. Modifying /// this structure *will not* reconfigure the port, instead the modifications should be done to @@ -952,7 +1027,7 @@ pub fn tcgetattr(fd: RawFd) -> Result<Termios> { } /// Set the configuration for a terminal (see -/// [tcsetattr(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetattr.html)). +/// [tcsetattr(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetattr.html)). /// /// `tcsetattr()` reconfigures the given port based on a given `Termios` structure. This change /// takes affect at a time specified by `actions`. Note that this function may return success if @@ -963,13 +1038,13 @@ pub fn tcsetattr(fd: RawFd, actions: SetArg, termios: &Termios) -> Result<()> { } /// Block until all output data is written (see -/// [tcdrain(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcdrain.html)). +/// [tcdrain(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcdrain.html)). pub fn tcdrain(fd: RawFd) -> Result<()> { Errno::result(unsafe { libc::tcdrain(fd) }).map(drop) } /// Suspend or resume the transmission or reception of data (see -/// [tcflow(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflow.html)). +/// [tcflow(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflow.html)). /// /// `tcflow()` suspends of resumes the transmission or reception of data for the given port /// depending on the value of `action`. @@ -978,7 +1053,7 @@ pub fn tcflow(fd: RawFd, action: FlowArg) -> Result<()> { } /// Discard data in the output or input queue (see -/// [tcflush(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflush.html)). +/// [tcflush(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflush.html)). /// /// `tcflush()` will discard data for a terminal port in the input queue, output queue, or both /// depending on the value of `action`. @@ -987,7 +1062,7 @@ pub fn tcflush(fd: RawFd, action: FlushArg) -> Result<()> { } /// Send a break for a specific duration (see -/// [tcsendbreak(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsendbreak.html)). +/// [tcsendbreak(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsendbreak.html)). /// /// When using asynchronous data transmission `tcsendbreak()` will transmit a continuous stream /// of zero-valued bits for an implementation-defined duration. @@ -996,7 +1071,7 @@ pub fn tcsendbreak(fd: RawFd, duration: c_int) -> Result<()> { } /// Get the session controlled by the given terminal (see -/// [tcgetsid(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetsid.html)). +/// [tcgetsid(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetsid.html)). pub fn tcgetsid(fd: RawFd) -> Result<Pid> { let res = unsafe { libc::tcgetsid(fd) }; @@ -1006,7 +1081,6 @@ pub fn tcgetsid(fd: RawFd) -> Result<Pid> { #[cfg(test)] mod test { use super::*; - use std::convert::TryFrom; #[test] fn try_from() { diff --git a/src/sys/time.rs b/src/sys/time.rs index ac42471..7546d1b 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -77,7 +77,11 @@ impl From<timespec> for TimeSpec { impl From<Duration> for TimeSpec { fn from(duration: Duration) -> Self { - Self::from_duration(duration) + #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 + TimeSpec(timespec { + tv_sec: duration.as_secs() as time_t, + tv_nsec: duration.subsec_nanos() as timespec_tv_nsec_t + }) } } @@ -187,25 +191,13 @@ impl TimeSpec { } #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 - pub const fn tv_sec(&self) -> time_t { + pub fn tv_sec(&self) -> time_t { self.0.tv_sec } - pub const fn tv_nsec(&self) -> timespec_tv_nsec_t { + pub fn tv_nsec(&self) -> timespec_tv_nsec_t { self.0.tv_nsec } - - pub const fn from_duration(duration: Duration) -> Self { - #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 - TimeSpec(timespec { - tv_sec: duration.as_secs() as time_t, - tv_nsec: duration.subsec_nanos() as timespec_tv_nsec_t - }) - } - - pub const fn from_timespec(timespec: timespec) -> Self { - Self(timespec) - } } impl ops::Neg for TimeSpec { @@ -404,11 +396,11 @@ impl TimeVal { } #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 - pub const fn tv_sec(&self) -> time_t { + pub fn tv_sec(&self) -> time_t { self.0.tv_sec } - pub const fn tv_usec(&self) -> suseconds_t { + pub fn tv_usec(&self) -> suseconds_t { self.0.tv_usec } } diff --git a/src/sys/timerfd.rs b/src/sys/timerfd.rs index 705a3c4..4a24719 100644 --- a/src/sys/timerfd.rs +++ b/src/sys/timerfd.rs @@ -3,7 +3,7 @@ //! Timer FD is a Linux-only API to create timers and get expiration //! notifications through file descriptors. //! -//! For more documentation, please read [timerfd_create(2)](https://man7.org/linux/man-pages/man2/timerfd_create.2.html). +//! For more documentation, please read [timerfd_create(2)](http://man7.org/linux/man-pages/man2/timerfd_create.2.html). //! //! # Examples //! @@ -30,7 +30,7 @@ //! ``` use crate::sys::time::TimeSpec; use crate::unistd::read; -use crate::{errno::Errno, Result}; +use crate::{errno::Errno, Error, Result}; use bitflags::bitflags; use libc::c_int; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; @@ -56,9 +56,8 @@ impl FromRawFd for TimerFd { libc_enum! { /// The type of the clock used to mark the progress of the timer. For more - /// details on each kind of clock, please refer to [timerfd_create(2)](https://man7.org/linux/man-pages/man2/timerfd_create.2.html). + /// details on each kind of clock, please refer to [timerfd_create(2)](http://man7.org/linux/man-pages/man2/timerfd_create.2.html). #[repr(i32)] - #[non_exhaustive] pub enum ClockId { CLOCK_REALTIME, CLOCK_MONOTONIC, @@ -88,7 +87,7 @@ bitflags! { struct TimerSpec(libc::itimerspec); impl TimerSpec { - pub const fn none() -> Self { + pub fn none() -> Self { Self(libc::itimerspec { it_interval: libc::timespec { tv_sec: 0, @@ -257,9 +256,14 @@ impl TimerFd { /// /// Note: If the alarm is unset, then you will wait forever. pub fn wait(&self) -> Result<()> { - while let Err(e) = read(self.fd, &mut [0u8; 8]) { - if e != Errno::EINTR { - return Err(e) + loop { + if let Err(e) = read(self.fd, &mut [0u8; 8]) { + match e { + Error::Sys(Errno::EINTR) => continue, + _ => return Err(e), + } + } else { + break; } } @@ -273,7 +277,7 @@ impl Drop for TimerFd { let result = Errno::result(unsafe { libc::close(self.fd) }); - if let Err(Errno::EBADF) = result { + if let Err(Error::Sys(Errno::EBADF)) = result { panic!("close of TimerFd encountered EBADF"); } } diff --git a/src/sys/uio.rs b/src/sys/uio.rs index 3abcde2..6533422 100644 --- a/src/sys/uio.rs +++ b/src/sys/uio.rs @@ -1,4 +1,5 @@ -//! Vectored I/O +// Silence invalid warnings due to rust-lang/rust#16719 +#![allow(improper_ctypes)] use crate::Result; use crate::errno::Errno; @@ -6,18 +7,12 @@ use libc::{self, c_int, c_void, size_t, off_t}; use std::marker::PhantomData; use std::os::unix::io::RawFd; -/// Low-level vectored write to a raw file descriptor -/// -/// See also [writev(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/writev.html) pub fn writev(fd: RawFd, iov: &[IoVec<&[u8]>]) -> Result<usize> { let res = unsafe { libc::writev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) }; Errno::result(res).map(|r| r as usize) } -/// Low-level vectored read from a raw file descriptor -/// -/// See also [readv(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/readv.html) pub fn readv(fd: RawFd, iov: &mut [IoVec<&mut [u8]>]) -> Result<usize> { let res = unsafe { libc::readv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) }; @@ -30,7 +25,11 @@ pub fn readv(fd: RawFd, iov: &mut [IoVec<&mut [u8]>]) -> Result<usize> { /// or an error occurs. The file offset is not changed. /// /// See also: [`writev`](fn.writev.html) and [`pwrite`](fn.pwrite.html) -#[cfg(not(target_os = "redox"))] +#[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd"))] pub fn pwritev(fd: RawFd, iov: &[IoVec<&[u8]>], offset: off_t) -> Result<usize> { let res = unsafe { @@ -47,7 +46,11 @@ pub fn pwritev(fd: RawFd, iov: &[IoVec<&[u8]>], /// changed. /// /// See also: [`readv`](fn.readv.html) and [`pread`](fn.pread.html) -#[cfg(not(target_os = "redox"))] +#[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd"))] pub fn preadv(fd: RawFd, iov: &[IoVec<&mut [u8]>], offset: off_t) -> Result<usize> { let res = unsafe { @@ -57,10 +60,6 @@ pub fn preadv(fd: RawFd, iov: &[IoVec<&mut [u8]>], Errno::result(res).map(|r| r as usize) } -/// Low-level write to a file, with specified offset. -/// -/// See also [pwrite(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html) -// TODO: move to unistd pub fn pwrite(fd: RawFd, buf: &[u8], offset: off_t) -> Result<usize> { let res = unsafe { libc::pwrite(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, @@ -70,10 +69,6 @@ pub fn pwrite(fd: RawFd, buf: &[u8], offset: off_t) -> Result<usize> { Errno::result(res).map(|r| r as usize) } -/// Low-level write to a file, with specified offset. -/// -/// See also [pread(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html) -// TODO: move to unistd pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result<usize>{ let res = unsafe { libc::pread(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t, @@ -117,7 +112,7 @@ pub struct RemoteIoVec { /// /// This function is only available on Linux. /// -/// [`process_vm_writev`(2)]: https://man7.org/linux/man-pages/man2/process_vm_writev.2.html +/// [`process_vm_writev`(2)]: http://man7.org/linux/man-pages/man2/process_vm_writev.2.html /// [ptrace]: ../ptrace/index.html /// [`IoVec`]: struct.IoVec.html /// [`RemoteIoVec`]: struct.RemoteIoVec.html @@ -152,7 +147,7 @@ pub fn process_vm_writev( /// /// This function is only available on Linux. /// -/// [`process_vm_readv`(2)]: https://man7.org/linux/man-pages/man2/process_vm_readv.2.html +/// [`process_vm_readv`(2)]: http://man7.org/linux/man-pages/man2/process_vm_readv.2.html /// [`ptrace`]: ../ptrace/index.html /// [`IoVec`]: struct.IoVec.html /// [`RemoteIoVec`]: struct.RemoteIoVec.html @@ -171,17 +166,11 @@ pub fn process_vm_readv( Errno::result(res).map(|r| r as usize) } -/// A vector of buffers. -/// -/// Vectored I/O methods like [`writev`] and [`readv`] use this structure for -/// both reading and writing. Each `IoVec` specifies the base address and -/// length of an area in memory. #[repr(transparent)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct IoVec<T>(pub(crate) libc::iovec, PhantomData<T>); +pub struct IoVec<T>(libc::iovec, PhantomData<T>); impl<T> IoVec<T> { - /// View the `IoVec` as a Rust slice. #[inline] pub fn as_slice(&self) -> &[u8] { use std::slice; @@ -195,15 +184,6 @@ impl<T> IoVec<T> { } impl<'a> IoVec<&'a [u8]> { - #[cfg(target_os = "freebsd")] - pub(crate) fn from_raw_parts(base: *mut c_void, len: usize) -> Self { - IoVec(libc::iovec { - iov_base: base, - iov_len: len - }, PhantomData) - } - - /// Create an `IoVec` from a Rust slice. pub fn from_slice(buf: &'a [u8]) -> IoVec<&'a [u8]> { IoVec(libc::iovec { iov_base: buf.as_ptr() as *mut c_void, @@ -213,7 +193,6 @@ impl<'a> IoVec<&'a [u8]> { } impl<'a> IoVec<&'a mut [u8]> { - /// Create an `IoVec` from a mutable Rust slice. pub fn from_mut_slice(buf: &'a mut [u8]) -> IoVec<&'a mut [u8]> { IoVec(libc::iovec { iov_base: buf.as_ptr() as *mut c_void, diff --git a/src/sys/utsname.rs b/src/sys/utsname.rs index 98edee0..bf1a814 100644 --- a/src/sys/utsname.rs +++ b/src/sys/utsname.rs @@ -1,42 +1,34 @@ -//! Get system identification use std::mem; use libc::{self, c_char}; use std::ffi::CStr; use std::str::from_utf8_unchecked; -/// Describes the running system. Return type of [`uname`]. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[repr(transparent)] pub struct UtsName(libc::utsname); impl UtsName { - /// Name of the operating system implementation pub fn sysname(&self) -> &str { to_str(&(&self.0.sysname as *const c_char ) as *const *const c_char) } - /// Network name of this machine. pub fn nodename(&self) -> &str { to_str(&(&self.0.nodename as *const c_char ) as *const *const c_char) } - /// Release level of the operating system. pub fn release(&self) -> &str { to_str(&(&self.0.release as *const c_char ) as *const *const c_char) } - /// Version level of the operating system. pub fn version(&self) -> &str { to_str(&(&self.0.version as *const c_char ) as *const *const c_char) } - /// Machine hardware platform. pub fn machine(&self) -> &str { to_str(&(&self.0.machine as *const c_char ) as *const *const c_char) } } -/// Get system identification pub fn uname() -> UtsName { unsafe { let mut ret = mem::MaybeUninit::uninit(); diff --git a/src/sys/wait.rs b/src/sys/wait.rs index ee49e37..faf8543 100644 --- a/src/sys/wait.rs +++ b/src/sys/wait.rs @@ -1,4 +1,3 @@ -//! Wait for a process to change status use crate::errno::Errno; use crate::sys::signal::Signal; use crate::unistd::Pid; @@ -8,17 +7,9 @@ use libc::{self, c_int}; use std::convert::TryFrom; libc_bitflags!( - /// Controls the behavior of [`waitpid`]. pub struct WaitPidFlag: c_int { - /// Do not block when there are no processes wishing to report status. WNOHANG; - /// Report the status of selected processes which are stopped due to a - /// [`SIGTTIN`](crate::sys::signal::Signal::SIGTTIN), - /// [`SIGTTOU`](crate::sys::signal::Signal::SIGTTOU), - /// [`SIGTSTP`](crate::sys::signal::Signal::SIGTSTP), or - /// [`SIGSTOP`](crate::sys::signal::Signal::SIGSTOP) signal. WUNTRACED; - /// Report the status of selected processes which have terminated. #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "haiku", @@ -28,11 +19,7 @@ libc_bitflags!( target_os = "macos", target_os = "netbsd"))] WEXITED; - /// Report the status of selected processes that have continued from a - /// job control stop by receiving a - /// [`SIGCONT`](crate::sys::signal::Signal::SIGCONT) signal. WCONTINUED; - /// An alias for WUNTRACED. #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "haiku", @@ -58,7 +45,6 @@ libc_bitflags!( /// Wait on all children, regardless of type #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] __WALL; - /// Wait for "clone" children only. #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] __WCLONE; } @@ -95,14 +81,14 @@ pub enum WaitStatus { /// field is the `PTRACE_EVENT_*` value of the event. /// /// [`nix::sys::ptrace`]: ../ptrace/index.html - /// [`ptrace`(2)]: https://man7.org/linux/man-pages/man2/ptrace.2.html + /// [`ptrace`(2)]: http://man7.org/linux/man-pages/man2/ptrace.2.html #[cfg(any(target_os = "linux", target_os = "android"))] PtraceEvent(Pid, Signal, c_int), /// The traced process was stopped by execution of a system call, /// and `PTRACE_O_TRACESYSGOOD` is in effect. See [`ptrace`(2)] for /// more information. /// - /// [`ptrace`(2)]: https://man7.org/linux/man-pages/man2/ptrace.2.html + /// [`ptrace`(2)]: http://man7.org/linux/man-pages/man2/ptrace.2.html #[cfg(any(target_os = "linux", target_os = "android"))] PtraceSyscall(Pid), /// The process was previously stopped but has resumed execution @@ -227,9 +213,6 @@ impl WaitStatus { } } -/// Wait for a process to change status -/// -/// See also [waitpid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/waitpid.html) pub fn waitpid<P: Into<Option<Pid>>>(pid: P, options: Option<WaitPidFlag>) -> Result<WaitStatus> { use self::WaitStatus::*; @@ -254,9 +237,6 @@ pub fn waitpid<P: Into<Option<Pid>>>(pid: P, options: Option<WaitPidFlag>) -> Re } } -/// Wait for any child process to change status or a signal is received. -/// -/// See also [wait(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html) pub fn wait() -> Result<WaitStatus> { waitpid(None, None) } diff --git a/src/time.rs b/src/time.rs index 6275b59..e6c3f8d 100644 --- a/src/time.rs +++ b/src/time.rs @@ -6,7 +6,7 @@ use crate::sys::time::TimeSpec; target_os = "android", target_os = "emscripten", ))] -use crate::unistd::Pid; +use crate::{unistd::Pid, Error}; use crate::{Errno, Result}; use libc::{self, clockid_t}; use std::mem::MaybeUninit; @@ -20,7 +20,7 @@ pub struct ClockId(clockid_t); impl ClockId { /// Creates `ClockId` from raw `clockid_t` - pub const fn from_raw(clk_id: clockid_t) -> Self { + pub fn from_raw(clk_id: clockid_t) -> Self { ClockId(clk_id) } @@ -61,7 +61,7 @@ impl ClockId { } /// Gets the raw `clockid_t` wrapped by `self` - pub const fn as_raw(self) -> clockid_t { + pub fn as_raw(self) -> clockid_t { self.0 } @@ -185,9 +185,9 @@ impl ClockId { pub const CLOCK_VIRTUAL: ClockId = ClockId(libc::CLOCK_VIRTUAL); } -impl From<ClockId> for clockid_t { - fn from(clock_id: ClockId) -> Self { - clock_id.as_raw() +impl Into<clockid_t> for ClockId { + fn into(self) -> clockid_t { + self.as_raw() } } @@ -255,6 +255,6 @@ pub fn clock_getcpuclockid(pid: Pid) -> Result<ClockId> { let res = unsafe { clk_id.assume_init() }; Ok(ClockId::from(res)) } else { - Err(Errno::from_i32(ret)) + Err(Error::Sys(Errno::from_i32(ret))) } } diff --git a/src/ucontext.rs b/src/ucontext.rs index f2338bd..a5b8cc7 100644 --- a/src/ucontext.rs +++ b/src/ucontext.rs @@ -1,3 +1,4 @@ +use libc; #[cfg(not(target_env = "musl"))] use crate::Result; #[cfg(not(target_env = "musl"))] diff --git a/src/unistd.rs b/src/unistd.rs index 2c89d77..7a4517e 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -29,9 +29,6 @@ pub use self::pivot_root::*; target_os = "linux", target_os = "openbsd"))] pub use self::setres::*; -#[cfg(any(target_os = "android", target_os = "linux"))] -pub use self::getres::*; - /// User identifier /// /// Newtype pattern around `uid_t` (which is just alias). It prevents bugs caused by accidentally @@ -41,7 +38,7 @@ pub struct Uid(uid_t); impl Uid { /// Creates `Uid` from raw `uid_t`. - pub const fn from_raw(uid: uid_t) -> Self { + pub fn from_raw(uid: uid_t) -> Self { Uid(uid) } @@ -56,12 +53,12 @@ impl Uid { } /// Returns true if the `Uid` represents privileged user - root. (If it equals zero.) - pub const fn is_root(self) -> bool { - self.0 == ROOT.0 + pub fn is_root(self) -> bool { + self == ROOT } /// Get the raw `uid_t` wrapped by `self`. - pub const fn as_raw(self) -> uid_t { + pub fn as_raw(self) -> uid_t { self.0 } } @@ -90,7 +87,7 @@ pub struct Gid(gid_t); impl Gid { /// Creates `Gid` from raw `gid_t`. - pub const fn from_raw(gid: gid_t) -> Self { + pub fn from_raw(gid: gid_t) -> Self { Gid(gid) } @@ -105,7 +102,7 @@ impl Gid { } /// Get the raw `gid_t` wrapped by `self`. - pub const fn as_raw(self) -> gid_t { + pub fn as_raw(self) -> gid_t { self.0 } } @@ -131,7 +128,7 @@ pub struct Pid(pid_t); impl Pid { /// Creates `Pid` from raw `pid_t`. - pub const fn from_raw(pid: pid_t) -> Self { + pub fn from_raw(pid: pid_t) -> Self { Pid(pid) } @@ -146,7 +143,7 @@ impl Pid { } /// Get the raw `pid_t` wrapped by `self`. - pub const fn as_raw(self) -> pid_t { + pub fn as_raw(self) -> pid_t { self.0 } } @@ -180,7 +177,10 @@ impl ForkResult { /// Return `true` if this is the child process of the `fork()` #[inline] pub fn is_child(self) -> bool { - matches!(self, ForkResult::Child) + match self { + ForkResult::Child => true, + _ => false + } } /// Returns `true` if this is the parent process of the `fork()` @@ -191,25 +191,20 @@ impl ForkResult { } /// Create a new child process duplicating the parent process ([see -/// fork(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html)). +/// fork(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html)). /// /// After calling the fork system call (successfully) two processes will /// be created that are identical with the exception of their pid and the /// return value of this function. As an example: /// -/// ``` -/// use nix::{sys::wait::waitpid,unistd::{fork, ForkResult, write}}; +/// ```no_run +/// use nix::unistd::{fork, ForkResult}; /// /// match unsafe{fork()} { /// Ok(ForkResult::Parent { child, .. }) => { /// println!("Continuing execution in parent process, new child has pid: {}", child); -/// waitpid(child, None).unwrap(); -/// } -/// Ok(ForkResult::Child) => { -/// // Unsafe to use `println!` (or `unwrap`) here. See Safety. -/// write(libc::STDOUT_FILENO, "I'm a new child process\n".as_bytes()).ok(); -/// unsafe { libc::_exit(0) }; /// } +/// Ok(ForkResult::Child) => println!("I'm a new child process"), /// Err(_) => println!("Fork failed"), /// } /// ``` @@ -233,7 +228,7 @@ impl ForkResult { /// Those functions are only a small subset of your operating system's API, so /// special care must be taken to only invoke code you can control and audit. /// -/// [async-signal-safe]: https://man7.org/linux/man-pages/man7/signal-safety.7.html +/// [async-signal-safe]: http://man7.org/linux/man-pages/man7/signal-safety.7.html #[inline] pub unsafe fn fork() -> Result<ForkResult> { use self::ForkResult::*; @@ -246,7 +241,7 @@ pub unsafe fn fork() -> Result<ForkResult> { } /// Get the pid of this process (see -/// [getpid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpid.html)). +/// [getpid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpid.html)). /// /// Since you are running code, there is always a pid to return, so there /// is no error case that needs to be handled. @@ -256,7 +251,7 @@ pub fn getpid() -> Pid { } /// Get the pid of this processes' parent (see -/// [getpid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getppid.html)). +/// [getpid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getppid.html)). /// /// There is always a parent pid to return, so there is no error case that needs /// to be handled. @@ -266,7 +261,7 @@ pub fn getppid() -> Pid { } /// Set a process group ID (see -/// [setpgid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgid.html)). +/// [setpgid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgid.html)). /// /// Set the process group id (PGID) of a particular process. If a pid of zero /// is specified, then the pid of the calling process is used. Process groups @@ -286,14 +281,14 @@ pub fn getpgid(pid: Option<Pid>) -> Result<Pid> { } /// Create new session and set process group id (see -/// [setsid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsid.html)). +/// [setsid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsid.html)). #[inline] pub fn setsid() -> Result<Pid> { Errno::result(unsafe { libc::setsid() }).map(Pid) } /// Get the process group ID of a session leader -/// [getsid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsid.html). +/// [getsid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsid.html). /// /// Obtain the process group ID of the process that is the session leader of the process specified /// by pid. If pid is zero, it specifies the calling process. @@ -306,7 +301,7 @@ pub fn getsid(pid: Option<Pid>) -> Result<Pid> { /// Get the terminal foreground process group (see -/// [tcgetpgrp(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetpgrp.html)). +/// [tcgetpgrp(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetpgrp.html)). /// /// Get the group process id (GPID) of the foreground process group on the /// terminal associated to file descriptor (FD). @@ -316,7 +311,7 @@ pub fn tcgetpgrp(fd: c_int) -> Result<Pid> { Errno::result(res).map(Pid) } /// Set the terminal foreground process group (see -/// [tcgetpgrp(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetpgrp.html)). +/// [tcgetpgrp(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetpgrp.html)). /// /// Get the group process id (PGID) to the foreground process group on the /// terminal associated to file descriptor (FD). @@ -328,7 +323,7 @@ pub fn tcsetpgrp(fd: c_int, pgrp: Pid) -> Result<()> { /// Get the group id of the calling process (see -///[getpgrp(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgrp.html)). +///[getpgrp(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgrp.html)). /// /// Get the process group id (PGID) of the calling process. /// According to the man page it is always successful. @@ -338,7 +333,7 @@ pub fn getpgrp() -> Pid { } /// Get the caller's thread ID (see -/// [gettid(2)](https://man7.org/linux/man-pages/man2/gettid.2.html). +/// [gettid(2)](http://man7.org/linux/man-pages/man2/gettid.2.html). /// /// This function is only available on Linux based systems. In a single /// threaded process, the main thread will have the same ID as the process. In @@ -354,7 +349,7 @@ pub fn gettid() -> Pid { } /// Create a copy of the specified file descriptor (see -/// [dup(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)). +/// [dup(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)). /// /// The new file descriptor will be have a new index but refer to the same /// resource as the old file descriptor and the old and new file descriptors may @@ -371,7 +366,7 @@ pub fn dup(oldfd: RawFd) -> Result<RawFd> { } /// Create a copy of the specified file descriptor using the specified fd (see -/// [dup(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)). +/// [dup(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)). /// /// This function behaves similar to `dup()` except that it will try to use the /// specified fd instead of allocating a new one. See the man pages for more @@ -384,7 +379,7 @@ pub fn dup2(oldfd: RawFd, newfd: RawFd) -> Result<RawFd> { } /// Create a new copy of the specified file descriptor using the specified fd -/// and flags (see [dup(2)](https://man7.org/linux/man-pages/man2/dup.2.html)). +/// and flags (see [dup(2)](http://man7.org/linux/man-pages/man2/dup.2.html)). /// /// This function behaves similar to `dup2()` but allows for flags to be /// specified. @@ -395,7 +390,7 @@ pub fn dup3(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> { #[inline] fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> { if oldfd == newfd { - return Err(Errno::EINVAL); + return Err(Error::Sys(Errno::EINVAL)); } let fd = dup2(oldfd, newfd)?; @@ -411,7 +406,7 @@ fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> { } /// Change the current working directory of the calling process (see -/// [chdir(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/chdir.html)). +/// [chdir(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/chdir.html)). /// /// This function may fail in a number of different scenarios. See the man /// pages for additional details on possible failure cases. @@ -426,7 +421,7 @@ pub fn chdir<P: ?Sized + NixPath>(path: &P) -> Result<()> { /// Change the current working directory of the process to the one /// given as an open file descriptor (see -/// [fchdir(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchdir.html)). +/// [fchdir(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchdir.html)). /// /// This function may fail in a number of different scenarios. See the man /// pages for additional details on possible failure cases. @@ -438,7 +433,7 @@ pub fn fchdir(dirfd: RawFd) -> Result<()> { Errno::result(res).map(drop) } -/// Creates new directory `path` with access rights `mode`. (see [mkdir(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdir.html)) +/// Creates new directory `path` with access rights `mode`. (see [mkdir(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdir.html)) /// /// # Errors /// @@ -455,13 +450,15 @@ pub fn fchdir(dirfd: RawFd) -> Result<()> { /// use nix::sys::stat; /// use tempfile::tempdir; /// -/// let tmp_dir1 = tempdir().unwrap(); -/// let tmp_dir2 = tmp_dir1.path().join("new_dir"); +/// fn main() { +/// let tmp_dir1 = tempdir().unwrap(); +/// let tmp_dir2 = tmp_dir1.path().join("new_dir"); /// -/// // create new directory and give read, write and execute rights to the owner -/// match unistd::mkdir(&tmp_dir2, stat::Mode::S_IRWXU) { -/// Ok(_) => println!("created {:?}", tmp_dir2), -/// Err(err) => println!("Error creating directory: {}", err), +/// // create new directory and give read, write and execute rights to the owner +/// match unistd::mkdir(&tmp_dir2, stat::Mode::S_IRWXU) { +/// Ok(_) => println!("created {:?}", tmp_dir2), +/// Err(err) => println!("Error creating directory: {}", err), +/// } /// } /// ``` #[inline] @@ -484,7 +481,7 @@ pub fn mkdir<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> { /// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X) /// /// For a full list consult -/// [posix specification](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifo.html) +/// [posix specification](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifo.html) /// /// # Example /// @@ -493,13 +490,15 @@ pub fn mkdir<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> { /// use nix::sys::stat; /// use tempfile::tempdir; /// -/// let tmp_dir = tempdir().unwrap(); -/// let fifo_path = tmp_dir.path().join("foo.pipe"); +/// fn main() { +/// let tmp_dir = tempdir().unwrap(); +/// let fifo_path = tmp_dir.path().join("foo.pipe"); /// -/// // create new fifo and give read, write and execute rights to the owner -/// match unistd::mkfifo(&fifo_path, stat::Mode::S_IRWXU) { -/// Ok(_) => println!("created {:?}", fifo_path), -/// Err(err) => println!("Error creating fifo: {}", err), +/// // create new fifo and give read, write and execute rights to the owner +/// match unistd::mkfifo(&fifo_path, stat::Mode::S_IRWXU) { +/// Ok(_) => println!("created {:?}", fifo_path), +/// Err(err) => println!("Error creating fifo: {}", err), +/// } /// } /// ``` #[inline] @@ -520,7 +519,7 @@ pub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> { /// /// # References /// -/// [mkfifoat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifoat.html). +/// [mkfifoat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifoat.html). // mkfifoat is not implemented in OSX or android #[inline] #[cfg(not(any( @@ -542,7 +541,7 @@ pub fn mkfifoat<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P, mode: Mode) /// If `dirfd` is `None`, then `path2` is relative to the current working /// directory. This is identical to `libc::symlink(path1, path2)`. /// -/// See also [symlinkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/symlinkat.html). +/// See also [symlinkat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/symlinkat.html). #[cfg(not(target_os = "redox"))] pub fn symlinkat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( path1: &P1, @@ -569,7 +568,7 @@ fn reserve_double_buffer_size<T>(buf: &mut Vec<T>, limit: usize) -> Result<()> { use std::cmp::min; if buf.capacity() >= limit { - return Err(Errno::ERANGE) + return Err(Error::Sys(Errno::ERANGE)) } let capacity = min(buf.capacity() * 2, limit); @@ -588,9 +587,11 @@ fn reserve_double_buffer_size<T>(buf: &mut Vec<T>, limit: usize) -> Result<()> { /// ```rust /// use nix::unistd; /// -/// // assume that we are allowed to get current directory -/// let dir = unistd::getcwd().unwrap(); -/// println!("The current directory is {:?}", dir); +/// fn main() { +/// // assume that we are allowed to get current directory +/// let dir = unistd::getcwd().unwrap(); +/// println!("The current directory is {:?}", dir); +/// } /// ``` #[inline] pub fn getcwd() -> Result<PathBuf> { @@ -612,9 +613,9 @@ pub fn getcwd() -> Result<PathBuf> { let error = Errno::last(); // ERANGE means buffer was too small to store directory name if error != Errno::ERANGE { - return Err(error); + return Err(Error::Sys(error)); } - } + } // Trigger the internal buffer resizing logic. reserve_double_buffer_size(&mut buf, PATH_MAX as usize)?; @@ -623,8 +624,6 @@ pub fn getcwd() -> Result<PathBuf> { } /// Computes the raw UID and GID values to pass to a `*chown` call. -// The cast is not unnecessary on all platforms. -#[allow(clippy::unnecessary_cast)] fn chown_raw_ids(owner: Option<Uid>, group: Option<Gid>) -> (libc::uid_t, libc::gid_t) { // According to the POSIX specification, -1 is used to indicate that owner and group // are not to be changed. Since uid_t and gid_t are unsigned types, we have to wrap @@ -638,7 +637,7 @@ fn chown_raw_ids(owner: Option<Uid>, group: Option<Gid>) -> (libc::uid_t, libc:: /// Change the ownership of the file at `path` to be owned by the specified /// `owner` (user) and `group` (see -/// [chown(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/chown.html)). +/// [chown(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/chown.html)). /// /// The owner/group for the provided path name will not be modified if `None` is /// provided for that argument. Ownership change will be attempted for the path @@ -694,7 +693,7 @@ pub enum FchownatFlags { /// /// # References /// -/// [fchownat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchownat.html). +/// [fchownat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchownat.html). #[cfg(not(target_os = "redox"))] pub fn fchownat<P: ?Sized + NixPath>( dirfd: Option<RawFd>, @@ -723,7 +722,7 @@ fn to_exec_array<S: AsRef<CStr>>(args: &[S]) -> Vec<*const c_char> { } /// Replace the current process image with a new one (see -/// [exec(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)). +/// [exec(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)). /// /// See the `::nix::unistd::execve` system call for additional details. `execv` /// performs the same action but does not allow for customization of the @@ -736,12 +735,12 @@ pub fn execv<S: AsRef<CStr>>(path: &CStr, argv: &[S]) -> Result<Infallible> { libc::execv(path.as_ptr(), args_p.as_ptr()) }; - Err(Errno::last()) + Err(Error::Sys(Errno::last())) } /// Replace the current process image with a new one (see -/// [execve(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)). +/// [execve(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)). /// /// The execve system call allows for another process to be "called" which will /// replace the current process image. That is, this process becomes the new @@ -761,12 +760,12 @@ pub fn execve<SA: AsRef<CStr>, SE: AsRef<CStr>>(path: &CStr, args: &[SA], env: & libc::execve(path.as_ptr(), args_p.as_ptr(), env_p.as_ptr()) }; - Err(Errno::last()) + Err(Error::Sys(Errno::last())) } /// Replace the current process image with a new one and replicate shell `PATH` /// searching behavior (see -/// [exec(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)). +/// [exec(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)). /// /// See `::nix::unistd::execve` for additional details. `execvp` behaves the /// same as execv except that it will examine the `PATH` environment variables @@ -781,12 +780,12 @@ pub fn execvp<S: AsRef<CStr>>(filename: &CStr, args: &[S]) -> Result<Infallible> libc::execvp(filename.as_ptr(), args_p.as_ptr()) }; - Err(Errno::last()) + Err(Error::Sys(Errno::last())) } /// Replace the current process image with a new one and replicate shell `PATH` /// searching behavior (see -/// [`execvpe(3)`](https://man7.org/linux/man-pages/man3/exec.3.html)). +/// [`execvpe(3)`](http://man7.org/linux/man-pages/man3/exec.3.html)). /// /// This functions like a combination of `execvp(2)` and `execve(2)` to pass an /// environment and have a search path. See these two for additional @@ -802,11 +801,11 @@ pub fn execvpe<SA: AsRef<CStr>, SE: AsRef<CStr>>(filename: &CStr, args: &[SA], e libc::execvpe(filename.as_ptr(), args_p.as_ptr(), env_p.as_ptr()) }; - Err(Errno::last()) + Err(Error::Sys(Errno::last())) } /// Replace the current process image with a new one (see -/// [fexecve(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fexecve.html)). +/// [fexecve(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fexecve.html)). /// /// The `fexecve` function allows for another process to be "called" which will /// replace the current process image. That is, this process becomes the new @@ -830,11 +829,11 @@ pub fn fexecve<SA: AsRef<CStr> ,SE: AsRef<CStr>>(fd: RawFd, args: &[SA], env: &[ libc::fexecve(fd, args_p.as_ptr(), env_p.as_ptr()) }; - Err(Errno::last()) + Err(Error::Sys(Errno::last())) } /// Execute program relative to a directory file descriptor (see -/// [execveat(2)](https://man7.org/linux/man-pages/man2/execveat.2.html)). +/// [execveat(2)](http://man7.org/linux/man-pages/man2/execveat.2.html)). /// /// The `execveat` function allows for another process to be "called" which will /// replace the current process image. That is, this process becomes the new @@ -855,11 +854,11 @@ pub fn execveat<SA: AsRef<CStr>,SE: AsRef<CStr>>(dirfd: RawFd, pathname: &CStr, args_p.as_ptr(), env_p.as_ptr(), flags); }; - Err(Errno::last()) + Err(Error::Sys(Errno::last())) } /// Daemonize this process by detaching from the controlling terminal (see -/// [daemon(3)](https://man7.org/linux/man-pages/man3/daemon.3.html)). +/// [daemon(3)](http://man7.org/linux/man-pages/man3/daemon.3.html)). /// /// When a process is launched it is typically associated with a parent and it, /// in turn, by its controlling terminal/process. In order for a process to run @@ -886,18 +885,16 @@ pub fn execveat<SA: AsRef<CStr>,SE: AsRef<CStr>>(dirfd: RawFd, pathname: &CStr, #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "illumos", target_os = "linux", target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] + target_os = "openbsd"))] pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> { let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) }; Errno::result(res).map(drop) } /// Set the system host name (see -/// [sethostname(2)](https://man7.org/linux/man-pages/man2/gethostname.2.html)). +/// [sethostname(2)](http://man7.org/linux/man-pages/man2/gethostname.2.html)). /// /// Given a name, attempt to update the system host name to the given string. /// On some systems, the host name is limited to as few as 64 bytes. An error @@ -909,10 +906,8 @@ pub fn sethostname<S: AsRef<OsStr>>(name: S) -> Result<()> { cfg_if! { if #[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "illumos", target_os = "ios", - target_os = "macos", - target_os = "solaris", ))] { + target_os = "macos", ))] { type sethostname_len_t = c_int; } else { type sethostname_len_t = size_t; @@ -927,7 +922,7 @@ pub fn sethostname<S: AsRef<OsStr>>(name: S) -> Result<()> { /// Get the host name and store it in the provided buffer, returning a pointer /// the `CStr` in that buffer on success (see -/// [gethostname(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/gethostname.html)). +/// [gethostname(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/gethostname.html)). /// /// This function call attempts to get the host name for the running system and /// store it in a provided buffer. The buffer will be populated with bytes up @@ -962,7 +957,7 @@ pub fn gethostname(buffer: &mut [u8]) -> Result<&CStr> { /// `std::fs::File`. Explicitly closing them with this method too can result in /// a double-close condition, which can cause confusing `EBADF` errors in /// seemingly unrelated code. Caveat programmer. See also -/// [close(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html). +/// [close(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html). /// /// # Examples /// @@ -970,16 +965,20 @@ pub fn gethostname(buffer: &mut [u8]) -> Result<&CStr> { /// use std::os::unix::io::AsRawFd; /// use nix::unistd::close; /// -/// let f = tempfile::tempfile().unwrap(); -/// close(f.as_raw_fd()).unwrap(); // Bad! f will also close on drop! +/// fn main() { +/// let f = tempfile::tempfile().unwrap(); +/// close(f.as_raw_fd()).unwrap(); // Bad! f will also close on drop! +/// } /// ``` /// /// ```rust /// use std::os::unix::io::IntoRawFd; /// use nix::unistd::close; /// -/// let f = tempfile::tempfile().unwrap(); -/// close(f.into_raw_fd()).unwrap(); // Good. into_raw_fd consumes f +/// fn main() { +/// let f = tempfile::tempfile().unwrap(); +/// close(f.into_raw_fd()).unwrap(); // Good. into_raw_fd consumes f +/// } /// ``` pub fn close(fd: RawFd) -> Result<()> { let res = unsafe { libc::close(fd) }; @@ -988,7 +987,7 @@ pub fn close(fd: RawFd) -> Result<()> { /// Read from a raw file descriptor. /// -/// See also [read(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html) +/// See also [read(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html) pub fn read(fd: RawFd, buf: &mut [u8]) -> Result<usize> { let res = unsafe { libc::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t) }; @@ -997,7 +996,7 @@ pub fn read(fd: RawFd, buf: &mut [u8]) -> Result<usize> { /// Write to a raw file descriptor. /// -/// See also [write(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html) +/// See also [write(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html) pub fn write(fd: RawFd, buf: &[u8]) -> Result<usize> { let res = unsafe { libc::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t) }; @@ -1020,28 +1019,20 @@ pub enum Whence { /// Specify an offset relative to the next location in the file greater than or /// equal to offset that contains some data. If offset points to /// some data, then the file offset is set to offset. - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "solaris"))] + #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))] SeekData = libc::SEEK_DATA, /// Specify an offset relative to the next hole in the file greater than /// or equal to offset. If offset points into the middle of a hole, then /// the file offset should be set to offset. If there is no hole past offset, /// then the file offset should be adjusted to the end of the file (i.e., there /// is an implicit hole at the end of any file). - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "solaris"))] + #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))] SeekHole = libc::SEEK_HOLE } /// Move the read/write file offset. /// -/// See also [lseek(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/lseek.html) +/// See also [lseek(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lseek.html) pub fn lseek(fd: RawFd, offset: off_t, whence: Whence) -> Result<off_t> { let res = unsafe { libc::lseek(fd, offset, whence as i32) }; @@ -1057,14 +1048,14 @@ pub fn lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result<libc: /// Create an interprocess channel. /// -/// See also [pipe(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html) -pub fn pipe() -> std::result::Result<(RawFd, RawFd), Error> { +/// See also [pipe(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html) +pub fn pipe() -> Result<(RawFd, RawFd)> { unsafe { let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit(); let res = libc::pipe(fds.as_mut_ptr() as *mut c_int); - Error::result(res)?; + Errno::result(res)?; Ok((fds.assume_init()[0], fds.assume_init()[1])) } @@ -1075,22 +1066,20 @@ pub fn pipe() -> std::result::Result<(RawFd, RawFd), Error> { /// The following flags are supported, and will be set atomically as the pipe is /// created: /// -/// - `O_CLOEXEC`: Set the close-on-exec flag for the new file descriptors. -#[cfg_attr(target_os = "linux", doc = "- `O_DIRECT`: Create a pipe that performs I/O in \"packet\" mode.")] -#[cfg_attr(target_os = "netbsd", doc = "- `O_NOSIGPIPE`: Return `EPIPE` instead of raising `SIGPIPE`.")] -/// - `O_NONBLOCK`: Set the non-blocking flag for the ends of the pipe. +/// `O_CLOEXEC`: Set the close-on-exec flag for the new file descriptors. +#[cfg_attr(target_os = "linux", doc = "`O_DIRECT`: Create a pipe that performs I/O in \"packet\" mode. ")] +#[cfg_attr(target_os = "netbsd", doc = "`O_NOSIGPIPE`: Return `EPIPE` instead of raising `SIGPIPE`. ")] +/// `O_NONBLOCK`: Set the non-blocking flag for the ends of the pipe. /// -/// See also [pipe(2)](https://man7.org/linux/man-pages/man2/pipe.2.html) +/// See also [pipe(2)](http://man7.org/linux/man-pages/man2/pipe.2.html) #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", - target_os = "illumos", target_os = "linux", target_os = "redox", target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] + target_os = "openbsd"))] pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit(); @@ -1106,7 +1095,7 @@ pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { /// Truncate a file to a specified length /// /// See also -/// [truncate(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html) +/// [truncate(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html) #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] pub fn truncate<P: ?Sized + NixPath>(path: &P, len: off_t) -> Result<()> { let res = path.with_nix_path(|cstr| { @@ -1121,7 +1110,7 @@ pub fn truncate<P: ?Sized + NixPath>(path: &P, len: off_t) -> Result<()> { /// Truncate a file to a specified length /// /// See also -/// [ftruncate(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html) +/// [ftruncate(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html) pub fn ftruncate(fd: RawFd, len: off_t) -> Result<()> { Errno::result(unsafe { libc::ftruncate(fd, len) }).map(drop) } @@ -1135,9 +1124,9 @@ pub fn isatty(fd: RawFd) -> Result<bool> { } else { match Errno::last() { Errno::ENOTTY => Ok(false), - err => Err(err), + err => Err(Error::Sys(err)), } - } + } } } @@ -1160,7 +1149,7 @@ pub enum LinkatFlags { /// process. If either `oldpath` or `newpath` is absolute, then `dirfd` is ignored. /// /// # References -/// See also [linkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/linkat.html) +/// See also [linkat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/linkat.html) #[cfg(not(target_os = "redox"))] // RedoxFS does not support symlinks yet pub fn linkat<P: ?Sized + NixPath>( olddirfd: Option<RawFd>, @@ -1196,7 +1185,7 @@ pub fn linkat<P: ?Sized + NixPath>( /// Remove a directory entry /// -/// See also [unlink(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html) +/// See also [unlink(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html) pub fn unlink<P: ?Sized + NixPath>(path: &P) -> Result<()> { let res = path.with_nix_path(|cstr| { unsafe { @@ -1222,7 +1211,7 @@ pub enum UnlinkatFlags { /// is performed. /// /// # References -/// See also [unlinkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlinkat.html) +/// See also [unlinkat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/unlinkat.html) #[cfg(not(target_os = "redox"))] pub fn unlinkat<P: ?Sized + NixPath>( dirfd: Option<RawFd>, @@ -1255,7 +1244,7 @@ pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> { /// Commit filesystem caches to disk /// -/// See also [sync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sync.html) +/// See also [sync(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sync.html) #[cfg(any( target_os = "dragonfly", target_os = "freebsd", @@ -1269,7 +1258,7 @@ pub fn sync() { /// Synchronize changes to a file /// -/// See also [fsync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html) +/// See also [fsync(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html) #[inline] pub fn fsync(fd: RawFd) -> Result<()> { let res = unsafe { libc::fsync(fd) }; @@ -1280,14 +1269,12 @@ pub fn fsync(fd: RawFd) -> Result<()> { /// Synchronize the data of a file /// /// See also -/// [fdatasync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html) +/// [fdatasync(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html) // `fdatasync(2) is in POSIX, but in libc it is only defined in `libc::notbsd`. // TODO: exclude only Apple systems after https://github.com/rust-lang/libc/pull/211 #[cfg(any(target_os = "linux", target_os = "android", - target_os = "emscripten", - target_os = "illumos", - target_os = "solaris"))] + target_os = "emscripten"))] #[inline] pub fn fdatasync(fd: RawFd) -> Result<()> { let res = unsafe { libc::fdatasync(fd) }; @@ -1297,7 +1284,7 @@ pub fn fdatasync(fd: RawFd) -> Result<()> { /// Get a real user ID /// -/// See also [getuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getuid.html) +/// See also [getuid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getuid.html) // POSIX requires that getuid is always successful, so no need to check return // value or errno. #[inline] @@ -1307,7 +1294,7 @@ pub fn getuid() -> Uid { /// Get the effective user ID /// -/// See also [geteuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/geteuid.html) +/// See also [geteuid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/geteuid.html) // POSIX requires that geteuid is always successful, so no need to check return // value or errno. #[inline] @@ -1317,7 +1304,7 @@ pub fn geteuid() -> Uid { /// Get the real group ID /// -/// See also [getgid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getgid.html) +/// See also [getgid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getgid.html) // POSIX requires that getgid is always successful, so no need to check return // value or errno. #[inline] @@ -1327,7 +1314,7 @@ pub fn getgid() -> Gid { /// Get the effective group ID /// -/// See also [getegid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getegid.html) +/// See also [getegid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getegid.html) // POSIX requires that getegid is always successful, so no need to check return // value or errno. #[inline] @@ -1337,7 +1324,7 @@ pub fn getegid() -> Gid { /// Set the effective user ID /// -/// See also [seteuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/seteuid.html) +/// See also [seteuid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/seteuid.html) #[inline] pub fn seteuid(euid: Uid) -> Result<()> { let res = unsafe { libc::seteuid(euid.into()) }; @@ -1347,7 +1334,7 @@ pub fn seteuid(euid: Uid) -> Result<()> { /// Set the effective group ID /// -/// See also [setegid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setegid.html) +/// See also [setegid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setegid.html) #[inline] pub fn setegid(egid: Gid) -> Result<()> { let res = unsafe { libc::setegid(egid.into()) }; @@ -1357,7 +1344,7 @@ pub fn setegid(egid: Gid) -> Result<()> { /// Set the user ID /// -/// See also [setuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setuid.html) +/// See also [setuid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setuid.html) #[inline] pub fn setuid(uid: Uid) -> Result<()> { let res = unsafe { libc::setuid(uid.into()) }; @@ -1367,7 +1354,7 @@ pub fn setuid(uid: Uid) -> Result<()> { /// Set the group ID /// -/// See also [setgid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setgid.html) +/// See also [setgid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setgid.html) #[inline] pub fn setgid(gid: Gid) -> Result<()> { let res = unsafe { libc::setgid(gid.into()) }; @@ -1379,7 +1366,7 @@ pub fn setgid(gid: Gid) -> Result<()> { /// On both success and failure, this call returns the previous filesystem user /// ID of the caller. /// -/// See also [setfsuid(2)](https://man7.org/linux/man-pages/man2/setfsuid.2.html) +/// See also [setfsuid(2)](http://man7.org/linux/man-pages/man2/setfsuid.2.html) #[cfg(any(target_os = "linux", target_os = "android"))] pub fn setfsuid(uid: Uid) -> Uid { let prev_fsuid = unsafe { libc::setfsuid(uid.into()) }; @@ -1390,7 +1377,7 @@ pub fn setfsuid(uid: Uid) -> Uid { /// On both success and failure, this call returns the previous filesystem group /// ID of the caller. /// -/// See also [setfsgid(2)](https://man7.org/linux/man-pages/man2/setfsgid.2.html) +/// See also [setfsgid(2)](http://man7.org/linux/man-pages/man2/setfsgid.2.html) #[cfg(any(target_os = "linux", target_os = "android"))] pub fn setfsgid(gid: Gid) -> Gid { let prev_fsgid = unsafe { libc::setfsgid(gid.into()) }; @@ -1399,7 +1386,7 @@ pub fn setfsgid(gid: Gid) -> Gid { /// Get the list of supplementary group IDs of the calling process. /// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html) +/// [Further reading](http://pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html) /// /// **Note:** This function is not available for Apple platforms. On those /// platforms, checking group membership should be achieved via communication @@ -1417,14 +1404,6 @@ pub fn getgroups() -> Result<Vec<Gid>> { // Next, get the number of groups so we can size our Vec let ngroups = unsafe { libc::getgroups(0, ptr::null_mut()) }; - // If there are no supplementary groups, return early. - // This prevents a potential buffer over-read if the number of groups - // increases from zero before the next call. It would return the total - // number of groups beyond the capacity of the buffer. - if ngroups == 0 { - return Ok(Vec::new()); - } - // Now actually get the groups. We try multiple times in case the number of // groups has changed since the first call to getgroups() and the buffer is // now too small. @@ -1442,11 +1421,11 @@ pub fn getgroups() -> Result<Vec<Gid>> { unsafe { groups.set_len(s as usize) }; return Ok(groups); }, - Err(Errno::EINVAL) => { + Err(Error::Sys(Errno::EINVAL)) => { // EINVAL indicates that the buffer size was too // small, resize it up to ngroups_max as limit. reserve_double_buffer_size(&mut groups, ngroups_max) - .or(Err(Errno::EINVAL))?; + .or(Err(Error::Sys(Errno::EINVAL)))?; }, Err(e) => return Err(e) } @@ -1455,7 +1434,7 @@ pub fn getgroups() -> Result<Vec<Gid>> { /// Set the list of supplementary group IDs for the calling process. /// -/// [Further reading](https://man7.org/linux/man-pages/man2/getgroups.2.html) +/// [Further reading](http://man7.org/linux/man-pages/man2/getgroups.2.html) /// /// **Note:** This function is not available for Apple platforms. On those /// platforms, group membership management should be achieved via communication @@ -1489,11 +1468,9 @@ pub fn setgroups(groups: &[Gid]) -> Result<()> { cfg_if! { if #[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "illumos", target_os = "ios", target_os = "macos", target_os = "netbsd", - target_os = "illumos", target_os = "openbsd"))] { type setgroups_ngroups_t = c_int; } else { @@ -1515,7 +1492,7 @@ pub fn setgroups(groups: &[Gid]) -> Result<()> { /// Gets the group IDs of all groups that `user` is a member of. The additional /// group `group` is also added to the list. /// -/// [Further reading](https://man7.org/linux/man-pages/man3/getgrouplist.3.html) +/// [Further reading](http://man7.org/linux/man-pages/man3/getgrouplist.3.html) /// /// **Note:** This function is not available for Apple platforms. On those /// platforms, checking group membership should be achieved via communication @@ -1530,17 +1507,15 @@ pub fn setgroups(groups: &[Gid]) -> Result<()> { /// and `setgroups()`. Additionally, while some implementations will return a /// partial list of groups when `NGROUPS_MAX` is exceeded, this implementation /// will only ever return the complete list or else an error. -#[cfg(not(any(target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "redox")))] +#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))] pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> { let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) { Ok(Some(n)) => n as c_int, Ok(None) | Err(_) => <c_int>::max_value(), }; use std::cmp::min; - let mut groups = Vec::<Gid>::with_capacity(min(ngroups_max, 8) as usize); + let mut ngroups = min(ngroups_max, 8); + let mut groups = Vec::<Gid>::with_capacity(ngroups as usize); cfg_if! { if #[cfg(any(target_os = "ios", target_os = "macos"))] { type getgrouplist_group_t = c_int; @@ -1550,7 +1525,6 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> { } let gid: gid_t = group.into(); loop { - let mut ngroups = groups.capacity() as i32; let ret = unsafe { libc::getgrouplist(user.as_ptr(), gid as getgrouplist_group_t, @@ -1568,7 +1542,7 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> { // groups as possible, but Linux manpages do not mention this // behavior. reserve_double_buffer_size(&mut groups, ngroups_max as usize) - .map_err(|_| Errno::EINVAL)?; + .or_else(|_| Err(Error::invalid_argument()))?; } } } @@ -1579,7 +1553,7 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> { /// that `user` is a member of. The additional group `group` is also added to /// the list. /// -/// [Further reading](https://man7.org/linux/man-pages/man3/initgroups.3.html) +/// [Further reading](http://man7.org/linux/man-pages/man3/initgroups.3.html) /// /// **Note:** This function is not available for Apple platforms. On those /// platforms, group membership management should be achieved via communication @@ -1628,7 +1602,7 @@ pub fn initgroups(user: &CStr, group: Gid) -> Result<()> { /// Suspend the thread until a signal is received. /// -/// See also [pause(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pause.html). +/// See also [pause(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pause.html). #[inline] #[cfg(not(target_os = "redox"))] pub fn pause() { @@ -1673,18 +1647,17 @@ pub mod alarm { //! extern fn signal_handler(_: nix::libc::c_int) { } //! let sa = SigAction::new( //! SigHandler::Handler(signal_handler), - //! SaFlags::SA_RESTART, + //! SaFlags::empty(), //! SigSet::empty() //! ); //! unsafe { //! sigaction(Signal::SIGALRM, &sa); //! } //! - //! let start = Instant::now(); - //! //! // Set an alarm for 1 second from now. //! alarm::set(1); //! + //! let start = Instant::now(); //! // Pause the process until the alarm signal is received. //! let mut sigset = SigSet::empty(); //! sigset.add(Signal::SIGALRM); @@ -1695,7 +1668,7 @@ pub mod alarm { //! //! # References //! - //! See also [alarm(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/alarm.html). + //! See also [alarm(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/alarm.html). /// Schedule an alarm signal. /// @@ -1725,7 +1698,7 @@ pub mod alarm { /// Suspend execution for an interval of time /// -/// See also [sleep(2)](https://pubs.opengroup.org/onlinepubs/009695399/functions/sleep.html#tag_03_705_05) +/// See also [sleep(2)](http://pubs.opengroup.org/onlinepubs/009695399/functions/sleep.html#tag_03_705_05) // Per POSIX, does not fail #[inline] pub fn sleep(seconds: c_uint) -> c_uint { @@ -1765,7 +1738,7 @@ pub mod acct { /// Err is returned either if no temporary filename could be created or the template doesn't /// end with XXXXXX /// -/// See also [mkstemp(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkstemp.html) +/// See also [mkstemp(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkstemp.html) /// /// # Example /// @@ -1796,7 +1769,7 @@ pub fn mkstemp<P: ?Sized + NixPath>(template: &P) -> Result<(RawFd, PathBuf)> { /// Variable names for `pathconf` /// /// Nix uses the same naming convention for these variables as the -/// [getconf(1)](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/getconf.html) utility. +/// [getconf(1)](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/getconf.html) utility. /// That is, `PathconfVar` variables have the same name as the abstract /// variables shown in the `pathconf(2)` man page. Usually, it's the same as /// the C variable name without the leading `_PC_`. @@ -1806,12 +1779,11 @@ pub fn mkstemp<P: ?Sized + NixPath>(template: &P) -> Result<(RawFd, PathBuf)> { /// /// # References /// -/// - [pathconf(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html) -/// - [limits.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html) -/// - [unistd.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html) +/// - [pathconf(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html) +/// - [limits.h](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html) +/// - [unistd.h](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html) #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[repr(i32)] -#[non_exhaustive] pub enum PathconfVar { #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux", target_os = "netbsd", target_os = "openbsd", target_os = "redox"))] @@ -1837,9 +1809,8 @@ pub enum PathconfVar { /// Maximum number of bytes that is guaranteed to be atomic when writing to /// a pipe. PIPE_BUF = libc::_PC_PIPE_BUF, - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "illumos", - target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_os = "redox", target_os = "solaris"))] + #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "linux", + target_os = "netbsd", target_os = "openbsd", target_os = "redox"))] /// Symbolic links can be created. POSIX2_SYMLINKS = libc::_PC_2_SYMLINKS, #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", @@ -1865,8 +1836,8 @@ pub enum PathconfVar { /// Recommended file transfer buffer alignment. POSIX_REC_XFER_ALIGN = libc::_PC_REC_XFER_ALIGN, #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "illumos", target_os = "linux", target_os = "netbsd", - target_os = "openbsd", target_os = "redox", target_os = "solaris"))] + target_os = "linux", target_os = "netbsd", target_os = "openbsd", + target_os = "redox"))] /// Maximum number of bytes in a symbolic link. SYMLINK_MAX = libc::_PC_SYMLINK_MAX, /// The use of `chown` and `fchown` is restricted to a process with @@ -1880,20 +1851,18 @@ pub enum PathconfVar { /// disable terminal special character handling. _POSIX_VDISABLE = libc::_PC_VDISABLE, #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "illumos", target_os = "linux", target_os = "openbsd", - target_os = "redox", target_os = "solaris"))] + target_os = "linux", target_os = "openbsd", target_os = "redox"))] /// Asynchronous input or output operations may be performed for the /// associated file. _POSIX_ASYNC_IO = libc::_PC_ASYNC_IO, #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "illumos", target_os = "linux", target_os = "openbsd", - target_os = "redox", target_os = "solaris"))] + target_os = "linux", target_os = "openbsd", target_os = "redox"))] /// Prioritized input or output operations may be performed for the /// associated file. _POSIX_PRIO_IO = libc::_PC_PRIO_IO, #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "illumos", target_os = "linux", target_os = "netbsd", - target_os = "openbsd", target_os = "redox", target_os = "solaris"))] + target_os = "linux", target_os = "netbsd", target_os = "openbsd", + target_os = "redox"))] /// Synchronized input or output operations may be performed for the /// associated file. _POSIX_SYNC_IO = libc::_PC_SYNC_IO, @@ -1903,7 +1872,7 @@ pub enum PathconfVar { } /// Like `pathconf`, but works with file descriptors instead of paths (see -/// [fpathconf(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html)) +/// [fpathconf(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html)) /// /// # Parameters /// @@ -1927,7 +1896,7 @@ pub fn fpathconf(fd: RawFd, var: PathconfVar) -> Result<Option<c_long>> { if errno::errno() == 0 { Ok(None) } else { - Err(Errno::last()) + Err(Error::Sys(Errno::last())) } } else { Ok(Some(raw)) @@ -1935,12 +1904,12 @@ pub fn fpathconf(fd: RawFd, var: PathconfVar) -> Result<Option<c_long>> { } /// Get path-dependent configurable system variables (see -/// [pathconf(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html)) +/// [pathconf(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html)) /// /// Returns the value of a path-dependent configurable system variable. Most /// supported variables also have associated compile-time constants, but POSIX /// allows their values to change at runtime. There are generally two types of -/// `pathconf` variables: options and limits. See [pathconf(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html) for more details. +/// `pathconf` variables: options and limits. See [pathconf(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html) for more details. /// /// # Parameters /// @@ -1966,7 +1935,7 @@ pub fn pathconf<P: ?Sized + NixPath>(path: &P, var: PathconfVar) -> Result<Optio if errno::errno() == 0 { Ok(None) } else { - Err(Errno::last()) + Err(Error::Sys(Errno::last())) } } else { Ok(Some(raw)) @@ -1976,7 +1945,7 @@ pub fn pathconf<P: ?Sized + NixPath>(path: &P, var: PathconfVar) -> Result<Optio /// Variable names for `sysconf` /// /// Nix uses the same naming convention for these variables as the -/// [getconf(1)](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/getconf.html) utility. +/// [getconf(1)](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/getconf.html) utility. /// That is, `SysconfVar` variables have the same name as the abstract variables /// shown in the `sysconf(3)` man page. Usually, it's the same as the C /// variable name without the leading `_SC_`. @@ -1986,12 +1955,11 @@ pub fn pathconf<P: ?Sized + NixPath>(path: &P, var: PathconfVar) -> Result<Optio /// /// # References /// -/// - [sysconf(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html) -/// - [unistd.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html) -/// - [limits.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html) +/// - [sysconf(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html) +/// - [unistd.h](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html) +/// - [limits.h](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html) #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[repr(i32)] -#[non_exhaustive] pub enum SysconfVar { /// Maximum number of I/O operations in a single list I/O call supported by /// the implementation. @@ -2039,9 +2007,9 @@ pub enum SysconfVar { /// the expr utility. #[cfg(not(target_os = "redox"))] EXPR_NEST_MAX = libc::_SC_EXPR_NEST_MAX, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="netbsd", target_os="openbsd", target_os = "solaris"))] + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", + target_os="openbsd"))] /// Maximum length of a host name (not including the terminating null) as /// returned from the `gethostname` function HOST_NAME_MAX = libc::_SC_HOST_NAME_MAX, @@ -2078,30 +2046,29 @@ pub enum SysconfVar { target_os="linux", target_os = "macos", target_os="openbsd"))] /// The implementation supports the Advisory Information option. _POSIX_ADVISORY_INFO = libc::_SC_ADVISORY_INFO, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="netbsd", target_os="openbsd", target_os = "solaris"))] + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", + target_os="openbsd"))] /// The implementation supports barriers. _POSIX_BARRIERS = libc::_SC_BARRIERS, /// The implementation supports asynchronous input and output. #[cfg(not(target_os = "redox"))] _POSIX_ASYNCHRONOUS_IO = libc::_SC_ASYNCHRONOUS_IO, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="netbsd", target_os="openbsd", target_os = "solaris"))] + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", + target_os="openbsd"))] /// The implementation supports clock selection. _POSIX_CLOCK_SELECTION = libc::_SC_CLOCK_SELECTION, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="netbsd", target_os="openbsd", target_os = "solaris"))] + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", + target_os="openbsd"))] /// The implementation supports the Process CPU-Time Clocks option. _POSIX_CPUTIME = libc::_SC_CPUTIME, /// The implementation supports the File Synchronization option. #[cfg(not(target_os = "redox"))] _POSIX_FSYNC = libc::_SC_FSYNC, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd", target_os = "solaris"))] + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="openbsd"))] /// The implementation supports the IPv6 option. _POSIX_IPV6 = libc::_SC_IPV6, /// The implementation supports job control. @@ -2126,21 +2093,20 @@ pub enum SysconfVar { #[cfg(not(target_os = "redox"))] _POSIX_MONOTONIC_CLOCK = libc::_SC_MONOTONIC_CLOCK, #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", - target_os = "illumos", target_os = "ios", target_os="linux", - target_os = "macos", target_os="openbsd", target_os = "solaris"))] + target_os = "ios", target_os="linux", target_os = "macos", + target_os="openbsd"))] /// The implementation supports the Prioritized Input and Output option. _POSIX_PRIORITIZED_IO = libc::_SC_PRIORITIZED_IO, /// The implementation supports the Process Scheduling option. #[cfg(not(target_os = "redox"))] _POSIX_PRIORITY_SCHEDULING = libc::_SC_PRIORITY_SCHEDULING, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd", target_os = "solaris"))] + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="openbsd"))] /// The implementation supports the Raw Sockets option. _POSIX_RAW_SOCKETS = libc::_SC_RAW_SOCKETS, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="netbsd", target_os="openbsd", target_os = "solaris"))] + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", + target_os="openbsd"))] /// The implementation supports read-write locks. _POSIX_READER_WRITER_LOCKS = libc::_SC_READER_WRITER_LOCKS, #[cfg(any(target_os = "android", target_os="dragonfly", target_os="freebsd", @@ -2148,9 +2114,9 @@ pub enum SysconfVar { target_os = "openbsd"))] /// The implementation supports realtime signals. _POSIX_REALTIME_SIGNALS = libc::_SC_REALTIME_SIGNALS, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="netbsd", target_os="openbsd", target_os = "solaris"))] + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", + target_os="openbsd"))] /// The implementation supports the Regular Expression Handling option. _POSIX_REGEXP = libc::_SC_REGEXP, /// Each process has a saved set-user-ID and a saved set-group-ID. @@ -2442,7 +2408,7 @@ pub enum SysconfVar { } /// Get configurable system variables (see -/// [sysconf(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html)) +/// [sysconf(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html)) /// /// Returns the value of a configurable system variable. Most supported /// variables also have associated compile-time constants, but POSIX @@ -2466,7 +2432,7 @@ pub fn sysconf(var: SysconfVar) -> Result<Option<c_long>> { if errno::errno() == 0 { Ok(None) } else { - Err(Errno::last()) + Err(Error::Sys(Errno::last())) } } else { Ok(Some(raw)) @@ -2500,7 +2466,7 @@ mod setres { use super::{Uid, Gid}; /// Sets the real, effective, and saved uid. - /// ([see setresuid(2)](https://man7.org/linux/man-pages/man2/setresuid.2.html)) + /// ([see setresuid(2)](http://man7.org/linux/man-pages/man2/setresuid.2.html)) /// /// * `ruid`: real user id /// * `euid`: effective user id @@ -2516,7 +2482,7 @@ mod setres { } /// Sets the real, effective, and saved gid. - /// ([see setresuid(2)](https://man7.org/linux/man-pages/man2/setresuid.2.html)) + /// ([see setresuid(2)](http://man7.org/linux/man-pages/man2/setresuid.2.html)) /// /// * `rgid`: real group id /// * `egid`: effective group id @@ -2532,67 +2498,6 @@ mod setres { } } -#[cfg(any(target_os = "android", target_os = "linux"))] -mod getres { - use crate::Result; - use crate::errno::Errno; - use super::{Uid, Gid}; - - /// Real, effective and saved user IDs. - #[derive(Debug, Copy, Clone, Eq, PartialEq)] - pub struct ResUid { - pub real: Uid, - pub effective: Uid, - pub saved: Uid - } - - /// Real, effective and saved group IDs. - #[derive(Debug, Copy, Clone, Eq, PartialEq)] - pub struct ResGid { - pub real: Gid, - pub effective: Gid, - pub saved: Gid - } - - /// Gets the real, effective, and saved user IDs. - /// - /// ([see getresuid(2)](http://man7.org/linux/man-pages/man2/getresuid.2.html)) - /// - /// #Returns - /// - /// - `Ok((Uid, Uid, Uid))`: tuple of real, effective and saved uids on success. - /// - `Err(x)`: libc error code on failure. - /// - #[inline] - pub fn getresuid() -> Result<ResUid> { - let mut ruid = libc::uid_t::max_value(); - let mut euid = libc::uid_t::max_value(); - let mut suid = libc::uid_t::max_value(); - let res = unsafe { libc::getresuid(&mut ruid, &mut euid, &mut suid) }; - - Errno::result(res).map(|_| ResUid{ real: Uid(ruid), effective: Uid(euid), saved: Uid(suid) }) - } - - /// Gets the real, effective, and saved group IDs. - /// - /// ([see getresgid(2)](http://man7.org/linux/man-pages/man2/getresgid.2.html)) - /// - /// #Returns - /// - /// - `Ok((Gid, Gid, Gid))`: tuple of real, effective and saved gids on success. - /// - `Err(x)`: libc error code on failure. - /// - #[inline] - pub fn getresgid() -> Result<ResGid> { - let mut rgid = libc::gid_t::max_value(); - let mut egid = libc::gid_t::max_value(); - let mut sgid = libc::gid_t::max_value(); - let res = unsafe { libc::getresgid(&mut rgid, &mut egid, &mut sgid) }; - - Errno::result(res).map(|_| ResGid { real: Gid(rgid), effective: Gid(egid), saved: Gid(sgid) } ) - } -} - libc_bitflags!{ /// Options for access() pub struct AccessFlags : c_int { @@ -2608,7 +2513,7 @@ libc_bitflags!{ } /// Checks the file named by `path` for accessibility according to the flags given by `amode` -/// See [access(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html) +/// See [access(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html) pub fn access<P: ?Sized + NixPath>(path: &P, amode: AccessFlags) -> Result<()> { let res = path.with_nix_path(|cstr| { unsafe { @@ -2636,32 +2541,23 @@ pub struct User { /// Group ID pub gid: Gid, /// User information - #[cfg(not(all(target_os = "android", target_pointer_width = "32")))] + #[cfg(not(target_os = "android"))] pub gecos: CString, /// Home directory pub dir: PathBuf, /// Path to shell pub shell: PathBuf, /// Login class - #[cfg(not(any(target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] + #[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 = "fuchsia", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] + #[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 = "fuchsia", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] + #[cfg(not(any(target_os = "android", target_os = "fuchsia", + target_os = "linux")))] pub expire: libc::time_t } @@ -2672,29 +2568,20 @@ impl From<&libc::passwd> for User { User { name: CStr::from_ptr((*pw).pw_name).to_string_lossy().into_owned(), passwd: CString::new(CStr::from_ptr((*pw).pw_passwd).to_bytes()).unwrap(), - #[cfg(not(all(target_os = "android", target_pointer_width = "32")))] + #[cfg(not(target_os = "android"))] gecos: CString::new(CStr::from_ptr((*pw).pw_gecos).to_bytes()).unwrap(), dir: PathBuf::from(OsStr::from_bytes(CStr::from_ptr((*pw).pw_dir).to_bytes())), shell: PathBuf::from(OsStr::from_bytes(CStr::from_ptr((*pw).pw_shell).to_bytes())), uid: Uid::from_raw((*pw).pw_uid), gid: Gid::from_raw((*pw).pw_gid), - #[cfg(not(any(target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] + #[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 = "fuchsia", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] + #[cfg(not(any(target_os = "android", target_os = "fuchsia", + target_os = "linux")))] change: (*pw).pw_change, - #[cfg(not(any(target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] + #[cfg(not(any(target_os = "android", target_os = "fuchsia", + target_os = "linux")))] expire: (*pw).pw_expire } } @@ -2702,58 +2589,6 @@ impl From<&libc::passwd> for User { } #[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd -impl From<User> for libc::passwd { - fn from(u: User) -> Self { - let name = match CString::new(u.name) { - Ok(n) => n.into_raw(), - Err(_) => CString::new("").unwrap().into_raw(), - }; - let dir = match u.dir.into_os_string().into_string() { - Ok(s) => CString::new(s.as_str()).unwrap().into_raw(), - Err(_) => CString::new("").unwrap().into_raw(), - }; - let shell = match u.shell.into_os_string().into_string() { - Ok(s) => CString::new(s.as_str()).unwrap().into_raw(), - Err(_) => CString::new("").unwrap().into_raw(), - }; - Self { - pw_name: name, - pw_passwd: u.passwd.into_raw(), - #[cfg(not(all(target_os = "android", target_pointer_width = "32")))] - pw_gecos: u.gecos.into_raw(), - pw_dir: dir, - pw_shell: shell, - pw_uid: u.uid.0, - pw_gid: u.gid.0, - #[cfg(not(any(target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] - pw_class: u.class.into_raw(), - #[cfg(not(any(target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] - pw_change: u.change, - #[cfg(not(any(target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] - pw_expire: u.expire, - #[cfg(target_os = "illumos")] - pw_age: CString::new("").unwrap().into_raw(), - #[cfg(target_os = "illumos")] - pw_comment: CString::new("").unwrap().into_raw(), - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - pw_fields: 0, - } - } -} - -#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd impl User { fn from_anything<F>(f: F) -> Result<Option<Self>> where @@ -2762,10 +2597,10 @@ impl User { libc::size_t, *mut *mut libc::passwd) -> libc::c_int { - let buflimit = 1048576; + let buflimit = 16384; let bufsize = match sysconf(SysconfVar::GETPW_R_SIZE_MAX) { Ok(Some(n)) => n as usize, - Ok(None) | Err(_) => 16384, + Ok(None) | Err(_) => buflimit as usize, }; let mut cbuf = Vec::with_capacity(bufsize); @@ -2785,7 +2620,7 @@ impl User { // Trigger the internal buffer resizing logic. reserve_double_buffer_size(&mut cbuf, buflimit)?; } else { - return Err(Errno::last()); + return Err(Error::Sys(Errno::last())); } } } @@ -2793,7 +2628,7 @@ impl User { /// Get a user by UID. /// /// Internally, this function calls - /// [getpwuid_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) + /// [getpwuid_r(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) /// /// # Examples /// @@ -2812,7 +2647,7 @@ impl User { /// Get a user by name. /// /// Internally, this function calls - /// [getpwnam_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) + /// [getpwnam_r(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) /// /// # Examples /// @@ -2883,10 +2718,10 @@ impl Group { libc::size_t, *mut *mut libc::group) -> libc::c_int { - let buflimit = 1048576; + let buflimit = 16384; let bufsize = match sysconf(SysconfVar::GETGR_R_SIZE_MAX) { Ok(Some(n)) => n as usize, - Ok(None) | Err(_) => 16384, + Ok(None) | Err(_) => buflimit as usize, }; let mut cbuf = Vec::with_capacity(bufsize); @@ -2906,7 +2741,7 @@ impl Group { // Trigger the internal buffer resizing logic. reserve_double_buffer_size(&mut cbuf, buflimit)?; } else { - return Err(Errno::last()); + return Err(Error::Sys(Errno::last())); } } } @@ -2914,7 +2749,7 @@ impl Group { /// Get a group by GID. /// /// Internally, this function calls - /// [getgrgid_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) + /// [getgrgid_r(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) /// /// # Examples /// @@ -2935,7 +2770,7 @@ impl Group { /// Get a group by name. /// /// Internally, this function calls - /// [getgrnam_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) + /// [getgrnam_r(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) /// /// # Examples /// @@ -2956,7 +2791,7 @@ impl Group { } /// Get the name of the terminal device that is open on file descriptor fd -/// (see [`ttyname(3)`](https://man7.org/linux/man-pages/man3/ttyname.3.html)). +/// (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; @@ -2965,7 +2800,7 @@ pub fn ttyname(fd: RawFd) -> Result<PathBuf> { let ret = unsafe { libc::ttyname_r(fd, c_buf, buf.len()) }; if ret != 0 { - return Err(Errno::from_i32(ret)); + return Err(Error::Sys(Errno::from_i32(ret))); } let nul = buf.iter().position(|c| *c == b'\0').unwrap(); diff --git a/test/common/mod.rs b/test/common/mod.rs index 84a0b4f..a871b47 100644 --- a/test/common/mod.rs +++ b/test/common/mod.rs @@ -14,33 +14,19 @@ use cfg_if::cfg_if; cfg_if! { if #[cfg(any(target_os = "android", target_os = "linux"))] { #[macro_export] macro_rules! require_capability { - ($name:expr, $capname:ident) => { + ($capname:ident) => { use ::caps::{Capability, CapSet, has_cap}; if !has_cap(None, CapSet::Effective, Capability::$capname) .unwrap() { - skip!("{} requires capability {}. Skipping test.", $name, Capability::$capname); + skip!("Insufficient capabilities. Skipping test."); } } } } else if #[cfg(not(target_os = "redox"))] { #[macro_export] macro_rules! require_capability { - ($name:expr, $capname:ident) => {} - } - } -} - -/// Skip the test if we don't have the ability to mount file systems. -#[cfg(target_os = "freebsd")] -#[macro_export] macro_rules! require_mount { - ($name:expr) => { - use ::sysctl::CtlValue; - use nix::unistd::Uid; - - if !Uid::current().is_root() && CtlValue::Int(0) == ::sysctl::value("vfs.usermount").unwrap() - { - skip!("{} requires the ability to mount file systems. Skipping test.", $name); + ($capname:ident) => {} } } } @@ -128,8 +114,8 @@ cfg_if! { let mut version = Version::parse(fixed_release).unwrap(); //Keep only numeric parts - version.pre = semver::Prerelease::EMPTY; - version.build = semver::BuildMetadata::EMPTY; + version.pre.clear(); + version.build.clear(); if !version_requirement.matches(&version) { skip!("Skip {} because kernel version `{}` doesn't match the requirement `{}`", diff --git a/test/sys/mod.rs b/test/sys/mod.rs index e73d9b1..14b0378 100644 --- a/test/sys/mod.rs +++ b/test/sys/mod.rs @@ -11,8 +11,6 @@ mod test_signal; target_os = "macos", target_os = "netbsd"))] mod test_aio; -#[cfg(not(target_os = "redox"))] -mod test_mman; #[cfg(target_os = "linux")] mod test_signalfd; #[cfg(not(target_os = "redox"))] diff --git a/test/sys/test_aio.rs b/test/sys/test_aio.rs index 80cd053..3878da9 100644 --- a/test/sys/test_aio.rs +++ b/test/sys/test_aio.rs @@ -1,5 +1,6 @@ +use bytes::{Bytes, BytesMut}; use libc::{c_int, c_void}; -use nix::Result; +use nix::{Error, Result}; use nix::errno::*; use nix::sys::aio::*; use nix::sys::signal::{SaFlags, SigAction, sigaction, SigevNotify, SigHandler, Signal, SigSet}; @@ -7,26 +8,15 @@ use nix::sys::time::{TimeSpec, TimeValLike}; use std::io::{Write, Read, Seek, SeekFrom}; use std::ops::Deref; use std::os::unix::io::AsRawFd; -use std::pin::Pin; use std::sync::atomic::{AtomicBool, Ordering}; use std::{thread, time}; use tempfile::tempfile; // Helper that polls an AioCb for completion or error -fn poll_aio(aiocb: &mut Pin<Box<AioCb>>) -> Result<()> { +fn poll_aio(aiocb: &mut AioCb) -> Result<()> { loop { let err = aiocb.error(); - if err != Err(Errno::EINPROGRESS) { return err; }; - thread::sleep(time::Duration::from_millis(10)); - } -} - -// Helper that polls a component of an LioCb for completion or error -#[cfg(not(any(target_os = "ios", target_os = "macos")))] -fn poll_lio(liocb: &mut LioCb, i: usize) -> Result<()> { - loop { - let err = liocb.error(i); - if err != Err(Errno::EINPROGRESS) { return err; }; + if err != Err(Error::from(Errno::EINPROGRESS)) { return err; }; thread::sleep(time::Duration::from_millis(10)); } } @@ -70,7 +60,7 @@ fn test_cancel() { LioOpcode::LIO_NOP); aiocb.write().unwrap(); let err = aiocb.error(); - assert!(err == Ok(()) || err == Err(Errno::EINPROGRESS)); + assert!(err == Ok(()) || err == Err(Error::from(Errno::EINPROGRESS))); let cancelstat = aiocb.cancel(); assert!(cancelstat.is_ok()); @@ -95,7 +85,7 @@ fn test_aio_cancel_all() { LioOpcode::LIO_NOP); aiocb.write().unwrap(); let err = aiocb.error(); - assert!(err == Ok(()) || err == Err(Errno::EINPROGRESS)); + assert!(err == Ok(()) || err == Err(Error::from(Errno::EINPROGRESS))); let cancelstat = aio_cancel_all(f.as_raw_fd()); assert!(cancelstat.is_ok()); @@ -142,7 +132,9 @@ fn test_fsync_error() { } #[test] -// On Cirrus on Linux, this test fails due to a glibc bug. +#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] +// On Travis, aio_suspend hits an assertion within glibc. This is either a bug +// 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 @@ -174,16 +166,16 @@ fn test_aio_suspend() { rcb.read().unwrap(); loop { { - let cbbuf = [wcb.as_ref(), rcb.as_ref()]; + let cbbuf = [&wcb, &rcb]; let r = aio_suspend(&cbbuf[..], Some(timeout)); match r { - Err(Errno::EINTR) => continue, + Err(Error::Sys(Errno::EINTR)) => continue, Err(e) => panic!("aio_suspend returned {:?}", e), Ok(_) => () }; } - if rcb.error() != Err(Errno::EINPROGRESS) && - wcb.error() != Err(Errno::EINPROGRESS) { + if rcb.error() != Err(Error::from(Errno::EINPROGRESS)) && + wcb.error() != Err(Error::from(Errno::EINPROGRESS)) { break } } @@ -343,6 +335,61 @@ fn test_write() { assert_eq!(rbuf, EXPECT); } +// Tests `AioCb::from_boxed_slice` with `Bytes` +#[test] +#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] +fn test_write_bytes() { + const INITIAL: &[u8] = b"abcdef123456"; + let wbuf = Box::new(Bytes::from(&b"CDEF"[..])); + let mut rbuf = Vec::new(); + const EXPECT: &[u8] = b"abCDEF123456"; + let expected_len = wbuf.len(); + + let mut f = tempfile().unwrap(); + f.write_all(INITIAL).unwrap(); + let mut aiocb = AioCb::from_boxed_slice( f.as_raw_fd(), + 2, //offset + wbuf, + 0, //priority + SigevNotify::SigevNone, + LioOpcode::LIO_NOP); + aiocb.write().unwrap(); + + let err = poll_aio(&mut aiocb); + assert_eq!(err, Ok(())); + assert_eq!(aiocb.aio_return().unwrap() as usize, expected_len); + + f.seek(SeekFrom::Start(0)).unwrap(); + let len = f.read_to_end(&mut rbuf).unwrap(); + assert_eq!(len, EXPECT.len()); + assert_eq!(rbuf, EXPECT); +} + +// Tests `AioCb::from_boxed_mut_slice` with `BytesMut` +#[test] +#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] +fn test_read_bytes_mut_small() { + const INITIAL: &[u8] = b"abcdef"; + let rbuf = Box::new(BytesMut::from(vec![0; 4])); + const EXPECT: &[u8] = b"cdef"; + let mut f = tempfile().unwrap(); + f.write_all(INITIAL).unwrap(); + + let mut aiocb = AioCb::from_boxed_mut_slice( f.as_raw_fd(), + 2, //offset + rbuf, + 0, //priority + SigevNotify::SigevNone, + LioOpcode::LIO_NOP); + aiocb.read().unwrap(); + + let err = poll_aio(&mut aiocb); + assert_eq!(err, Ok(())); + assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len()); + let buffer = aiocb.boxed_mut_slice().unwrap(); + assert_eq!(buffer.borrow(), EXPECT); +} + // Tests `AioCb::from_ptr` #[test] #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] @@ -406,7 +453,7 @@ extern fn sigfunc(_: c_int) { #[test] #[cfg_attr(any(all(target_env = "musl", target_arch = "x86_64"), target_arch = "mips", target_arch = "mips64"), ignore)] fn test_write_sigev_signal() { - let _m = crate::SIGNAL_MTX.lock(); + let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); let sa = SigAction::new(SigHandler::Handler(sigfunc), SaFlags::SA_RESETHAND, SigSet::empty()); @@ -458,22 +505,22 @@ fn test_liocb_listio_wait() { f.write_all(INITIAL).unwrap(); { - let mut liocb = LioCbBuilder::with_capacity(2) - .emplace_slice( - f.as_raw_fd(), - 2, //offset - WBUF, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_WRITE - ).emplace_mut_slice( - f.as_raw_fd(), - 8, //offset - &mut rbuf, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_READ - ).finish(); + let wcb = AioCb::from_slice( f.as_raw_fd(), + 2, //offset + WBUF, + 0, //priority + SigevNotify::SigevNone, + LioOpcode::LIO_WRITE); + + let rcb = AioCb::from_mut_slice( f.as_raw_fd(), + 8, //offset + &mut rbuf, + 0, //priority + SigevNotify::SigevNone, + LioOpcode::LIO_READ); + let mut liocb = LioCb::with_capacity(2); + liocb.aiocbs.push(wcb); + liocb.aiocbs.push(rcb); let err = liocb.listio(LioMode::LIO_WAIT, SigevNotify::SigevNone); err.expect("lio_listio"); @@ -505,29 +552,29 @@ fn test_liocb_listio_nowait() { f.write_all(INITIAL).unwrap(); { - let mut liocb = LioCbBuilder::with_capacity(2) - .emplace_slice( - f.as_raw_fd(), - 2, //offset - WBUF, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_WRITE - ).emplace_mut_slice( - f.as_raw_fd(), - 8, //offset - &mut rbuf, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_READ - ).finish(); + let wcb = AioCb::from_slice( f.as_raw_fd(), + 2, //offset + WBUF, + 0, //priority + SigevNotify::SigevNone, + LioOpcode::LIO_WRITE); + + let rcb = AioCb::from_mut_slice( f.as_raw_fd(), + 8, //offset + &mut rbuf, + 0, //priority + SigevNotify::SigevNone, + LioOpcode::LIO_READ); + let mut liocb = LioCb::with_capacity(2); + liocb.aiocbs.push(wcb); + liocb.aiocbs.push(rcb); let err = liocb.listio(LioMode::LIO_NOWAIT, SigevNotify::SigevNone); err.expect("lio_listio"); - poll_lio(&mut liocb, 0).unwrap(); - poll_lio(&mut liocb, 1).unwrap(); - assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len()); - assert_eq!(liocb.aio_return(1).unwrap() as usize, rlen); + poll_aio(&mut liocb.aiocbs[0]).unwrap(); + poll_aio(&mut liocb.aiocbs[1]).unwrap(); + assert_eq!(liocb.aiocbs[0].aio_return().unwrap() as usize, WBUF.len()); + assert_eq!(liocb.aiocbs[1].aio_return().unwrap() as usize, rlen); } assert_eq!(rbuf.deref().deref(), b"3456"); @@ -544,7 +591,7 @@ fn test_liocb_listio_nowait() { #[cfg(not(any(target_os = "ios", target_os = "macos")))] #[cfg_attr(any(target_arch = "mips", target_arch = "mips64", target_env = "musl"), ignore)] fn test_liocb_listio_signal() { - let _m = crate::SIGNAL_MTX.lock(); + let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); const INITIAL: &[u8] = b"abcdef123456"; const WBUF: &[u8] = b"CDEF"; let mut rbuf = vec![0; 4]; @@ -561,22 +608,22 @@ fn test_liocb_listio_signal() { f.write_all(INITIAL).unwrap(); { - let mut liocb = LioCbBuilder::with_capacity(2) - .emplace_slice( - f.as_raw_fd(), - 2, //offset - WBUF, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_WRITE - ).emplace_mut_slice( - f.as_raw_fd(), - 8, //offset - &mut rbuf, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_READ - ).finish(); + let wcb = AioCb::from_slice( f.as_raw_fd(), + 2, //offset + WBUF, + 0, //priority + SigevNotify::SigevNone, + LioOpcode::LIO_WRITE); + + let rcb = AioCb::from_mut_slice( f.as_raw_fd(), + 8, //offset + &mut rbuf, + 0, //priority + SigevNotify::SigevNone, + LioOpcode::LIO_READ); + let mut liocb = LioCb::with_capacity(2); + liocb.aiocbs.push(wcb); + liocb.aiocbs.push(rcb); SIGNALED.store(false, Ordering::Relaxed); unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap(); let err = liocb.listio(LioMode::LIO_NOWAIT, sigev_notify); @@ -585,8 +632,8 @@ fn test_liocb_listio_signal() { thread::sleep(time::Duration::from_millis(10)); } - assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len()); - assert_eq!(liocb.aio_return(1).unwrap() as usize, rlen); + assert_eq!(liocb.aiocbs[0].aio_return().unwrap() as usize, WBUF.len()); + assert_eq!(liocb.aiocbs[1].aio_return().unwrap() as usize, rlen); } assert_eq!(rbuf.deref().deref(), b"3456"); @@ -607,14 +654,13 @@ fn test_liocb_listio_read_immutable() { let f = tempfile().unwrap(); - let mut liocb = LioCbBuilder::with_capacity(1) - .emplace_slice( - f.as_raw_fd(), + let mut liocb = LioCb::from(vec![ + AioCb::from_slice( f.as_raw_fd(), 2, //offset rbuf, 0, //priority SigevNotify::SigevNone, - LioOpcode::LIO_READ - ).finish(); + LioOpcode::LIO_READ) + ]); let _ = liocb.listio(LioMode::LIO_NOWAIT, SigevNotify::SigevNone); } 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_epoll.rs b/test/sys/test_epoll.rs index 8d44cd0..e0dc513 100644 --- a/test/sys/test_epoll.rs +++ b/test/sys/test_epoll.rs @@ -1,5 +1,6 @@ use nix::sys::epoll::{EpollCreateFlags, EpollFlags, EpollOp, EpollEvent}; use nix::sys::epoll::{epoll_create1, epoll_ctl}; +use nix::Error; use nix::errno::Errno; #[test] @@ -7,11 +8,11 @@ pub fn test_epoll_errno() { let efd = epoll_create1(EpollCreateFlags::empty()).unwrap(); let result = epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None); assert!(result.is_err()); - assert_eq!(result.unwrap_err(), Errno::ENOENT); + assert_eq!(result.unwrap_err(), Error::Sys(Errno::ENOENT)); let result = epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, None); assert!(result.is_err()); - assert_eq!(result.unwrap_err(), Errno::EINVAL); + assert_eq!(result.unwrap_err(), Error::Sys(Errno::EINVAL)); } #[test] diff --git a/test/sys/test_inotify.rs b/test/sys/test_inotify.rs index 137816a..a8ead46 100644 --- a/test/sys/test_inotify.rs +++ b/test/sys/test_inotify.rs @@ -1,5 +1,7 @@ use nix::sys::inotify::{AddWatchFlags,InitFlags,Inotify}; +use nix::Error; use nix::errno::Errno; +use tempfile; use std::ffi::OsString; use std::fs::{rename, File}; @@ -12,7 +14,7 @@ pub fn test_inotify() { instance.add_watch(tempdir.path(), AddWatchFlags::IN_ALL_EVENTS).unwrap(); let events = instance.read_events(); - assert_eq!(events.unwrap_err(), Errno::EAGAIN); + assert_eq!(events.unwrap_err(), Error::Sys(Errno::EAGAIN)); File::create(tempdir.path().join("test")).unwrap(); @@ -29,7 +31,7 @@ pub fn test_inotify_multi_events() { instance.add_watch(tempdir.path(), AddWatchFlags::IN_ALL_EVENTS).unwrap(); let events = instance.read_events(); - assert_eq!(events.unwrap_err(), Errno::EAGAIN); + assert_eq!(events.unwrap_err(), Error::Sys(Errno::EAGAIN)); File::create(tempdir.path().join("test")).unwrap(); rename(tempdir.path().join("test"), tempdir.path().join("test2")).unwrap(); diff --git a/test/sys/test_ioctl.rs b/test/sys/test_ioctl.rs index 236d242..fa4510a 100644 --- a/test/sys/test_ioctl.rs +++ b/test/sys/test_ioctl.rs @@ -56,10 +56,10 @@ mod linux { #[test] fn test_op_write_64() { if cfg!(any(target_arch = "mips64", target_arch="powerpc64")){ - assert_eq!(request_code_write!(b'z', 10, 1u64 << 32) as u32, + assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32) as u32, 0x8000_7A0A); } else { - assert_eq!(request_code_write!(b'z', 10, 1u64 << 32) as u32, + assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32) as u32, 0x4000_7A0A); } @@ -80,10 +80,10 @@ mod linux { #[test] fn test_op_read_64() { if cfg!(any(target_arch = "mips64", target_arch="powerpc64")){ - assert_eq!(request_code_read!(b'z', 10, 1u64 << 32) as u32, + assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32) as u32, 0x4000_7A0A); } else { - assert_eq!(request_code_read!(b'z', 10, 1u64 << 32) as u32, + assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32) as u32, 0x8000_7A0A); } } @@ -97,7 +97,7 @@ mod linux { #[cfg(target_pointer_width = "64")] #[test] fn test_op_read_write_64() { - assert_eq!(request_code_readwrite!(b'z', 10, 1u64 << 32) as u32, + assert_eq!(request_code_readwrite!(b'z', 10, (1 as u64) << 32) as u32, 0xC000_7A0A); } } @@ -131,7 +131,7 @@ mod bsd { #[cfg(target_pointer_width = "64")] #[test] fn test_op_write_64() { - assert_eq!(request_code_write!(b'z', 10, 1u64 << 32), 0x8000_7A0A); + assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32), 0x8000_7A0A); } #[test] @@ -143,7 +143,7 @@ mod bsd { #[cfg(target_pointer_width = "64")] #[test] fn test_op_read_64() { - assert_eq!(request_code_read!(b'z', 10, 1u64 << 32), 0x4000_7A0A); + assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32), 0x4000_7A0A); } #[test] @@ -155,7 +155,7 @@ mod bsd { #[cfg(target_pointer_width = "64")] #[test] fn test_op_read_write_64() { - assert_eq!(request_code_readwrite!(b'z', 10, 1u64 << 32), 0xC000_7A0A); + assert_eq!(request_code_readwrite!(b'z', 10, (1 as u64) << 32), 0xC000_7A0A); } } @@ -167,14 +167,15 @@ mod linux_ioctls { use tempfile::tempfile; use libc::{TCGETS, TCSBRK, TCSETS, TIOCNXCL, termios}; - use nix::errno::Errno; + use nix::Error::Sys; + use nix::errno::Errno::{ENOTTY, ENOSYS}; ioctl_none_bad!(tiocnxcl, TIOCNXCL); #[test] fn test_ioctl_none_bad() { let file = tempfile().unwrap(); let res = unsafe { tiocnxcl(file.as_raw_fd()) }; - assert_eq!(res, Err(Errno::ENOTTY)); + assert_eq!(res, Err(Sys(ENOTTY))); } ioctl_read_bad!(tcgets, TCGETS, termios); @@ -183,7 +184,7 @@ mod linux_ioctls { let file = tempfile().unwrap(); let mut termios = unsafe { mem::zeroed() }; let res = unsafe { tcgets(file.as_raw_fd(), &mut termios) }; - assert_eq!(res, Err(Errno::ENOTTY)); + assert_eq!(res, Err(Sys(ENOTTY))); } ioctl_write_int_bad!(tcsbrk, TCSBRK); @@ -191,7 +192,7 @@ mod linux_ioctls { fn test_ioctl_write_int_bad() { let file = tempfile().unwrap(); let res = unsafe { tcsbrk(file.as_raw_fd(), 0) }; - assert_eq!(res, Err(Errno::ENOTTY)); + assert_eq!(res, Err(Sys(ENOTTY))); } ioctl_write_ptr_bad!(tcsets, TCSETS, termios); @@ -200,7 +201,7 @@ mod linux_ioctls { let file = tempfile().unwrap(); let termios: termios = unsafe { mem::zeroed() }; let res = unsafe { tcsets(file.as_raw_fd(), &termios) }; - assert_eq!(res, Err(Errno::ENOTTY)); + assert_eq!(res, Err(Sys(ENOTTY))); } // FIXME: Find a suitable example for `ioctl_readwrite_bad` @@ -211,7 +212,7 @@ mod linux_ioctls { fn test_ioctl_none() { let file = tempfile().unwrap(); let res = unsafe { log_status(file.as_raw_fd()) }; - assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS)); + assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS))); } #[repr(C)] @@ -230,7 +231,7 @@ mod linux_ioctls { let file = tempfile().unwrap(); let data: v4l2_audio = unsafe { mem::zeroed() }; let res = unsafe { s_audio(file.as_raw_fd(), &data) }; - assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS)); + assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS))); } // From linux/net/bluetooth/hci_sock.h @@ -241,7 +242,7 @@ mod linux_ioctls { fn test_ioctl_write_int() { let file = tempfile().unwrap(); let res = unsafe { hcidevup(file.as_raw_fd(), 0) }; - assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS)); + assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS))); } // From linux/videodev2.h @@ -251,7 +252,7 @@ mod linux_ioctls { let file = tempfile().unwrap(); let mut data: v4l2_audio = unsafe { mem::zeroed() }; let res = unsafe { g_audio(file.as_raw_fd(), &mut data) }; - assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS)); + assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS))); } // From linux/videodev2.h @@ -261,7 +262,7 @@ mod linux_ioctls { let file = tempfile().unwrap(); let mut data: v4l2_audio = unsafe { mem::zeroed() }; let res = unsafe { enum_audio(file.as_raw_fd(), &mut data) }; - assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS)); + assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS))); } // FIXME: Find a suitable example for `ioctl_read_buf`. @@ -287,7 +288,7 @@ mod linux_ioctls { let file = tempfile().unwrap(); let data: [spi_ioc_transfer; 4] = unsafe { mem::zeroed() }; let res = unsafe { spi_ioc_message(file.as_raw_fd(), &data[..]) }; - assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS)); + assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS))); } // FIXME: Find a suitable example for `ioctl_readwrite_buf`. @@ -301,7 +302,8 @@ mod freebsd_ioctls { use tempfile::tempfile; use libc::termios; - use nix::errno::Errno; + use nix::Error::Sys; + use nix::errno::Errno::ENOTTY; // From sys/sys/ttycom.h const TTY_IOC_MAGIC: u8 = b't'; @@ -314,7 +316,7 @@ mod freebsd_ioctls { fn test_ioctl_none() { let file = tempfile().unwrap(); let res = unsafe { tiocnxcl(file.as_raw_fd()) }; - assert_eq!(res, Err(Errno::ENOTTY)); + assert_eq!(res, Err(Sys(ENOTTY))); } ioctl_read!(tiocgeta, TTY_IOC_MAGIC, TTY_IOC_TYPE_GETA, termios); @@ -323,7 +325,7 @@ mod freebsd_ioctls { let file = tempfile().unwrap(); let mut termios = unsafe { mem::zeroed() }; let res = unsafe { tiocgeta(file.as_raw_fd(), &mut termios) }; - assert_eq!(res, Err(Errno::ENOTTY)); + assert_eq!(res, Err(Sys(ENOTTY))); } ioctl_write_ptr!(tiocseta, TTY_IOC_MAGIC, TTY_IOC_TYPE_SETA, termios); @@ -332,6 +334,6 @@ mod freebsd_ioctls { let file = tempfile().unwrap(); let termios: termios = unsafe { mem::zeroed() }; let res = unsafe { tiocseta(file.as_raw_fd(), &termios) }; - assert_eq!(res, Err(Errno::ENOTTY)); + assert_eq!(res, Err(Sys(ENOTTY))); } } diff --git a/test/sys/test_lio_listio_resubmit.rs b/test/sys/test_lio_listio_resubmit.rs index c907789..0795370 100644 --- a/test/sys/test_lio_listio_resubmit.rs +++ b/test/sys/test_lio_listio_resubmit.rs @@ -4,6 +4,7 @@ // we must disable the test here rather than in Cargo.toml #![cfg(target_os = "freebsd")] +use nix::Error; use nix::errno::*; use nix::libc::off_t; use nix::sys::aio::*; @@ -19,12 +20,12 @@ const BYTES_PER_OP: usize = 512; /// Attempt to collect final status for all of `liocb`'s operations, freeing /// system resources fn finish_liocb(liocb: &mut LioCb) { - for j in 0..liocb.len() { + for j in 0..liocb.aiocbs.len() { loop { let e = liocb.error(j); match e { Ok(()) => break, - Err(Errno::EINPROGRESS) => + Err(Error::Sys(Errno::EINPROGRESS)) => thread::sleep(time::Duration::from_millis(10)), Err(x) => panic!("aio_error({:?})", x) } @@ -69,21 +70,21 @@ fn test_lio_listio_resubmit() { }).collect::<Vec<_>>(); let mut liocbs = (0..num_listios).map(|i| { - let mut builder = LioCbBuilder::with_capacity(ops_per_listio); + let mut liocb = LioCb::with_capacity(ops_per_listio); for j in 0..ops_per_listio { let offset = (BYTES_PER_OP * (i * ops_per_listio + j)) as off_t; - builder = builder.emplace_slice(f.as_raw_fd(), - offset, - &buffer_set[i][j][..], - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_WRITE); + let wcb = AioCb::from_slice( f.as_raw_fd(), + offset, + &buffer_set[i][j][..], + 0, //priority + SigevNotify::SigevNone, + LioOpcode::LIO_WRITE); + liocb.aiocbs.push(wcb); } - let mut liocb = builder.finish(); let mut err = liocb.listio(LioMode::LIO_NOWAIT, SigevNotify::SigevNone); - while err == Err(Errno::EIO) || - err == Err(Errno::EAGAIN) || - err == Err(Errno::EINTR) { + while err == Err(Error::Sys(Errno::EIO)) || + err == Err(Error::Sys(Errno::EAGAIN)) || + err == Err(Error::Sys(Errno::EINTR)) { // thread::sleep(time::Duration::from_millis(10)); resubmit_count += 1; diff --git a/test/sys/test_mman.rs b/test/sys/test_mman.rs index a7ceedc..152fff6 100644 --- a/test/sys/test_mman.rs +++ b/test/sys/test_mman.rs @@ -1,24 +1,27 @@ +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() { - unsafe { + 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() as *mut u8; - assert_eq !(*ptr, 0x00u8); - *ptr = 0xffu8; - assert_eq !(*ptr, 0xffu8); - } + .unwrap(); + *(ptr as * mut u8) + }; + assert_eq !(*byte, 0x00u8); + *byte = 0xffu8; + assert_eq !(*byte, 0xffu8); } #[test] -#[cfg(any(target_os = "linux", target_os = "netbsd"))] +#[cfg(target_os = "linux")] fn test_mremap_grow() { - use nix::sys::mman::{mremap, MRemapFlags}; - use nix::libc::{c_void, size_t}; - const ONE_K : size_t = 1024; let slice : &mut[u8] = unsafe { let mem = mmap(std::ptr::null_mut(), ONE_K, @@ -32,14 +35,9 @@ fn test_mremap_grow() { assert_eq !(slice[ONE_K - 1], 0xFF); let slice : &mut[u8] = unsafe { - #[cfg(target_os = "linux")] let mem = mremap(slice.as_mut_ptr() as * mut c_void, ONE_K, 10 * ONE_K, MRemapFlags::MREMAP_MAYMOVE, None) .unwrap(); - #[cfg(target_os = "netbsd")] - let mem = mremap(slice.as_mut_ptr() as * mut c_void, ONE_K, 10 * ONE_K, - MRemapFlags::MAP_REMAPDUP, None) - .unwrap(); std::slice::from_raw_parts_mut(mem as * mut u8, 10 * ONE_K) }; @@ -53,13 +51,8 @@ fn test_mremap_grow() { } #[test] -#[cfg(any(target_os = "linux", target_os = "netbsd"))] -// Segfaults for unknown reasons under QEMU for 32-bit targets -#[cfg_attr(all(target_pointer_width = "32", qemu), ignore)] +#[cfg(target_os = "linux")] fn test_mremap_shrink() { - use nix::sys::mman::{mremap, MRemapFlags}; - use nix::libc::{c_void, size_t}; - const ONE_K : size_t = 1024; let slice : &mut[u8] = unsafe { let mem = mmap(std::ptr::null_mut(), 10 * ONE_K, @@ -73,16 +66,11 @@ fn test_mremap_shrink() { assert_eq !(slice[ONE_K - 1], 0xFF); let slice : &mut[u8] = unsafe { - #[cfg(target_os = "linux")] 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. - #[cfg(target_os = "netbsd")] - let mem = mremap(slice.as_mut_ptr() as * mut c_void, 10 * ONE_K, ONE_K, - MRemapFlags::MAP_FIXED, None) - .unwrap(); assert_eq !(mem, slice.as_mut_ptr() as * mut c_void); std::slice::from_raw_parts_mut(mem as * mut u8, ONE_K) }; diff --git a/test/sys/test_pthread.rs b/test/sys/test_pthread.rs index fa9b510..1fc3dd9 100644 --- a/test/sys/test_pthread.rs +++ b/test/sys/test_pthread.rs @@ -13,10 +13,3 @@ fn test_pthread_self() { let tid = pthread_self(); assert!(tid != 0); } - -#[test] -#[cfg(not(target_os = "redox"))] -fn test_pthread_kill_none() { - pthread_kill(pthread_self(), None) - .expect("Should be able to send signal to my thread."); -} diff --git a/test/sys/test_ptrace.rs b/test/sys/test_ptrace.rs index 83fff9a..b9793b3 100644 --- a/test/sys/test_ptrace.rs +++ b/test/sys/test_ptrace.rs @@ -1,3 +1,4 @@ +use nix::Error; use nix::errno::Errno; use nix::unistd::getpid; use nix::sys::ptrace; @@ -13,37 +14,37 @@ use crate::*; fn test_ptrace() { // Just make sure ptrace can be called at all, for now. // FIXME: qemu-user doesn't implement ptrace on all arches, so permit ENOSYS - require_capability!("test_ptrace", CAP_SYS_PTRACE); + require_capability!(CAP_SYS_PTRACE); let err = ptrace::attach(getpid()).unwrap_err(); - assert!(err == Errno::EPERM || err == Errno::EINVAL || - err == Errno::ENOSYS); + assert!(err == Error::Sys(Errno::EPERM) || err == Error::Sys(Errno::EINVAL) || + err == Error::Sys(Errno::ENOSYS)); } // Just make sure ptrace_setoptions can be called at all, for now. #[test] #[cfg(any(target_os = "android", target_os = "linux"))] fn test_ptrace_setoptions() { - require_capability!("test_ptrace_setoptions", CAP_SYS_PTRACE); + require_capability!(CAP_SYS_PTRACE); let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD).unwrap_err(); - assert!(err != Errno::EOPNOTSUPP); + assert!(err != Error::UnsupportedOperation); } // Just make sure ptrace_getevent can be called at all, for now. #[test] #[cfg(any(target_os = "android", target_os = "linux"))] fn test_ptrace_getevent() { - require_capability!("test_ptrace_getevent", CAP_SYS_PTRACE); + require_capability!(CAP_SYS_PTRACE); let err = ptrace::getevent(getpid()).unwrap_err(); - assert!(err != Errno::EOPNOTSUPP); + assert!(err != Error::UnsupportedOperation); } // Just make sure ptrace_getsiginfo can be called at all, for now. #[test] #[cfg(any(target_os = "android", target_os = "linux"))] fn test_ptrace_getsiginfo() { - require_capability!("test_ptrace_getsiginfo", CAP_SYS_PTRACE); - if let Err(Errno::EOPNOTSUPP) = ptrace::getsiginfo(getpid()) { - panic!("ptrace_getsiginfo returns Errno::EOPNOTSUPP!"); + require_capability!(CAP_SYS_PTRACE); + if let Err(Error::UnsupportedOperation) = ptrace::getsiginfo(getpid()) { + panic!("ptrace_getsiginfo returns Error::UnsupportedOperation!"); } } @@ -51,10 +52,10 @@ fn test_ptrace_getsiginfo() { #[test] #[cfg(any(target_os = "android", target_os = "linux"))] fn test_ptrace_setsiginfo() { - require_capability!("test_ptrace_setsiginfo", CAP_SYS_PTRACE); + require_capability!(CAP_SYS_PTRACE); let siginfo = unsafe { mem::zeroed() }; - if let Err(Errno::EOPNOTSUPP) = ptrace::setsiginfo(getpid(), &siginfo) { - panic!("ptrace_setsiginfo returns Errno::EOPNOTSUPP!"); + if let Err(Error::UnsupportedOperation) = ptrace::setsiginfo(getpid(), &siginfo) { + panic!("ptrace_setsiginfo returns Error::UnsupportedOperation!"); } } @@ -67,9 +68,9 @@ fn test_ptrace_cont() { use nix::unistd::fork; use nix::unistd::ForkResult::*; - require_capability!("test_ptrace_cont", CAP_SYS_PTRACE); + require_capability!(CAP_SYS_PTRACE); - let _m = crate::FORK_MTX.lock(); + let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); // FIXME: qemu-user doesn't implement ptrace on all architectures // and retunrs ENOSYS in this case. @@ -78,7 +79,7 @@ fn test_ptrace_cont() { // On valid platforms the ptrace call should return Errno::EPERM, this // is already tested by `test_ptrace`. let err = ptrace::attach(getpid()).unwrap_err(); - if err == Errno::ENOSYS { + if err == Error::Sys(Errno::ENOSYS) { return; } @@ -114,48 +115,6 @@ fn test_ptrace_cont() { } } -#[cfg(target_os = "linux")] -#[test] -fn test_ptrace_interrupt() { - use nix::sys::ptrace; - use nix::sys::signal::Signal; - use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus}; - use nix::unistd::fork; - use nix::unistd::ForkResult::*; - use std::thread::sleep; - use std::time::Duration; - - require_capability!("test_ptrace_interrupt", CAP_SYS_PTRACE); - - let _m = crate::FORK_MTX.lock(); - - match unsafe{fork()}.expect("Error: Fork Failed") { - Child => { - loop { - sleep(Duration::from_millis(1000)); - } - - }, - Parent { child } => { - ptrace::seize(child, ptrace::Options::PTRACE_O_TRACESYSGOOD).unwrap(); - ptrace::interrupt(child).unwrap(); - assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceEvent(child, Signal::SIGTRAP, 128))); - ptrace::syscall(child, None).unwrap(); - assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child))); - ptrace::detach(child, Some(Signal::SIGKILL)).unwrap(); - match waitpid(child, None) { - Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) if pid == child => { - let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); - while ptrace::cont(child, Some(Signal::SIGKILL)).is_ok() { - let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); - } - } - _ => panic!("The process should have been killed"), - } - }, - } -} - // ptrace::{setoptions, getregs} are only available in these platforms #[cfg(all(target_os = "linux", any(target_arch = "x86_64", @@ -171,9 +130,9 @@ fn test_ptrace_syscall() { use nix::unistd::getpid; use nix::unistd::ForkResult::*; - require_capability!("test_ptrace_syscall", CAP_SYS_PTRACE); + require_capability!(CAP_SYS_PTRACE); - let _m = crate::FORK_MTX.lock(); + let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); match unsafe{fork()}.expect("Error: Fork Failed") { Child => { diff --git a/test/sys/test_select.rs b/test/sys/test_select.rs index 2f7396b..3795108 100644 --- a/test/sys/test_select.rs +++ b/test/sys/test_select.rs @@ -5,7 +5,9 @@ use nix::sys::time::{TimeSpec, TimeValLike}; #[test] pub fn test_pselect() { - let _mtx = crate::SIGNAL_MTX.lock(); + let _mtx = crate::SIGNAL_MTX + .lock() + .expect("Mutex got poisoned by another test"); let (r1, w1) = pipe().unwrap(); write(w1, b"hi!").unwrap(); @@ -50,31 +52,3 @@ pub fn test_pselect_nfds2() { assert!(fd_set.contains(r1)); assert!(!fd_set.contains(r2)); } - -macro_rules! generate_fdset_bad_fd_tests { - ($fd:expr, $($method:ident),* $(,)?) => { - $( - #[test] - #[should_panic] - fn $method() { - FdSet::new().$method($fd); - } - )* - } -} - -mod test_fdset_negative_fd { - use super::*; - generate_fdset_bad_fd_tests!(-1, insert, remove, contains); -} - -mod test_fdset_too_large_fd { - use super::*; - use std::convert::TryInto; - generate_fdset_bad_fd_tests!( - FD_SETSIZE.try_into().unwrap(), - insert, - remove, - contains, - ); -} diff --git a/test/sys/test_signal.rs b/test/sys/test_signal.rs index fdd2568..ae22527 100644 --- a/test/sys/test_signal.rs +++ b/test/sys/test_signal.rs @@ -1,5 +1,6 @@ +use libc; #[cfg(not(target_os = "redox"))] -use nix::errno::Errno; +use nix::Error; use nix::sys::signal::*; use nix::unistd::*; use std::convert::TryFrom; @@ -19,7 +20,7 @@ fn test_killpg_none() { #[test] fn test_old_sigaction_flags() { - let _m = crate::SIGNAL_MTX.lock(); + let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); extern "C" fn handler(_: ::libc::c_int) {} let act = SigAction::new( @@ -41,7 +42,7 @@ fn test_sigprocmask_noop() { #[test] fn test_sigprocmask() { - let _m = crate::SIGNAL_MTX.lock(); + let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); // This needs to be a signal that rust doesn't use in the test harness. const SIGNAL: Signal = Signal::SIGCHLD; @@ -52,9 +53,9 @@ fn test_sigprocmask() { // Make sure the old set doesn't contain the signal, otherwise the following // test don't make sense. - assert!(!old_signal_set.contains(SIGNAL), - "the {:?} signal is already blocked, please change to a \ - different one", SIGNAL); + assert_eq!(old_signal_set.contains(SIGNAL), false, + "the {:?} signal is already blocked, please change to a \ + different one", SIGNAL); // Now block the signal. let mut signal_set = SigSet::empty(); @@ -66,8 +67,8 @@ fn test_sigprocmask() { old_signal_set.clear(); sigprocmask(SigmaskHow::SIG_BLOCK, None, Some(&mut old_signal_set)) .expect("expect to be able to retrieve old signals"); - assert!(old_signal_set.contains(SIGNAL), - "expected the {:?} to be blocked", SIGNAL); + assert_eq!(old_signal_set.contains(SIGNAL), true, + "expected the {:?} to be blocked", SIGNAL); // Reset the signal. sigprocmask(SigmaskHow::SIG_UNBLOCK, Some(&signal_set), None) @@ -89,15 +90,15 @@ extern fn test_sigaction_action(_: libc::c_int, _: *mut libc::siginfo_t, _: *mut #[test] #[cfg(not(target_os = "redox"))] fn test_signal_sigaction() { - let _m = crate::SIGNAL_MTX.lock(); + let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); let action_handler = SigHandler::SigAction(test_sigaction_action); - assert_eq!(unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(), Errno::ENOTSUP); + assert_eq!(unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(), Error::UnsupportedOperation); } #[test] fn test_signal() { - let _m = crate::SIGNAL_MTX.lock(); + let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); unsafe { signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap(); raise(Signal::SIGINT).unwrap(); @@ -107,15 +108,8 @@ fn test_signal() { assert_eq!(unsafe { signal(Signal::SIGINT, handler) }.unwrap(), SigHandler::SigDfl); raise(Signal::SIGINT).unwrap(); assert!(SIGNALED.load(Ordering::Relaxed)); - - #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] assert_eq!(unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), handler); - // System V based OSes (e.g. illumos and Solaris) always resets the - // disposition to SIG_DFL prior to calling the signal handler - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - assert_eq!(unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), SigHandler::SigDfl); - // Restore default signal handler unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(); } diff --git a/test/sys/test_signalfd.rs b/test/sys/test_signalfd.rs index b6f748b..af04c22 100644 --- a/test/sys/test_signalfd.rs +++ b/test/sys/test_signalfd.rs @@ -6,7 +6,7 @@ fn test_signalfd() { use nix::sys::signal::{self, raise, Signal, SigSet}; // Grab the mutex for altering signals so we don't interfere with other tests. - let _m = crate::SIGNAL_MTX.lock(); + let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); // Block the SIGUSR1 signal from automatic processing for this thread let mut mask = SigSet::empty(); diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 0f6fac6..7eab28c 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -1,13 +1,13 @@ -use nix::sys::socket::{AddressFamily, InetAddr, SockAddr, UnixAddr, getsockname, sockaddr, sockaddr_in6, sockaddr_storage_to_addr}; +use nix::sys::socket::{AddressFamily, InetAddr, UnixAddr, getsockname}; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; -use std::mem::{self, MaybeUninit}; use std::net::{self, Ipv6Addr, SocketAddr, SocketAddrV6}; use std::os::unix::io::RawFd; use std::path::Path; use std::slice; use std::str::FromStr; -use libc::{c_char, sockaddr_storage}; +use libc::c_char; +use tempfile; #[cfg(any(target_os = "linux", target_os= "android"))] use crate::*; @@ -28,36 +28,13 @@ pub fn test_inetv4_addr_to_sock_addr() { _ => panic!("nope"), } - assert_eq!(addr.to_string(), "127.0.0.1:3000"); + assert_eq!(addr.to_str(), "127.0.0.1:3000"); let inet = addr.to_std(); assert_eq!(actual, inet); } #[test] -pub fn test_inetv4_addr_roundtrip_sockaddr_storage_to_addr() { - let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap(); - let addr = InetAddr::from_std(&actual); - let sockaddr = SockAddr::new_inet(addr); - - let (storage, ffi_size) = { - let mut storage = MaybeUninit::<sockaddr_storage>::zeroed(); - let storage_ptr = storage.as_mut_ptr().cast::<sockaddr>(); - let (ffi_ptr, ffi_size) = sockaddr.as_ffi_pair(); - assert_eq!(mem::size_of::<sockaddr>(), ffi_size as usize); - unsafe { - storage_ptr.copy_from_nonoverlapping(ffi_ptr as *const sockaddr, 1); - (storage.assume_init(), ffi_size) - } - }; - - let from_storage = sockaddr_storage_to_addr(&storage, ffi_size as usize).unwrap(); - assert_eq!(from_storage, sockaddr); - let from_storage = sockaddr_storage_to_addr(&storage, mem::size_of::<sockaddr_storage>()).unwrap(); - assert_eq!(from_storage, sockaddr); -} - -#[test] pub fn test_inetv6_addr_to_sock_addr() { let port: u16 = 3000; let flowinfo: u32 = 1; @@ -78,33 +55,6 @@ pub fn test_inetv6_addr_to_sock_addr() { assert_eq!(actual, addr.to_std()); } -#[test] -pub fn test_inetv6_addr_roundtrip_sockaddr_storage_to_addr() { - let port: u16 = 3000; - let flowinfo: u32 = 1; - let scope_id: u32 = 2; - let ip: Ipv6Addr = "fe80::1".parse().unwrap(); - - let actual = SocketAddr::V6(SocketAddrV6::new(ip, port, flowinfo, scope_id)); - let addr = InetAddr::from_std(&actual); - let sockaddr = SockAddr::new_inet(addr); - - let (storage, ffi_size) = { - let mut storage = MaybeUninit::<sockaddr_storage>::zeroed(); - let storage_ptr = storage.as_mut_ptr().cast::<sockaddr_in6>(); - let (ffi_ptr, ffi_size) = sockaddr.as_ffi_pair(); - assert_eq!(mem::size_of::<sockaddr_in6>(), ffi_size as usize); - unsafe { - storage_ptr.copy_from_nonoverlapping((ffi_ptr as *const sockaddr).cast::<sockaddr_in6>(), 1); - (storage.assume_init(), ffi_size) - } - }; - - let from_storage = sockaddr_storage_to_addr(&storage, ffi_size as usize).unwrap(); - assert_eq!(from_storage, sockaddr); - let from_storage = sockaddr_storage_to_addr(&storage, mem::size_of::<sockaddr_storage>()).unwrap(); - assert_eq!(from_storage, sockaddr); -} #[test] pub fn test_path_to_sock_addr() { @@ -113,9 +63,9 @@ pub fn test_path_to_sock_addr() { let addr = UnixAddr::new(actual).unwrap(); let expect: &[c_char] = unsafe { - slice::from_raw_parts(path.as_ptr() as *const c_char, path.len()) + slice::from_raw_parts(path.as_bytes().as_ptr() as *const c_char, path.len()) }; - assert_eq!(unsafe { &(*addr.as_ptr()).sun_path[..8] }, expect); + assert_eq!(&addr.0.sun_path[..8], expect); assert_eq!(addr.path(), Some(actual)); } @@ -131,9 +81,9 @@ pub fn test_addr_equality_path() { let path = "/foo/bar"; let actual = Path::new(path); let addr1 = UnixAddr::new(actual).unwrap(); - let mut addr2 = addr1; + let mut addr2 = addr1.clone(); - unsafe { (*addr2.as_mut_ptr()).sun_path[10] = 127 }; + addr2.0.sun_path[10] = 127; assert_eq!(addr1, addr2); assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2)); @@ -152,12 +102,12 @@ pub fn test_abstract_sun_path_too_long() { pub fn test_addr_equality_abstract() { let name = String::from("nix\0abstract\0test"); let addr1 = UnixAddr::new_abstract(name.as_bytes()).unwrap(); - let mut addr2 = addr1; + let mut addr2 = addr1.clone(); assert_eq!(addr1, addr2); assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2)); - unsafe { (*addr2.as_mut_ptr()).sun_path[17] = 127 }; + addr2.0.sun_path[17] = 127; assert_ne!(addr1, addr2); assert_ne!(calculate_hash(&addr1), calculate_hash(&addr2)); } @@ -180,7 +130,7 @@ pub fn test_abstract_uds_addr() { assert_eq!(addr.path(), None); // Internally, name is null-prefixed (abstract namespace) - assert_eq!(unsafe { (*addr.as_ptr()).sun_path[0] }, 0); + assert_eq!(addr.0.sun_path[0], 0); } #[test] @@ -194,7 +144,8 @@ pub fn test_getsockname() { .expect("socket failed"); let sockaddr = SockAddr::new_unix(&sockname).unwrap(); bind(sock, &sockaddr).expect("bind failed"); - assert_eq!(sockaddr, getsockname(sock).expect("getsockname failed")); + assert_eq!(sockaddr.to_str(), + getsockname(sock).expect("getsockname failed").to_str()); } #[test] @@ -217,7 +168,7 @@ mod recvfrom { use std::thread; use super::*; - const MSG: &[u8] = b"Hello, World!"; + const MSG: &'static [u8] = b"Hello, World!"; fn sendrecv<Fs, Fr>(rsock: RawFd, ssock: RawFd, f_send: Fs, mut f_recv: Fr) -> Option<SockAddr> where @@ -287,9 +238,9 @@ mod recvfrom { use nix::sys::socket::sockopt::{UdpGroSegment, UdpGsoSegment}; #[test] - // Disable the test under emulation because it fails in Cirrus-CI. Lack - // of QEMU support is suspected. - #[cfg_attr(qemu, ignore)] + // 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"); @@ -341,9 +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(qemu, ignore)] + // 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"); @@ -393,14 +344,14 @@ mod recvfrom { let from = sendrecv(rsock, ssock, move |s, m, flags| { let iov = [IoVec::from_slice(m)]; - let mut msgs = vec![ + let mut msgs = Vec::new(); + msgs.push( SendMmsgData { iov: &iov, cmsgs: &[], addr: Some(sock_addr), _lt: Default::default(), - } - ]; + }); let batch_size = 15; @@ -416,7 +367,7 @@ mod recvfrom { } sendmmsg(s, msgs.iter(), flags) .map(move |sent_bytes| { - assert!(!sent_bytes.is_empty()); + assert!(sent_bytes.len() >= 1); for sent in &sent_bytes { assert_eq!(*sent, m.len()); } @@ -474,7 +425,7 @@ mod recvfrom { for iov in &iovs { msgs.push_back(RecvMmsgData { - iov, + iov: iov, cmsg_buffer: None, }) }; @@ -546,7 +497,7 @@ mod recvfrom { for iov in &iovs { msgs.push_back(RecvMmsgData { - iov, + iov: iov, cmsg_buffer: None, }) }; @@ -568,6 +519,7 @@ mod recvfrom { // Test error handling of our recvmsg wrapper #[test] pub fn test_recvmsg_ebadf() { + use nix::Error; use nix::errno::Errno; use nix::sys::socket::{MsgFlags, recvmsg}; use nix::sys::uio::IoVec; @@ -576,12 +528,12 @@ pub fn test_recvmsg_ebadf() { let iov = [IoVec::from_mut_slice(&mut buf[..])]; let fd = -1; // Bad file descriptor let r = recvmsg(fd, &iov, None, MsgFlags::empty()); - assert_eq!(r.err().unwrap(), Errno::EBADF); + assert_eq!(r.err().unwrap(), Error::Sys(Errno::EBADF)); } // Disable the test on emulated platforms due to a bug in QEMU versions < // 2.12.0. https://bugs.launchpad.net/qemu/+bug/1701808 -#[cfg_attr(qemu, ignore)] +#[cfg_attr(not(any(target_arch = "x86_64", target_arch="i686")), ignore)] #[test] pub fn test_scm_rights() { use nix::sys::uio::IoVec; @@ -635,10 +587,11 @@ pub fn test_scm_rights() { } // Disable the test on emulated platforms due to not enabled support of AF_ALG in QEMU from rust cross +#[cfg_attr(not(any(target_arch = "x86_64", target_arch = "i686")), ignore)] #[cfg(any(target_os = "linux", target_os= "android"))] -#[cfg_attr(qemu, ignore)] #[test] pub fn test_af_alg_cipher() { + use libc; use nix::sys::uio::IoVec; use nix::unistd::read; use nix::sys::socket::{socket, sendmsg, bind, accept, setsockopt, @@ -702,14 +655,12 @@ pub fn test_af_alg_cipher() { assert_eq!(decrypted, payload); } -// Disable the test on emulated platforms due to not enabled support of AF_ALG -// in QEMU from rust cross +// Disable the test on emulated platforms due to not enabled support of AF_ALG in QEMU from rust cross +#[cfg_attr(not(any(target_arch = "x86_64", target_arch = "i686")), ignore)] #[cfg(any(target_os = "linux", target_os= "android"))] -#[cfg_attr(qemu, ignore)] #[test] pub fn test_af_alg_aead() { use libc::{ALG_OP_DECRYPT, ALG_OP_ENCRYPT}; - use nix::fcntl::{fcntl, FcntlArg, OFlag}; use nix::sys::uio::IoVec; use nix::unistd::{read, close}; use nix::sys::socket::{socket, sendmsg, bind, accept, setsockopt, @@ -788,11 +739,6 @@ pub fn test_af_alg_aead() { // allocate buffer for decrypted data let mut decrypted = vec![0u8; payload_len + (assoc_size as usize) + auth_size]; - // Starting with kernel 4.9, the interface changed slightly such that the - // authentication tag memory is only needed in the output buffer for encryption - // and in the input buffer for decryption. - // Do not block on read, as we may have fewer bytes than buffer size - fcntl(session_socket,FcntlArg::F_SETFL(OFlag::O_NONBLOCK)).expect("fcntl non_blocking"); let num_bytes = read(session_socket, &mut decrypted).expect("read decrypt"); assert!(num_bytes >= payload_len + (assoc_size as usize)); @@ -811,7 +757,6 @@ pub fn test_af_alg_aead() { target_os = "netbsd"))] #[test] pub fn test_sendmsg_ipv4packetinfo() { - use cfg_if::cfg_if; use nix::sys::uio::IoVec; use nix::sys::socket::{socket, sendmsg, bind, AddressFamily, SockType, SockFlag, SockAddr, @@ -833,21 +778,11 @@ pub fn test_sendmsg_ipv4packetinfo() { let iov = [IoVec::from_slice(&slice)]; if let InetAddr::V4(sin) = inet_addr { - cfg_if! { - if #[cfg(target_os = "netbsd")] { - let _dontcare = sin; - let pi = libc::in_pktinfo { - ipi_ifindex: 0, /* Unspecified interface */ - ipi_addr: libc::in_addr { s_addr: 0 }, - }; - } else { - let pi = libc::in_pktinfo { - ipi_ifindex: 0, /* Unspecified interface */ - ipi_addr: libc::in_addr { s_addr: 0 }, - ipi_spec_dst: sin.sin_addr, - }; - } - } + let pi = libc::in_pktinfo { + ipi_ifindex: 0, /* Unspecified interface */ + ipi_addr: libc::in_addr { s_addr: 0 }, + ipi_spec_dst: sin.sin_addr, + }; let cmsg = [ControlMessage::Ipv4PacketInfo(&pi)]; @@ -872,6 +807,7 @@ pub fn test_sendmsg_ipv4packetinfo() { target_os = "freebsd"))] #[test] pub fn test_sendmsg_ipv6packetinfo() { + use nix::Error; use nix::errno::Errno; use nix::sys::uio::IoVec; use nix::sys::socket::{socket, sendmsg, bind, @@ -888,9 +824,12 @@ pub fn test_sendmsg_ipv6packetinfo() { let inet_addr = InetAddr::from_std(&std_sa); let sock_addr = SockAddr::new_inet(inet_addr); - if let Err(Errno::EADDRNOTAVAIL) = bind(sock, &sock_addr) { - println!("IPv6 not available, skipping test."); - return; + match bind(sock, &sock_addr) { + Err(Error::Sys(Errno::EADDRNOTAVAIL)) => { + println!("IPv6 not available, skipping test."); + return; + }, + _ => (), } let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; @@ -914,7 +853,7 @@ pub fn test_sendmsg_ipv6packetinfo() { /// Tests that passing multiple fds using a single `ControlMessage` works. // Disable the test on emulated platforms due to a bug in QEMU versions < // 2.12.0. https://bugs.launchpad.net/qemu/+bug/1701808 -#[cfg_attr(qemu, ignore)] +#[cfg_attr(not(any(target_arch = "x86_64", target_arch="i686")), ignore)] #[test] fn test_scm_rights_single_cmsg_multiple_fds() { use std::os::unix::net::UnixDatagram; @@ -923,6 +862,7 @@ fn test_scm_rights_single_cmsg_multiple_fds() { use nix::sys::socket::{ControlMessage, ControlMessageOwned, MsgFlags, sendmsg, recvmsg}; use nix::sys::uio::IoVec; + use libc; let (send, receive) = UnixDatagram::pair().unwrap(); let thread = thread::spawn(move || { @@ -1060,11 +1000,13 @@ fn test_scm_credentials() { /// Ensure that we can send `SCM_CREDENTIALS` and `SCM_RIGHTS` with a single /// `sendmsg` call. #[cfg(any(target_os = "android", target_os = "linux"))] -// qemu's handling of multiple cmsgs is bugged, ignore tests under emulation +// qemu's handling of multiple cmsgs is bugged, ignore tests on non-x86 // see https://bugs.launchpad.net/qemu/+bug/1781280 -#[cfg_attr(qemu, ignore)] +#[cfg_attr(not(any(target_arch = "x86_64", target_arch = "x86")), ignore)] #[test] fn test_scm_credentials_and_rights() { + use libc; + let space = cmsg_space!(libc::ucred, RawFd); test_impl_scm_credentials_and_rights(space); } @@ -1072,9 +1014,9 @@ fn test_scm_credentials_and_rights() { /// Ensure that passing a an oversized control message buffer to recvmsg /// still works. #[cfg(any(target_os = "android", target_os = "linux"))] -// qemu's handling of multiple cmsgs is bugged, ignore tests under emulation +// qemu's handling of multiple cmsgs is bugged, ignore tests on non-x86 // see https://bugs.launchpad.net/qemu/+bug/1781280 -#[cfg_attr(qemu, ignore)] +#[cfg_attr(not(any(target_arch = "x86_64", target_arch = "x86")), ignore)] #[test] fn test_too_large_cmsgspace() { let space = vec![0u8; 1024]; @@ -1195,6 +1137,7 @@ pub fn test_unixdomain() { #[cfg(any(target_os = "macos", target_os = "ios"))] #[test] pub fn test_syscontrol() { + use nix::Error; use nix::errno::Errno; use nix::sys::socket::{socket, SockAddr, SockType, SockFlag, SockProtocol}; @@ -1202,7 +1145,7 @@ pub fn test_syscontrol() { SockFlag::empty(), SockProtocol::KextControl) .expect("socket failed"); let _sockaddr = SockAddr::new_sys_control(fd, "com.apple.net.utun_control", 0).expect("resolving sys_control name failed"); - assert_eq!(SockAddr::new_sys_control(fd, "foo.bar.lol", 0).err(), Some(Errno::ENOENT)); + assert_eq!(SockAddr::new_sys_control(fd, "foo.bar.lol", 0).err(), Some(Error::Sys(Errno::ENOENT))); // requires root privileges // connect(fd, &sockaddr).expect("connect failed"); @@ -1221,6 +1164,7 @@ fn loopback_address(family: AddressFamily) -> Option<nix::ifaddrs::InterfaceAddr use std::io; use std::io::Write; use nix::ifaddrs::getifaddrs; + use nix::sys::socket::SockAddr; use nix::net::if_::*; let addrs = match getifaddrs() { @@ -1263,16 +1207,14 @@ fn loopback_address(family: AddressFamily) -> Option<nix::ifaddrs::InterfaceAddr target_os = "netbsd", ))] // qemu doesn't seem to be emulating this correctly in these architectures -#[cfg_attr(all( - qemu, - any( - target_arch = "mips", - target_arch = "mips64", - target_arch = "powerpc64", - ) +#[cfg_attr(any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc64", ), ignore)] #[test] pub fn test_recv_ipv4pktinfo() { + use libc; use nix::sys::socket::sockopt::Ipv4PacketInfo; use nix::sys::socket::{bind, SockFlag, SockType}; use nix::sys::socket::{getsockname, setsockopt, socket}; @@ -1325,15 +1267,18 @@ pub fn test_recv_ipv4pktinfo() { ); let mut cmsgs = msg.cmsgs(); - if let Some(ControlMessageOwned::Ipv4PacketInfo(pktinfo)) = cmsgs.next() { - let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex"); - assert_eq!( - pktinfo.ipi_ifindex as libc::c_uint, - i, - "unexpected ifindex (expected {}, got {})", - i, - pktinfo.ipi_ifindex - ); + match cmsgs.next() { + Some(ControlMessageOwned::Ipv4PacketInfo(pktinfo)) => { + let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex"); + assert_eq!( + pktinfo.ipi_ifindex as libc::c_uint, + i, + "unexpected ifindex (expected {}, got {})", + i, + pktinfo.ipi_ifindex + ); + } + _ => (), } assert!(cmsgs.next().is_none(), "unexpected additional control msg"); assert_eq!(msg.bytes, 8); @@ -1352,16 +1297,14 @@ pub fn test_recv_ipv4pktinfo() { target_os = "openbsd", ))] // qemu doesn't seem to be emulating this correctly in these architectures -#[cfg_attr(all( - qemu, - any( - target_arch = "mips", - target_arch = "mips64", - target_arch = "powerpc64", - ) +#[cfg_attr(any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc64", ), ignore)] #[test] pub fn test_recvif() { + use libc; use nix::net::if_::*; use nix::sys::socket::sockopt::{Ipv4RecvIf, Ipv4RecvDstAddr}; use nix::sys::socket::{bind, SockFlag, SockType}; @@ -1445,8 +1388,8 @@ pub fn test_recvif() { _ => panic!("unexpected additional control msg"), } } - assert!(rx_recvif); - assert!(rx_recvdstaddr); + assert_eq!(rx_recvif, true); + assert_eq!(rx_recvdstaddr, true); assert_eq!(msg.bytes, 8); assert_eq!( iovec[0].as_slice(), @@ -1465,16 +1408,14 @@ pub fn test_recvif() { target_os = "openbsd", ))] // qemu doesn't seem to be emulating this correctly in these architectures -#[cfg_attr(all( - qemu, - any( - target_arch = "mips", - target_arch = "mips64", - target_arch = "powerpc64", - ) +#[cfg_attr(any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc64", ), ignore)] #[test] pub fn test_recv_ipv6pktinfo() { + use libc; use nix::net::if_::*; use nix::sys::socket::sockopt::Ipv6RecvPacketInfo; use nix::sys::socket::{bind, SockFlag, SockType}; @@ -1527,16 +1468,18 @@ pub fn test_recv_ipv6pktinfo() { ); let mut cmsgs = msg.cmsgs(); - if let Some(ControlMessageOwned::Ipv6PacketInfo(pktinfo)) = cmsgs.next() - { - let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex"); - assert_eq!( - pktinfo.ipi6_ifindex as libc::c_uint, - i, - "unexpected ifindex (expected {}, got {})", - i, - pktinfo.ipi6_ifindex - ); + match cmsgs.next() { + Some(ControlMessageOwned::Ipv6PacketInfo(pktinfo)) => { + let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex"); + assert_eq!( + pktinfo.ipi6_ifindex, + i, + "unexpected ifindex (expected {}, got {})", + i, + pktinfo.ipi6_ifindex + ); + } + _ => (), } assert!(cmsgs.next().is_none(), "unexpected additional control msg"); assert_eq!(msg.bytes, 8); @@ -1548,9 +1491,10 @@ pub fn test_recv_ipv6pktinfo() { } #[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(graviton, ignore = "Not supported by the CI environment")] #[test] pub fn test_vsock() { + use libc; + use nix::Error; use nix::errno::Errno; use nix::sys::socket::{AddressFamily, socket, bind, connect, listen, SockAddr, SockType, SockFlag}; @@ -1563,10 +1507,16 @@ pub fn test_vsock() { SockFlag::empty(), None) .expect("socket failed"); - // VMADDR_CID_HYPERVISOR is reserved, so we expect an EADDRNOTAVAIL error. + // VMADDR_CID_HYPERVISOR and VMADDR_CID_LOCAL are reserved, so we expect + // an EADDRNOTAVAIL error. let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_HYPERVISOR, port); assert_eq!(bind(s1, &sockaddr).err(), - Some(Errno::EADDRNOTAVAIL)); + Some(Error::Sys(Errno::EADDRNOTAVAIL))); + + let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_LOCAL, port); + assert_eq!(bind(s1, &sockaddr).err(), + Some(Error::Sys(Errno::EADDRNOTAVAIL))); + let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_ANY, port); assert_eq!(bind(s1, &sockaddr), Ok(())); @@ -1591,351 +1541,3 @@ pub fn test_vsock() { close(s1).unwrap(); thr.join().unwrap(); } - -// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack -// of QEMU support is suspected. -#[cfg_attr(qemu, ignore)] -#[cfg(all(target_os = "linux"))] -#[test] -fn test_recvmsg_timestampns() { - use nix::sys::socket::*; - use nix::sys::uio::IoVec; - use nix::sys::time::*; - use std::time::*; - - // Set up - let message = "Ohayō!".as_bytes(); - let in_socket = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None).unwrap(); - setsockopt(in_socket, sockopt::ReceiveTimestampns, &true).unwrap(); - let localhost = InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0); - bind(in_socket, &SockAddr::new_inet(localhost)).unwrap(); - let address = getsockname(in_socket).unwrap(); - // Get initial time - let time0 = SystemTime::now(); - // Send the message - let iov = [IoVec::from_slice(message)]; - let flags = MsgFlags::empty(); - let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap(); - assert_eq!(message.len(), l); - // Receive the message - let mut buffer = vec![0u8; message.len()]; - let mut cmsgspace = nix::cmsg_space!(TimeSpec); - let iov = [IoVec::from_mut_slice(&mut buffer)]; - let r = recvmsg(in_socket, &iov, Some(&mut cmsgspace), flags).unwrap(); - let rtime = match r.cmsgs().next() { - Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime, - Some(_) => panic!("Unexpected control message"), - None => panic!("No control message") - }; - // Check the final time - let time1 = SystemTime::now(); - // the packet's received timestamp should lie in-between the two system - // times, unless the system clock was adjusted in the meantime. - let rduration = Duration::new(rtime.tv_sec() as u64, - rtime.tv_nsec() as u32); - assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration); - assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap()); - // Close socket - nix::unistd::close(in_socket).unwrap(); -} - -// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack -// of QEMU support is suspected. -#[cfg_attr(qemu, ignore)] -#[cfg(all(target_os = "linux"))] -#[test] -fn test_recvmmsg_timestampns() { - use nix::sys::socket::*; - use nix::sys::uio::IoVec; - use nix::sys::time::*; - use std::time::*; - - // Set up - let message = "Ohayō!".as_bytes(); - let in_socket = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None).unwrap(); - setsockopt(in_socket, sockopt::ReceiveTimestampns, &true).unwrap(); - let localhost = InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0); - bind(in_socket, &SockAddr::new_inet(localhost)).unwrap(); - let address = getsockname(in_socket).unwrap(); - // Get initial time - let time0 = SystemTime::now(); - // Send the message - let iov = [IoVec::from_slice(message)]; - let flags = MsgFlags::empty(); - let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap(); - assert_eq!(message.len(), l); - // Receive the message - let mut buffer = vec![0u8; message.len()]; - let mut cmsgspace = nix::cmsg_space!(TimeSpec); - let iov = [IoVec::from_mut_slice(&mut buffer)]; - let mut data = vec![ - RecvMmsgData { - iov, - cmsg_buffer: Some(&mut cmsgspace), - }, - ]; - let r = recvmmsg(in_socket, &mut data, flags, None).unwrap(); - let rtime = match r[0].cmsgs().next() { - Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime, - Some(_) => panic!("Unexpected control message"), - None => panic!("No control message") - }; - // Check the final time - let time1 = SystemTime::now(); - // the packet's received timestamp should lie in-between the two system - // times, unless the system clock was adjusted in the meantime. - let rduration = Duration::new(rtime.tv_sec() as u64, - rtime.tv_nsec() as u32); - assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration); - assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap()); - // Close socket - nix::unistd::close(in_socket).unwrap(); -} - -// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack -// of QEMU support is suspected. -#[cfg_attr(qemu, ignore)] -#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] -#[test] -fn test_recvmsg_rxq_ovfl() { - use nix::Error; - use nix::sys::socket::*; - use nix::sys::uio::IoVec; - use nix::sys::socket::sockopt::{RxqOvfl, RcvBuf}; - - let message = [0u8; 2048]; - let bufsize = message.len() * 2; - - let in_socket = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None).unwrap(); - let out_socket = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None).unwrap(); - - let localhost = InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0); - bind(in_socket, &SockAddr::new_inet(localhost)).unwrap(); - - let address = getsockname(in_socket).unwrap(); - connect(out_socket, &address).unwrap(); - - // Set SO_RXQ_OVFL flag. - setsockopt(in_socket, RxqOvfl, &1).unwrap(); - - // Set the receiver buffer size to hold only 2 messages. - setsockopt(in_socket, RcvBuf, &bufsize).unwrap(); - - let mut drop_counter = 0; - - for _ in 0..2 { - let iov = [IoVec::from_slice(&message)]; - let flags = MsgFlags::empty(); - - // Send the 3 messages (the receiver buffer can only hold 2 messages) - // to create an overflow. - for _ in 0..3 { - let l = sendmsg(out_socket, &iov, &[], flags, Some(&address)).unwrap(); - assert_eq!(message.len(), l); - } - - // Receive the message and check the drop counter if any. - loop { - let mut buffer = vec![0u8; message.len()]; - let mut cmsgspace = nix::cmsg_space!(u32); - - let iov = [IoVec::from_mut_slice(&mut buffer)]; - - match recvmsg( - in_socket, - &iov, - Some(&mut cmsgspace), - MsgFlags::MSG_DONTWAIT) { - Ok(r) => { - drop_counter = match r.cmsgs().next() { - Some(ControlMessageOwned::RxqOvfl(drop_counter)) => drop_counter, - Some(_) => panic!("Unexpected control message"), - None => 0, - }; - }, - Err(Error::EAGAIN) => { break; }, - _ => { panic!("unknown recvmsg() error"); }, - } - } - } - - // One packet lost. - assert_eq!(drop_counter, 1); - - // Close sockets - nix::unistd::close(in_socket).unwrap(); - nix::unistd::close(out_socket).unwrap(); -} - -#[cfg(any( - target_os = "linux", - target_os = "android", -))] -mod linux_errqueue { - use nix::sys::socket::*; - use super::{FromStr, SocketAddr}; - - // Send a UDP datagram to a bogus destination address and observe an ICMP error (v4). - // - // Disable the test on QEMU because QEMU emulation of IP_RECVERR is broken (as documented on PR - // #1514). - #[cfg_attr(qemu, ignore)] - #[test] - fn test_recverr_v4() { - #[repr(u8)] - enum IcmpTypes { - DestUnreach = 3, // ICMP_DEST_UNREACH - } - #[repr(u8)] - enum IcmpUnreachCodes { - PortUnreach = 3, // ICMP_PORT_UNREACH - } - - test_recverr_impl::<sockaddr_in, _, _>( - "127.0.0.1:6800", - AddressFamily::Inet, - sockopt::Ipv4RecvErr, - libc::SO_EE_ORIGIN_ICMP, - IcmpTypes::DestUnreach as u8, - IcmpUnreachCodes::PortUnreach as u8, - // Closure handles protocol-specific testing and returns generic sock_extended_err for - // protocol-independent test impl. - |cmsg| { - if let ControlMessageOwned::Ipv4RecvErr(ext_err, err_addr) = cmsg { - if let Some(origin) = err_addr { - // Validate that our network error originated from 127.0.0.1:0. - assert_eq!(origin.sin_family, AddressFamily::Inet as _); - assert_eq!(Ipv4Addr(origin.sin_addr), Ipv4Addr::new(127, 0, 0, 1)); - assert_eq!(origin.sin_port, 0); - } else { - panic!("Expected some error origin"); - } - *ext_err - } else { - panic!("Unexpected control message {:?}", cmsg); - } - }, - ) - } - - // Essentially the same test as v4. - // - // Disable the test on QEMU because QEMU emulation of IPV6_RECVERR is broken (as documented on - // PR #1514). - #[cfg_attr(qemu, ignore)] - #[test] - fn test_recverr_v6() { - #[repr(u8)] - enum IcmpV6Types { - DestUnreach = 1, // ICMPV6_DEST_UNREACH - } - #[repr(u8)] - enum IcmpV6UnreachCodes { - PortUnreach = 4, // ICMPV6_PORT_UNREACH - } - - test_recverr_impl::<sockaddr_in6, _, _>( - "[::1]:6801", - AddressFamily::Inet6, - sockopt::Ipv6RecvErr, - libc::SO_EE_ORIGIN_ICMP6, - IcmpV6Types::DestUnreach as u8, - IcmpV6UnreachCodes::PortUnreach as u8, - // Closure handles protocol-specific testing and returns generic sock_extended_err for - // protocol-independent test impl. - |cmsg| { - if let ControlMessageOwned::Ipv6RecvErr(ext_err, err_addr) = cmsg { - if let Some(origin) = err_addr { - // Validate that our network error originated from localhost:0. - assert_eq!(origin.sin6_family, AddressFamily::Inet6 as _); - assert_eq!( - Ipv6Addr(origin.sin6_addr), - Ipv6Addr::from_std(&"::1".parse().unwrap()), - ); - assert_eq!(origin.sin6_port, 0); - } else { - panic!("Expected some error origin"); - } - *ext_err - } else { - panic!("Unexpected control message {:?}", cmsg); - } - }, - ) - } - - fn test_recverr_impl<SA, OPT, TESTF>(sa: &str, - af: AddressFamily, - opt: OPT, - ee_origin: u8, - ee_type: u8, - ee_code: u8, - testf: TESTF) - where - OPT: SetSockOpt<Val = bool>, - TESTF: FnOnce(&ControlMessageOwned) -> libc::sock_extended_err, - { - use nix::errno::Errno; - use nix::sys::uio::IoVec; - - const MESSAGE_CONTENTS: &str = "ABCDEF"; - - let sock_addr = { - let std_sa = SocketAddr::from_str(sa).unwrap(); - let inet_addr = InetAddr::from_std(&std_sa); - SockAddr::new_inet(inet_addr) - }; - let sock = socket(af, SockType::Datagram, SockFlag::SOCK_CLOEXEC, None).unwrap(); - setsockopt(sock, opt, &true).unwrap(); - if let Err(e) = sendto(sock, MESSAGE_CONTENTS.as_bytes(), &sock_addr, MsgFlags::empty()) { - assert_eq!(e, Errno::EADDRNOTAVAIL); - println!("{:?} not available, skipping test.", af); - return; - } - - let mut buf = [0u8; 8]; - let iovec = [IoVec::from_mut_slice(&mut buf)]; - let mut cspace = cmsg_space!(libc::sock_extended_err, SA); - - let msg = recvmsg(sock, &iovec, Some(&mut cspace), MsgFlags::MSG_ERRQUEUE).unwrap(); - // The sent message / destination associated with the error is returned: - assert_eq!(msg.bytes, MESSAGE_CONTENTS.as_bytes().len()); - assert_eq!(&buf[..msg.bytes], MESSAGE_CONTENTS.as_bytes()); - // recvmsg(2): "The original destination address of the datagram that caused the error is - // supplied via msg_name;" however, this is not literally true. E.g., an earlier version - // of this test used 0.0.0.0 (::0) as the destination address, which was mutated into - // 127.0.0.1 (::1). - assert_eq!(msg.address, Some(sock_addr)); - - // Check for expected control message. - let ext_err = match msg.cmsgs().next() { - Some(cmsg) => testf(&cmsg), - None => panic!("No control message"), - }; - - assert_eq!(ext_err.ee_errno, libc::ECONNREFUSED as u32); - assert_eq!(ext_err.ee_origin, ee_origin); - // ip(7): ee_type and ee_code are set from the type and code fields of the ICMP (ICMPv6) - // header. - assert_eq!(ext_err.ee_type, ee_type); - assert_eq!(ext_err.ee_code, ee_code); - // ip(7): ee_info contains the discovered MTU for EMSGSIZE errors. - assert_eq!(ext_err.ee_info, 0); - } -} diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs index 01920fd..5606593 100644 --- a/test/sys/test_sockopt.rs +++ b/test/sys/test_sockopt.rs @@ -3,53 +3,12 @@ use nix::sys::socket::{socket, sockopt, getsockopt, setsockopt, AddressFamily, S #[cfg(any(target_os = "android", target_os = "linux"))] use crate::*; -// NB: FreeBSD supports LOCAL_PEERCRED for SOCK_SEQPACKET, but OSX does not. -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", -))] -#[test] -pub fn test_local_peercred_seqpacket() { - use nix::{ - unistd::{Gid, Uid}, - sys::socket::socketpair - }; - - let (fd1, _fd2) = socketpair(AddressFamily::Unix, SockType::SeqPacket, None, - SockFlag::empty()).unwrap(); - let xucred = getsockopt(fd1, sockopt::LocalPeerCred).unwrap(); - assert_eq!(xucred.version(), 0); - assert_eq!(Uid::from_raw(xucred.uid()), Uid::current()); - assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current()); -} - -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "ios" -))] -#[test] -pub fn test_local_peercred_stream() { - use nix::{ - unistd::{Gid, Uid}, - sys::socket::socketpair - }; - - let (fd1, _fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, - SockFlag::empty()).unwrap(); - let xucred = getsockopt(fd1, sockopt::LocalPeerCred).unwrap(); - assert_eq!(xucred.version(), 0); - assert_eq!(Uid::from_raw(xucred.uid()), Uid::current()); - assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current()); -} - #[cfg(target_os = "linux")] #[test] fn is_so_mark_functional() { use nix::sys::socket::sockopt; - require_capability!("is_so_mark_functional", CAP_NET_ADMIN); + require_capability!(CAP_NET_ADMIN); let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap(); setsockopt(s, sockopt::Mark, &1337).unwrap(); @@ -61,7 +20,7 @@ fn is_so_mark_functional() { fn test_so_buf() { let fd = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), SockProtocol::Udp) .unwrap(); - let bufsize: usize = thread_rng().gen_range(4096..131_072); + let bufsize: usize = thread_rng().gen_range(4096, 131_072); setsockopt(fd, sockopt::SndBuf, &bufsize).unwrap(); let actual = getsockopt(fd, sockopt::SndBuf).unwrap(); assert!(actual >= bufsize); @@ -70,57 +29,6 @@ fn test_so_buf() { assert!(actual >= bufsize); } -#[test] -fn test_so_tcp_maxseg() { - use std::net::SocketAddr; - use std::str::FromStr; - use nix::sys::socket::{accept, bind, connect, listen, InetAddr, SockAddr}; - use nix::unistd::{close, write}; - - let std_sa = SocketAddr::from_str("127.0.0.1:4001").unwrap(); - let inet_addr = InetAddr::from_std(&std_sa); - let sock_addr = SockAddr::new_inet(inet_addr); - - let rsock = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), SockProtocol::Tcp) - .unwrap(); - bind(rsock, &sock_addr).unwrap(); - listen(rsock, 10).unwrap(); - let initial = getsockopt(rsock, sockopt::TcpMaxSeg).unwrap(); - // Initial MSS is expected to be 536 (https://tools.ietf.org/html/rfc879#section-1) but some - // platforms keep it even lower. This might fail if you've tuned your initial MSS to be larger - // than 700 - cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { - let segsize: u32 = 873; - assert!(initial < segsize); - setsockopt(rsock, sockopt::TcpMaxSeg, &segsize).unwrap(); - } else { - assert!(initial < 700); - } - } - - // Connect and check the MSS that was advertised - let ssock = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), SockProtocol::Tcp) - .unwrap(); - connect(ssock, &sock_addr).unwrap(); - let rsess = accept(rsock).unwrap(); - write(rsess, b"hello").unwrap(); - let actual = getsockopt(ssock, sockopt::TcpMaxSeg).unwrap(); - // Actual max segment size takes header lengths into account, max IPv4 options (60 bytes) + max - // TCP options (40 bytes) are subtracted from the requested maximum as a lower boundary. - cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { - assert!((segsize - 100) <= actual); - assert!(actual <= segsize); - } else { - assert!(initial < actual); - assert!(536 < actual); - } - } - close(rsock).unwrap(); - close(ssock).unwrap(); -} - // The CI doesn't supported getsockopt and setsockopt on emulated processors. // It's beleived that a QEMU issue, the tests run ok on a fully emulated system. // Current CI just run the binary with QEMU but the Kernel remains the same as the host. @@ -166,7 +74,7 @@ fn test_bindtodevice() { fn test_so_tcp_keepalive() { let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), SockProtocol::Tcp).unwrap(); setsockopt(fd, sockopt::KeepAlive, &true).unwrap(); - assert!(getsockopt(fd, sockopt::KeepAlive).unwrap()); + assert_eq!(getsockopt(fd, sockopt::KeepAlive).unwrap(), true); #[cfg(any(target_os = "android", target_os = "dragonfly", @@ -186,14 +94,3 @@ fn test_so_tcp_keepalive() { assert_eq!(getsockopt(fd, sockopt::TcpKeepInterval).unwrap(), x + 1); } } - -#[test] -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] -fn test_ttl_opts() { - let fd4 = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap(); - setsockopt(fd4, sockopt::Ipv4Ttl, &1) - .expect("setting ipv4ttl on an inet socket should succeed"); - let fd6 = socket(AddressFamily::Inet6, SockType::Datagram, SockFlag::empty(), None).unwrap(); - setsockopt(fd6, sockopt::Ipv6Ttl, &1) - .expect("setting ipv6ttl on an inet6 socket should succeed"); -} diff --git a/test/sys/test_termios.rs b/test/sys/test_termios.rs index 4a86154..00aeb2f 100644 --- a/test/sys/test_termios.rs +++ b/test/sys/test_termios.rs @@ -1,7 +1,7 @@ use std::os::unix::prelude::*; use tempfile::tempfile; -use nix::fcntl; +use nix::{Error, fcntl}; use nix::errno::Errno; use nix::pty::openpty; use nix::sys::termios::{self, LocalFlags, OutputFlags, tcgetattr}; @@ -19,7 +19,7 @@ fn write_all(f: RawFd, buf: &[u8]) { #[test] fn test_tcgetattr_pty() { // openpty uses ptname(3) internally - let _m = crate::PTSNAME_MTX.lock(); + let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); let pty = openpty(None, None).expect("openpty failed"); assert!(termios::tcgetattr(pty.slave).is_ok()); @@ -32,21 +32,21 @@ fn test_tcgetattr_pty() { fn test_tcgetattr_enotty() { let file = tempfile().unwrap(); assert_eq!(termios::tcgetattr(file.as_raw_fd()).err(), - Some(Errno::ENOTTY)); + Some(Error::Sys(Errno::ENOTTY))); } // Test tcgetattr on an invalid file descriptor #[test] fn test_tcgetattr_ebadf() { assert_eq!(termios::tcgetattr(-1).err(), - Some(Errno::EBADF)); + Some(Error::Sys(Errno::EBADF))); } // Test modifying output flags #[test] fn test_output_flags() { // openpty uses ptname(3) internally - let _m = crate::PTSNAME_MTX.lock(); + let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); // Open one pty to get attributes for the second one let mut termios = { @@ -88,7 +88,7 @@ fn test_output_flags() { #[test] fn test_local_flags() { // openpty uses ptname(3) internally - let _m = crate::PTSNAME_MTX.lock(); + let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); // Open one pty to get attributes for the second one let mut termios = { @@ -126,5 +126,5 @@ fn test_local_flags() { let read = read(pty.master, &mut buf).unwrap_err(); close(pty.master).unwrap(); close(pty.slave).unwrap(); - assert_eq!(read, Errno::EAGAIN); + assert_eq!(read, Error::Sys(Errno::EAGAIN)); } diff --git a/test/sys/test_uio.rs b/test/sys/test_uio.rs index c63b581..8d22bf1 100644 --- a/test/sys/test_uio.rs +++ b/test/sys/test_uio.rs @@ -14,11 +14,7 @@ use tempfile::tempdir; fn test_writev() { let mut to_write = Vec::with_capacity(16 * 128); for _ in 0..16 { - let s: String = thread_rng() - .sample_iter(&Alphanumeric) - .map(char::from) - .take(128) - .collect(); + let s: String = thread_rng().sample_iter(&Alphanumeric).take(128).collect(); let b = s.as_bytes(); to_write.extend(b.iter().cloned()); } @@ -27,7 +23,7 @@ fn test_writev() { let mut consumed = 0; while consumed < to_write.len() { let left = to_write.len() - consumed; - let slice_len = if left <= 64 { left } else { thread_rng().gen_range(64..cmp::min(256, left)) }; + let slice_len = if left <= 64 { left } else { thread_rng().gen_range(64, cmp::min(256, left)) }; let b = &to_write[consumed..consumed+slice_len]; iovecs.push(IoVec::from_slice(b)); consumed += slice_len; @@ -61,17 +57,13 @@ fn test_writev() { #[test] #[cfg(not(target_os = "redox"))] fn test_readv() { - let s:String = thread_rng() - .sample_iter(&Alphanumeric) - .map(char::from) - .take(128) - .collect(); + let s:String = thread_rng().sample_iter(&Alphanumeric).take(128).collect(); let to_write = s.as_bytes().to_vec(); let mut storage = Vec::new(); let mut allocated = 0; while allocated < to_write.len() { let left = to_write.len() - allocated; - let vec_len = if left <= 64 { left } else { thread_rng().gen_range(64..cmp::min(256, left)) }; + let vec_len = if left <= 64 { left } else { thread_rng().gen_range(64, cmp::min(256, left)) }; let v: Vec<u8> = iter::repeat(0u8).take(vec_len).collect(); storage.push(v); allocated += vec_len; @@ -141,7 +133,7 @@ fn test_pread() { } #[test] -#[cfg(not(target_os = "redox"))] +#[cfg(target_os = "linux")] fn test_pwritev() { use std::io::Read; @@ -171,7 +163,7 @@ fn test_pwritev() { } #[test] -#[cfg(not(target_os = "redox"))] +#[cfg(target_os = "linux")] fn test_preadv() { use std::io::Write; @@ -205,16 +197,16 @@ fn test_preadv() { #[test] #[cfg(target_os = "linux")] -// qemu-user doesn't implement process_vm_readv/writev on most arches -#[cfg_attr(qemu, ignore)] +// FIXME: qemu-user doesn't implement process_vm_readv/writev on most arches +#[cfg_attr(not(any(target_arch = "x86", target_arch = "x86_64")), ignore)] fn test_process_vm_readv() { use nix::unistd::ForkResult::*; use nix::sys::signal::*; use nix::sys::wait::*; use crate::*; - require_capability!("test_process_vm_readv", CAP_SYS_PTRACE); - let _m = crate::FORK_MTX.lock(); + require_capability!(CAP_SYS_PTRACE); + let _ = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); // Pre-allocate memory in the child, since allocation isn't safe // post-fork (~= async-signal-safe) diff --git a/test/sys/test_wait.rs b/test/sys/test_wait.rs index afe4f42..5bb298e 100644 --- a/test/sys/test_wait.rs +++ b/test/sys/test_wait.rs @@ -1,4 +1,4 @@ -use nix::errno::Errno; +use nix::Error; use nix::unistd::*; use nix::unistd::ForkResult::*; use nix::sys::signal::*; @@ -8,7 +8,7 @@ use libc::_exit; #[test] #[cfg(not(target_os = "redox"))] fn test_wait_signal() { - let _m = crate::FORK_MTX.lock(); + let _ = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); // Safe: The child only calls `pause` and/or `_exit`, which are async-signal-safe. match unsafe{fork()}.expect("Error: Fork Failed") { @@ -25,7 +25,7 @@ fn test_wait_signal() { #[test] fn test_wait_exit() { - let _m = crate::FORK_MTX.lock(); + let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); // Safe: Child only calls `_exit`, which is async-signal-safe. match unsafe{fork()}.expect("Error: Fork Failed") { @@ -41,12 +41,12 @@ fn test_waitstatus_from_raw() { let pid = Pid::from_raw(1); assert_eq!(WaitStatus::from_raw(pid, 0x0002), Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false))); assert_eq!(WaitStatus::from_raw(pid, 0x0200), Ok(WaitStatus::Exited(pid, 2))); - assert_eq!(WaitStatus::from_raw(pid, 0x7f7f), Err(Errno::EINVAL)); + assert_eq!(WaitStatus::from_raw(pid, 0x7f7f), Err(Error::invalid_argument())); } #[test] fn test_waitstatus_pid() { - let _m = crate::FORK_MTX.lock(); + let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); match unsafe{fork()}.unwrap() { Child => unsafe { _exit(0) }, @@ -96,8 +96,8 @@ mod ptrace { #[test] fn test_wait_ptrace() { - require_capability!("test_wait_ptrace", CAP_SYS_PTRACE); - let _m = crate::FORK_MTX.lock(); + require_capability!(CAP_SYS_PTRACE); + let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); match unsafe{fork()}.expect("Error: Fork Failed") { Child => ptrace_child(), diff --git a/test/test.rs b/test/test.rs index aade937..5a5330b 100644 --- a/test/test.rs +++ b/test/test.rs @@ -13,8 +13,6 @@ mod test_fcntl; #[cfg(any(target_os = "android", target_os = "linux"))] mod test_kmod; -#[cfg(target_os = "freebsd")] -mod test_nmount; #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "fushsia", @@ -24,7 +22,6 @@ mod test_mq; #[cfg(not(target_os = "redox"))] mod test_net; mod test_nix_path; -mod test_resource; mod test_poll; #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] mod test_pty; @@ -43,7 +40,7 @@ mod test_unistd; use std::os::unix::io::RawFd; use std::path::PathBuf; -use parking_lot::{Mutex, RwLock, RwLockWriteGuard}; +use std::sync::{Mutex, RwLock, RwLockWriteGuard}; use nix::unistd::{chdir, getcwd, read}; @@ -84,7 +81,8 @@ struct DirRestore<'a> { impl<'a> DirRestore<'a> { fn new() -> Self { - let guard = crate::CWD_LOCK.write(); + let guard = crate::CWD_LOCK.write() + .expect("Lock got poisoned by another test"); DirRestore{ _g: guard, d: getcwd().unwrap(), diff --git a/test/test_dir.rs b/test/test_dir.rs index 2940b6e..505277e 100644 --- a/test/test_dir.rs +++ b/test/test_dir.rs @@ -4,25 +4,13 @@ use nix::sys::stat::Mode; use std::fs::File; use tempfile::tempdir; - -#[cfg(test)] -fn flags() -> OFlag { - #[cfg(target_os = "illumos")] - let f = OFlag::O_RDONLY | OFlag::O_CLOEXEC; - - #[cfg(not(target_os = "illumos"))] - let f = OFlag::O_RDONLY | OFlag::O_CLOEXEC | OFlag::O_DIRECTORY; - - f -} - #[test] -#[allow(clippy::unnecessary_sort_by)] // False positive fn read() { let tmp = tempdir().unwrap(); File::create(&tmp.path().join("foo")).unwrap(); ::std::os::unix::fs::symlink("foo", tmp.path().join("bar")).unwrap(); - let mut dir = Dir::open(tmp.path(), flags(), Mode::empty()).unwrap(); + let mut dir = Dir::open(tmp.path(), OFlag::O_DIRECTORY | OFlag::O_RDONLY | OFlag::O_CLOEXEC, + Mode::empty()).unwrap(); let mut entries: Vec<_> = dir.iter().map(|e| e.unwrap()).collect(); entries.sort_by(|a, b| a.file_name().cmp(b.file_name())); let entry_names: Vec<_> = entries @@ -42,7 +30,8 @@ fn read() { #[test] fn rewind() { let tmp = tempdir().unwrap(); - let mut dir = Dir::open(tmp.path(), flags(), Mode::empty()).unwrap(); + let mut dir = Dir::open(tmp.path(), OFlag::O_DIRECTORY | OFlag::O_RDONLY | OFlag::O_CLOEXEC, + 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(); @@ -52,5 +41,5 @@ fn rewind() { #[test] fn ebadf() { - assert_eq!(Dir::from_fd(-1).unwrap_err(), nix::Error::EBADF); + assert_eq!(Dir::from_fd(-1).unwrap_err(), nix::Error::Sys(nix::errno::Errno::EBADF)); } diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index db2acfb..5d1bafe 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -1,20 +1,11 @@ #[cfg(not(target_os = "redox"))] +use nix::Error; +#[cfg(not(target_os = "redox"))] use nix::errno::*; #[cfg(not(target_os = "redox"))] use nix::fcntl::{open, OFlag, readlink}; #[cfg(not(target_os = "redox"))] use nix::fcntl::{openat, readlinkat, renameat}; -#[cfg(all( - target_os = "linux", - target_env = "gnu", - any( - target_arch = "x86_64", - target_arch = "x32", - target_arch = "powerpc", - target_arch = "s390x" - ) -))] -use nix::fcntl::{RenameFlags, renameat2}; #[cfg(not(target_os = "redox"))] use nix::sys::stat::Mode; #[cfg(not(target_os = "redox"))] @@ -28,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() { @@ -62,139 +55,13 @@ fn test_renameat() { let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap(); assert_eq!(renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap_err(), - Errno::ENOENT); - close(old_dirfd).unwrap(); - close(new_dirfd).unwrap(); - assert!(new_dir.path().join("new").exists()); -} - -#[test] -#[cfg(all( - target_os = "linux", - target_env = "gnu", - any( - target_arch = "x86_64", - target_arch = "x32", - target_arch = "powerpc", - target_arch = "s390x" - ) -))] -fn test_renameat2_behaves_like_renameat_with_no_flags() { - let old_dir = tempfile::tempdir().unwrap(); - let old_dirfd = open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); - let old_path = old_dir.path().join("old"); - File::create(&old_path).unwrap(); - let new_dir = tempfile::tempdir().unwrap(); - let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); - renameat2( - Some(old_dirfd), - "old", - Some(new_dirfd), - "new", - RenameFlags::empty(), - ) - .unwrap(); - assert_eq!( - renameat2( - Some(old_dirfd), - "old", - Some(new_dirfd), - "new", - RenameFlags::empty() - ) - .unwrap_err(), - Errno::ENOENT - ); + Error::Sys(Errno::ENOENT)); close(old_dirfd).unwrap(); close(new_dirfd).unwrap(); assert!(new_dir.path().join("new").exists()); } #[test] -#[cfg(all( - target_os = "linux", - target_env = "gnu", - any( - target_arch = "x86_64", - target_arch = "x32", - target_arch = "powerpc", - target_arch = "s390x" - ) -))] -fn test_renameat2_exchange() { - let old_dir = tempfile::tempdir().unwrap(); - let old_dirfd = open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); - let old_path = old_dir.path().join("old"); - { - let mut old_f = File::create(&old_path).unwrap(); - old_f.write_all(b"old").unwrap(); - } - let new_dir = tempfile::tempdir().unwrap(); - let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); - let new_path = new_dir.path().join("new"); - { - let mut new_f = File::create(&new_path).unwrap(); - new_f.write_all(b"new").unwrap(); - } - renameat2( - Some(old_dirfd), - "old", - Some(new_dirfd), - "new", - RenameFlags::RENAME_EXCHANGE, - ) - .unwrap(); - let mut buf = String::new(); - let mut new_f = File::open(&new_path).unwrap(); - new_f.read_to_string(&mut buf).unwrap(); - assert_eq!(buf, "old"); - buf = "".to_string(); - let mut old_f = File::open(&old_path).unwrap(); - old_f.read_to_string(&mut buf).unwrap(); - assert_eq!(buf, "new"); - close(old_dirfd).unwrap(); - close(new_dirfd).unwrap(); -} - -#[test] -#[cfg(all( - target_os = "linux", - target_env = "gnu", - any( - target_arch = "x86_64", - target_arch = "x32", - target_arch = "powerpc", - target_arch = "s390x" - ) -))] -fn test_renameat2_noreplace() { - let old_dir = tempfile::tempdir().unwrap(); - let old_dirfd = open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); - let old_path = old_dir.path().join("old"); - File::create(&old_path).unwrap(); - let new_dir = tempfile::tempdir().unwrap(); - let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); - let new_path = new_dir.path().join("new"); - File::create(&new_path).unwrap(); - assert_eq!( - renameat2( - Some(old_dirfd), - "old", - Some(new_dirfd), - "new", - RenameFlags::RENAME_NOREPLACE - ) - .unwrap_err(), - Errno::EEXIST - ); - close(old_dirfd).unwrap(); - close(new_dirfd).unwrap(); - assert!(new_dir.path().join("new").exists()); - assert!(old_dir.path().join("old").exists()); -} - - -#[test] #[cfg(not(target_os = "redox"))] fn test_readlink() { let tempdir = tempfile::tempdir().unwrap(); @@ -214,18 +81,19 @@ fn test_readlink() { #[cfg(any(target_os = "linux", target_os = "android"))] mod linux_android { + use std::fs::File; use std::io::prelude::*; - use std::io::SeekFrom; + use std::io::{BufRead, BufReader, SeekFrom}; use std::os::unix::prelude::*; + use libc::loff_t; use nix::fcntl::*; + use nix::sys::stat::fstat; use nix::sys::uio::IoVec; use nix::unistd::{close, pipe, read, write}; - use tempfile::tempfile; - #[cfg(any(target_os = "linux"))] - use tempfile::NamedTempFile; + use tempfile::{tempfile, NamedTempFile}; use crate::*; @@ -235,9 +103,11 @@ mod linux_android { /// resulting file is read and should contain the contents `bar`. /// The from_offset should be updated by the call to reflect /// the 3 bytes read (6). + /// + /// FIXME: This test is disabled for linux based builds, because Travis + /// Linux version is too old for `copy_file_range`. #[test] - // QEMU does not support copy_file_range. Skip under qemu - #[cfg_attr(qemu, ignore)] + #[ignore] fn test_copy_file_range() { const CONTENTS: &[u8] = b"foobarbaz"; @@ -319,10 +189,9 @@ mod linux_android { let buf1 = b"abcdef"; let buf2 = b"defghi"; - let iovecs = vec![ - IoVec::from_slice(&buf1[0..3]), - IoVec::from_slice(&buf2[0..3]) - ]; + let mut iovecs = Vec::with_capacity(2); + iovecs.push(IoVec::from_slice(&buf1[0..3])); + iovecs.push(IoVec::from_slice(&buf2[0..3])); let res = vmsplice(wr, &iovecs[..], SpliceFFlags::empty()).unwrap(); @@ -337,7 +206,6 @@ mod linux_android { close(wr).unwrap(); } - #[cfg(any(target_os = "linux"))] #[test] fn test_fallocate() { let tmp = NamedTempFile::new().unwrap(); @@ -356,11 +224,17 @@ mod linux_android { // they run under QEMU. #[test] - #[cfg(all(target_os = "linux", not(target_env = "musl")))] + #[cfg(not(any(target_arch = "aarch64", + target_arch = "arm", + target_arch = "armv7", + target_arch = "x86", + target_arch = "mips", + target_arch = "mips64", + target_arch = "mips64el", + target_arch = "powerpc64", + target_arch = "powerpc64le", + target_env = "musl")))] fn test_ofd_write_lock() { - use nix::sys::stat::fstat; - use std::mem; - let tmp = NamedTempFile::new().unwrap(); let fd = tmp.as_raw_fd(); @@ -373,14 +247,13 @@ mod linux_android { } let inode = fstat(fd).expect("fstat failed").st_ino as usize; - let mut flock: libc::flock = unsafe { - mem::zeroed() // required for Linux/mips + let mut flock = libc::flock { + l_type: libc::F_WRLCK as libc::c_short, + l_whence: libc::SEEK_SET as libc::c_short, + l_start: 0, + l_len: 0, + l_pid: 0, }; - flock.l_type = libc::F_WRLCK as libc::c_short; - flock.l_whence = libc::SEEK_SET as libc::c_short; - flock.l_start = 0; - flock.l_len = 0; - flock.l_pid = 0; fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("write lock failed"); assert_eq!( Some(("OFDLCK".to_string(), "WRITE".to_string())), @@ -393,11 +266,17 @@ mod linux_android { } #[test] - #[cfg(all(target_os = "linux", not(target_env = "musl")))] + #[cfg(not(any(target_arch = "aarch64", + target_arch = "arm", + target_arch = "armv7", + target_arch = "x86", + target_arch = "mips", + target_arch = "mips64", + target_arch = "mips64el", + target_arch = "powerpc64", + target_arch = "powerpc64le", + target_env = "musl")))] fn test_ofd_read_lock() { - use nix::sys::stat::fstat; - use std::mem; - let tmp = NamedTempFile::new().unwrap(); let fd = tmp.as_raw_fd(); @@ -410,14 +289,13 @@ mod linux_android { } let inode = fstat(fd).expect("fstat failed").st_ino as usize; - let mut flock: libc::flock = unsafe { - mem::zeroed() // required for Linux/mips + let mut flock = libc::flock { + l_type: libc::F_RDLCK as libc::c_short, + l_whence: libc::SEEK_SET as libc::c_short, + l_start: 0, + l_len: 0, + l_pid: 0, }; - flock.l_type = libc::F_RDLCK as libc::c_short; - flock.l_whence = libc::SEEK_SET as libc::c_short; - flock.l_start = 0; - flock.l_len = 0; - flock.l_pid = 0; fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("read lock failed"); assert_eq!( Some(("OFDLCK".to_string(), "READ".to_string())), @@ -429,13 +307,7 @@ mod linux_android { assert_eq!(None, lock_info(inode)); } - #[cfg(all(target_os = "linux", not(target_env = "musl")))] fn lock_info(inode: usize) -> Option<(String, String)> { - use std::{ - fs::File, - io::BufReader - }; - let file = File::open("/proc/locks").expect("open /proc/locks failed"); let buf = BufReader::new(file); @@ -473,16 +345,17 @@ mod test_posix_fadvise { fn test_success() { let tmp = NamedTempFile::new().unwrap(); let fd = tmp.as_raw_fd(); - let res = posix_fadvise(fd, 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED); + let res = posix_fadvise(fd, 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED).unwrap(); - assert!(res.is_ok()); + assert_eq!(res, 0); } #[test] fn test_errno() { let (rd, _wr) = pipe().unwrap(); - let res = posix_fadvise(rd as RawFd, 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED); - assert_eq!(res, Err(Errno::ESPIPE)); + let errno = posix_fadvise(rd as RawFd, 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED) + .unwrap(); + assert_eq!(errno, Errno::ESPIPE as i32); } } @@ -512,7 +385,7 @@ mod test_posix_fallocate { assert_eq!(tmp.read(&mut data).expect("read failure"), LEN); assert_eq!(&data[..], &[0u8; LEN][..]); } - Err(Errno::EINVAL) => { + Err(nix::Error::Sys(Errno::EINVAL)) => { // POSIX requires posix_fallocate to return EINVAL both for // invalid arguments (i.e. len < 0) and if the operation is not // supported by the file system. @@ -528,8 +401,12 @@ mod test_posix_fallocate { fn errno() { let (rd, _wr) = pipe().unwrap(); let err = posix_fallocate(rd as RawFd, 0, 100).unwrap_err(); + use nix::Error::Sys; match err { - Errno::EINVAL | Errno::ENODEV | Errno::ESPIPE | Errno::EBADF => (), + Sys(Errno::EINVAL) + | Sys(Errno::ENODEV) + | Sys(Errno::ESPIPE) + | Sys(Errno::EBADF) => (), errno => panic!( "unexpected errno {}", diff --git a/test/test_kmod/mod.rs b/test/test_kmod/mod.rs index 8eef538..fb7260b 100644 --- a/test/test_kmod/mod.rs +++ b/test/test_kmod/mod.rs @@ -5,7 +5,9 @@ use tempfile::{tempdir, TempDir}; use crate::*; fn compile_kernel_module() -> (PathBuf, String, TempDir) { - let _m = crate::FORK_MTX.lock(); + let _m = crate::FORK_MTX + .lock() + .expect("Mutex got poisoned by another test"); let tmp_dir = tempdir().expect("unable to create temporary build directory"); @@ -32,15 +34,16 @@ fn compile_kernel_module() -> (PathBuf, String, TempDir) { use nix::errno::Errno; use nix::kmod::{delete_module, DeleteModuleFlags}; use nix::kmod::{finit_module, init_module, ModuleInitFlags}; +use nix::Error; use std::ffi::CString; use std::fs::File; use std::io::Read; #[test] fn test_finit_and_delete_module() { - require_capability!("test_finit_and_delete_module", CAP_SYS_MODULE); - let _m0 = crate::KMOD_MTX.lock(); - let _m1 = crate::CWD_LOCK.read(); + require_capability!(CAP_SYS_MODULE); + let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); + let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); @@ -55,10 +58,10 @@ fn test_finit_and_delete_module() { } #[test] -fn test_finit_and_delete_module_with_params() { - require_capability!("test_finit_and_delete_module_with_params", CAP_SYS_MODULE); - let _m0 = crate::KMOD_MTX.lock(); - let _m1 = crate::CWD_LOCK.read(); +fn test_finit_and_delete_modul_with_params() { + require_capability!(CAP_SYS_MODULE); + let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); + let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); @@ -77,9 +80,9 @@ fn test_finit_and_delete_module_with_params() { #[test] fn test_init_and_delete_module() { - require_capability!("test_init_and_delete_module", CAP_SYS_MODULE); - let _m0 = crate::KMOD_MTX.lock(); - let _m1 = crate::CWD_LOCK.read(); + require_capability!(CAP_SYS_MODULE); + let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); + let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); @@ -87,7 +90,7 @@ fn test_init_and_delete_module() { let mut contents: Vec<u8> = Vec::new(); f.read_to_end(&mut contents) .expect("unable to read kernel module content to buffer"); - init_module(&contents, &CString::new("").unwrap()).expect("unable to load kernel module"); + init_module(&mut contents, &CString::new("").unwrap()).expect("unable to load kernel module"); delete_module( &CString::new(kmod_name).unwrap(), @@ -97,9 +100,9 @@ fn test_init_and_delete_module() { #[test] fn test_init_and_delete_module_with_params() { - require_capability!("test_init_and_delete_module_with_params", CAP_SYS_MODULE); - let _m0 = crate::KMOD_MTX.lock(); - let _m1 = crate::CWD_LOCK.read(); + require_capability!(CAP_SYS_MODULE); + let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); + let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); @@ -107,7 +110,7 @@ fn test_init_and_delete_module_with_params() { let mut contents: Vec<u8> = Vec::new(); f.read_to_end(&mut contents) .expect("unable to read kernel module content to buffer"); - init_module(&contents, &CString::new("who=Nix number=2015").unwrap()) + init_module(&mut contents, &CString::new("who=Nix number=2015").unwrap()) .expect("unable to load kernel module"); delete_module( @@ -118,23 +121,23 @@ fn test_init_and_delete_module_with_params() { #[test] fn test_finit_module_invalid() { - require_capability!("test_finit_module_invalid", CAP_SYS_MODULE); - let _m0 = crate::KMOD_MTX.lock(); - let _m1 = crate::CWD_LOCK.read(); + require_capability!(CAP_SYS_MODULE); + let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); + let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); let kmod_path = "/dev/zero"; let f = File::open(kmod_path).expect("unable to open kernel module"); let result = finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()); - assert_eq!(result.unwrap_err(), Errno::EINVAL); + assert_eq!(result.unwrap_err(), Error::Sys(Errno::EINVAL)); } #[test] fn test_finit_module_twice_and_delete_module() { - require_capability!("test_finit_module_twice_and_delete_module", CAP_SYS_MODULE); - let _m0 = crate::KMOD_MTX.lock(); - let _m1 = crate::CWD_LOCK.read(); + require_capability!(CAP_SYS_MODULE); + let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); + let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); @@ -144,7 +147,7 @@ fn test_finit_module_twice_and_delete_module() { let result = finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()); - assert_eq!(result.unwrap_err(), Errno::EEXIST); + assert_eq!(result.unwrap_err(), Error::Sys(Errno::EEXIST)); delete_module( &CString::new(kmod_name).unwrap(), @@ -154,11 +157,11 @@ fn test_finit_module_twice_and_delete_module() { #[test] fn test_delete_module_not_loaded() { - require_capability!("test_delete_module_not_loaded", CAP_SYS_MODULE); - let _m0 = crate::KMOD_MTX.lock(); - let _m1 = crate::CWD_LOCK.read(); + require_capability!(CAP_SYS_MODULE); + let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); + let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); let result = delete_module(&CString::new("hello").unwrap(), DeleteModuleFlags::empty()); - assert_eq!(result.unwrap_err(), Errno::ENOENT); + assert_eq!(result.unwrap_err(), Error::Sys(Errno::ENOENT)); } diff --git a/test/test_mount.rs b/test/test_mount.rs index 44287f9..c1b6c8a 100644 --- a/test/test_mount.rs +++ b/test/test_mount.rs @@ -21,13 +21,14 @@ mod test_mount { use nix::sys::stat::{self, Mode}; use nix::unistd::getuid; - static SCRIPT_CONTENTS: &[u8] = b"#!/bin/sh + use tempfile; + + static SCRIPT_CONTENTS: &'static [u8] = b"#!/bin/sh exit 23"; const EXPECTED_STATUS: i32 = 23; const NONE: Option<&'static [u8]> = None; - #[allow(clippy::bind_instead_of_map)] // False positive pub fn test_mount_tmpfs_without_flags_allows_rwx() { let tempdir = tempfile::tempdir().unwrap(); diff --git a/test/test_mq.rs b/test/test_mq.rs index 430df5d..1667a35 100644 --- a/test/test_mq.rs +++ b/test/test_mq.rs @@ -1,7 +1,8 @@ use std::ffi::CString; use std::str; -use nix::errno::Errno; +use nix::errno::Errno::*; +use nix::Error::Sys; 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; @@ -15,7 +16,7 @@ fn test_mq_send_and_receive() { let oflag0 = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; let r0 = mq_open(mq_name, oflag0, mode, Some(&attr)); - if let Err(Errno::ENOSYS) = r0 { + if let Err(Sys(ENOSYS)) = r0 { println!("message queues not supported or module not loaded?"); return; }; @@ -46,7 +47,7 @@ fn test_mq_getattr() { let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; let r = mq_open(mq_name, oflag, mode, Some(&initial_attr)); - if let Err(Errno::ENOSYS) = r { + if let Err(Sys(ENOSYS)) = r { println!("message queues not supported or module not loaded?"); return; }; @@ -60,11 +61,7 @@ fn test_mq_getattr() { // FIXME: Fix failures for mips in QEMU #[test] #[cfg(not(any(target_os = "netbsd")))] -#[cfg_attr(all( - qemu, - any(target_arch = "mips", target_arch = "mips64") - ), ignore -)] +#[cfg_attr(any(target_arch = "mips", target_arch = "mips64"), ignore)] fn test_mq_setattr() { use nix::mqueue::{mq_getattr, mq_setattr}; const MSG_SIZE: mq_attr_member_t = 32; @@ -73,7 +70,7 @@ fn test_mq_setattr() { let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; let r = mq_open(mq_name, oflag, mode, Some(&initial_attr)); - if let Err(Errno::ENOSYS) = r { + if let Err(Sys(ENOSYS)) = r { println!("message queues not supported or module not loaded?"); return; }; @@ -101,11 +98,7 @@ fn test_mq_setattr() { // FIXME: Fix failures for mips in QEMU #[test] #[cfg(not(any(target_os = "netbsd")))] -#[cfg_attr(all( - qemu, - any(target_arch = "mips", target_arch = "mips64") - ), ignore -)] +#[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: mq_attr_member_t = 32; @@ -114,7 +107,7 @@ fn test_mq_set_nonblocking() { let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; let r = mq_open(mq_name, oflag, mode, Some(&initial_attr)); - if let Err(Errno::ENOSYS) = r { + if let Err(Sys(ENOSYS)) = r { println!("message queues not supported or module not loaded?"); return; }; @@ -139,7 +132,7 @@ fn test_mq_unlink() { let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; let r = mq_open(mq_name_opened, oflag, mode, Some(&initial_attr)); - if let Err(Errno::ENOSYS) = r { + if let Err(Sys(ENOSYS)) = r { println!("message queues not supported or module not loaded?"); return; }; @@ -149,9 +142,9 @@ fn test_mq_unlink() { assert_eq!(res_unlink, Ok(()) ); let res_unlink_not_opened = mq_unlink(mq_name_not_opened); - assert_eq!(res_unlink_not_opened, Err(Errno::ENOENT) ); + assert_eq!(res_unlink_not_opened, Err(Sys(ENOENT)) ); mq_close(mqd).unwrap(); let res_unlink_after_close = mq_unlink(mq_name_opened); - assert_eq!(res_unlink_after_close, Err(Errno::ENOENT) ); + assert_eq!(res_unlink_after_close, Err(Sys(ENOENT)) ); } diff --git a/test/test_net.rs b/test/test_net.rs index 40ecd6b..b8940e7 100644 --- a/test/test_net.rs +++ b/test/test_net.rs @@ -8,5 +8,5 @@ const LOOPBACK: &[u8] = b"lo0"; #[test] fn test_if_nametoindex() { - assert!(if_nametoindex(LOOPBACK).is_ok()); + assert!(if_nametoindex(&LOOPBACK[..]).is_ok()); } diff --git a/test/test_nmount.rs b/test/test_nmount.rs deleted file mode 100644 index 4c74ecf..0000000 --- a/test/test_nmount.rs +++ /dev/null @@ -1,51 +0,0 @@ -use crate::*; -use nix::{ - errno::Errno, - mount::{MntFlags, Nmount, unmount} -}; -use std::{ - ffi::CString, - fs::File, - path::Path -}; -use tempfile::tempdir; - -#[test] -fn ok() { - require_mount!("nullfs"); - - let mountpoint = tempdir().unwrap(); - let target = tempdir().unwrap(); - let _sentry = File::create(target.path().join("sentry")).unwrap(); - - let fstype = CString::new("fstype").unwrap(); - let nullfs = CString::new("nullfs").unwrap(); - Nmount::new() - .str_opt(&fstype, &nullfs) - .str_opt_owned("fspath", mountpoint.path().to_str().unwrap()) - .str_opt_owned("target", target.path().to_str().unwrap()) - .nmount(MntFlags::empty()).unwrap(); - - // Now check that the sentry is visible through the mountpoint - let exists = Path::exists(&mountpoint.path().join("sentry")); - - // Cleanup the mountpoint before asserting - unmount(mountpoint.path(), MntFlags::empty()).unwrap(); - - assert!(exists); -} - -#[test] -fn bad_fstype() { - let mountpoint = tempdir().unwrap(); - let target = tempdir().unwrap(); - let _sentry = File::create(target.path().join("sentry")).unwrap(); - - let e = Nmount::new() - .str_opt_owned("fspath", mountpoint.path().to_str().unwrap()) - .str_opt_owned("target", target.path().to_str().unwrap()) - .nmount(MntFlags::empty()).unwrap_err(); - - assert_eq!(e.error(), Errno::EINVAL); - assert_eq!(e.errmsg(), Some("Invalid fstype")); -} diff --git a/test/test_poll.rs b/test/test_poll.rs index e4b369f..a5e2d25 100644 --- a/test/test_poll.rs +++ b/test/test_poll.rs @@ -1,4 +1,5 @@ use nix::{ + Error, errno::Errno, poll::{PollFlags, poll, PollFd}, unistd::{write, pipe} @@ -9,8 +10,8 @@ macro_rules! loop_while_eintr { loop { match $poll_expr { Ok(nfds) => break nfds, - Err(Errno::EINTR) => (), - Err(e) => panic!("{}", e) + Err(Error::Sys(Errno::EINTR)) => (), + Err(e) => panic!(e) } } } @@ -64,19 +65,3 @@ fn test_ppoll() { assert_eq!(nfds, 1); assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN)); } - -#[test] -fn test_pollfd_fd() { - use std::os::unix::io::AsRawFd; - - let pfd = PollFd::new(0x1234, PollFlags::empty()); - assert_eq!(pfd.as_raw_fd(), 0x1234); -} - -#[test] -fn test_pollfd_events() { - let mut pfd = PollFd::new(-1, PollFlags::POLLIN); - assert_eq!(pfd.events(), PollFlags::POLLIN); - pfd.set_events(PollFlags::POLLOUT); - assert_eq!(pfd.events(), PollFlags::POLLOUT); -} diff --git a/test/test_pty.rs b/test/test_pty.rs index 71932f2..ab347bb 100644 --- a/test/test_pty.rs +++ b/test/test_pty.rs @@ -29,7 +29,7 @@ fn test_explicit_close() { #[test] #[cfg(any(target_os = "android", target_os = "linux"))] fn test_ptsname_equivalence() { - let _m = crate::PTSNAME_MTX.lock(); + let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); // Open a new PTTY master let master_fd = posix_openpt(OFlag::O_RDWR).unwrap(); @@ -46,7 +46,7 @@ fn test_ptsname_equivalence() { #[test] #[cfg(any(target_os = "android", target_os = "linux"))] fn test_ptsname_copy() { - let _m = crate::PTSNAME_MTX.lock(); + let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); // Open a new PTTY master let master_fd = posix_openpt(OFlag::O_RDWR).unwrap(); @@ -80,7 +80,7 @@ fn test_ptsname_r_copy() { #[test] #[cfg(any(target_os = "android", target_os = "linux"))] fn test_ptsname_unique() { - let _m = crate::PTSNAME_MTX.lock(); + let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); // Open a new PTTY master let master1_fd = posix_openpt(OFlag::O_RDWR).unwrap(); @@ -98,7 +98,7 @@ fn test_ptsname_unique() { /// Common setup for testing PTTY pairs fn open_ptty_pair() -> (PtyMaster, File) { - let _m = crate::PTSNAME_MTX.lock(); + let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); // Open a new PTTY master let master = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed"); @@ -112,30 +112,6 @@ fn open_ptty_pair() -> (PtyMaster, File) { // Open the slave device let slave_fd = open(Path::new(&slave_name), OFlag::O_RDWR, stat::Mode::empty()).unwrap(); - - #[cfg(target_os = "illumos")] - // TODO: rewrite using ioctl! - #[allow(clippy::comparison_chain)] - { - use libc::{ioctl, I_FIND, I_PUSH}; - - // On illumos systems, as per pts(7D), one must push STREAMS modules - // after opening a device path returned from ptsname(). - let ptem = b"ptem\0"; - let ldterm = b"ldterm\0"; - let r = unsafe { ioctl(slave_fd, I_FIND, ldterm.as_ptr()) }; - if r < 0 { - panic!("I_FIND failure"); - } else if r == 0 { - if unsafe { ioctl(slave_fd, I_PUSH, ptem.as_ptr()) } < 0 { - panic!("I_PUSH ptem failure"); - } - if unsafe { ioctl(slave_fd, I_PUSH, ldterm.as_ptr()) } < 0 { - panic!("I_PUSH ldterm failure"); - } - } - } - let slave = unsafe { File::from_raw_fd(slave_fd) }; (master, slave) @@ -187,7 +163,7 @@ fn test_write_ptty_pair() { #[test] fn test_openpty() { // openpty uses ptname(3) internally - let _m = crate::PTSNAME_MTX.lock(); + let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); let pty = openpty(None, None).unwrap(); assert!(pty.master > 0); @@ -222,7 +198,7 @@ fn test_openpty() { #[test] fn test_openpty_with_termios() { // openpty uses ptname(3) internally - let _m = crate::PTSNAME_MTX.lock(); + let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); // Open one pty to get attributes for the second one let mut termios = { @@ -273,15 +249,13 @@ fn test_forkpty() { use nix::sys::signal::*; use nix::sys::wait::wait; // forkpty calls openpty which uses ptname(3) internally. - let _m0 = crate::PTSNAME_MTX.lock(); + let _m0 = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test"); // forkpty spawns a child process - let _m1 = crate::FORK_MTX.lock(); + let _m1 = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); let string = "naninani\n"; let echoed_string = "naninani\r\n"; - let pty = unsafe { - forkpty(None, None).unwrap() - }; + let pty = forkpty(None, None).unwrap(); match pty.fork_result { Child => { write(STDOUT_FILENO, string.as_bytes()).unwrap(); diff --git a/test/test_ptymaster_drop.rs b/test/test_ptymaster_drop.rs index a68f81e..ff939b9 100644 --- a/test/test_ptymaster_drop.rs +++ b/test/test_ptymaster_drop.rs @@ -12,6 +12,10 @@ mod t { /// race condition. #[test] #[should_panic(expected = "Closing an invalid file descriptor!")] + // In Travis on i686-unknown-linux-musl, this test gets SIGABRT. I don't + // know why. It doesn't happen on any other target, and it doesn't happen + // on my PC. + #[cfg_attr(all(target_env = "musl", target_arch = "x86"), ignore)] fn test_double_close() { let m = posix_openpt(OFlag::O_RDWR).unwrap(); close(m.as_raw_fd()).unwrap(); diff --git a/test/test_resource.rs b/test/test_resource.rs deleted file mode 100644 index 5969750..0000000 --- a/test/test_resource.rs +++ /dev/null @@ -1,23 +0,0 @@ -#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "illumos")))] -use nix::sys::resource::{getrlimit, setrlimit, Resource}; - -/// Tests the RLIMIT_NOFILE functionality of getrlimit(), where the resource RLIMIT_NOFILE refers -/// to the maximum file descriptor number that can be opened by the process (aka the maximum number -/// of file descriptors that the process can open, since Linux 4.5). -/// -/// We first fetch the existing file descriptor maximum values using getrlimit(), then edit the -/// soft limit to make sure it has a new and distinct value to the hard limit. We then setrlimit() -/// to put the new soft limit in effect, and then getrlimit() once more to ensure the limits have -/// been updated. -#[test] -#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "illumos")))] -pub fn test_resource_limits_nofile() { - let (soft_limit, hard_limit) = getrlimit(Resource::RLIMIT_NOFILE).unwrap(); - - let soft_limit = Some(soft_limit.map_or(1024, |v| v - 1)); - assert_ne!(soft_limit, hard_limit); - setrlimit(Resource::RLIMIT_NOFILE, soft_limit, hard_limit).unwrap(); - - let (new_soft_limit, _) = getrlimit(Resource::RLIMIT_NOFILE).unwrap(); - assert_eq!(new_soft_limit, soft_limit); -} diff --git a/test/test_sendfile.rs b/test/test_sendfile.rs index b6559d3..3bc7932 100644 --- a/test/test_sendfile.rs +++ b/test/test_sendfile.rs @@ -36,28 +36,6 @@ fn test_sendfile_linux() { close(wr).unwrap(); } -#[cfg(target_os = "linux")] -#[test] -fn test_sendfile64_linux() { - const CONTENTS: &[u8] = b"abcdef123456"; - let mut tmp = tempfile().unwrap(); - tmp.write_all(CONTENTS).unwrap(); - - let (rd, wr) = pipe().unwrap(); - let mut offset: libc::off64_t = 5; - let res = sendfile64(wr, tmp.as_raw_fd(), Some(&mut offset), 2).unwrap(); - - assert_eq!(2, res); - - let mut buf = [0u8; 1024]; - assert_eq!(2, read(rd, &mut buf).unwrap()); - assert_eq!(b"f1", &buf[0..2]); - assert_eq!(7, offset); - - close(rd).unwrap(); - close(wr).unwrap(); -} - #[cfg(target_os = "freebsd")] #[test] fn test_sendfile_freebsd() { diff --git a/test/test_stat.rs b/test/test_stat.rs index 33cf748..0b94666 100644 --- a/test/test_stat.rs +++ b/test/test_stat.rs @@ -10,11 +10,10 @@ use std::time::{Duration, UNIX_EPOCH}; use std::path::Path; #[cfg(not(any(target_os = "netbsd", target_os = "redox")))] -use libc::{S_IFMT, S_IFLNK}; -use libc::mode_t; +use libc::{S_IFMT, S_IFLNK, mode_t}; #[cfg(not(target_os = "redox"))] -use nix::fcntl; +use nix::{fcntl, Error}; #[cfg(not(target_os = "redox"))] use nix::errno::Errno; #[cfg(not(target_os = "redox"))] @@ -43,6 +42,18 @@ use nix::unistd::chdir; #[cfg(not(any(target_os = "netbsd", target_os = "redox")))] use nix::Result; +use tempfile; + +#[allow(unused_comparisons)] +// uid and gid are signed on Windows, but not on other platforms. This function +// allows warning free compiles on all platforms, and can be removed when +// expression-level #[allow] is available. +#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] +fn valid_uid_gid(stat: FileStat) -> bool { + // uid could be 0 for the `root` user. This quite possible when + // the tests are being run on a rooted Android device. + stat.st_uid >= 0 && stat.st_gid >= 0 +} #[cfg(not(any(target_os = "netbsd", target_os = "redox")))] fn assert_stat_results(stat_result: Result<FileStat>) { @@ -51,15 +62,13 @@ fn assert_stat_results(stat_result: Result<FileStat>) { assert!(stats.st_ino > 0); // inode is positive integer, exact number machine dependent assert!(stats.st_mode > 0); // must be positive integer assert_eq!(stats.st_nlink, 1); // there links created, must be 1 + assert!(valid_uid_gid(stats)); // must be positive integers assert_eq!(stats.st_size, 0); // size is 0 because we did not write anything to the file assert!(stats.st_blksize > 0); // must be positive integer, exact number machine dependent assert!(stats.st_blocks <= 16); // Up to 16 blocks can be allocated for a blank file } #[cfg(not(any(target_os = "netbsd", target_os = "redox")))] -// (Android's st_blocks is ulonglong which is always non-negative.) -#[cfg_attr(target_os = "android", allow(unused_comparisons))] -#[allow(clippy::absurd_extreme_comparisons)] // Not absurd on all OSes fn assert_lstat_results(stat_result: Result<FileStat>) { let stats = stat_result.expect("stat call failed"); assert!(stats.st_dev > 0); // must be positive integer, exact number machine dependent @@ -71,11 +80,13 @@ fn assert_lstat_results(stat_result: Result<FileStat>) { // On other platforms they are the same (either both are u16 or u32). assert_eq!((stats.st_mode as usize) & (S_IFMT as usize), S_IFLNK as usize); // should be a link assert_eq!(stats.st_nlink, 1); // there links created, must be 1 + assert!(valid_uid_gid(stats)); // must be positive integers assert!(stats.st_size > 0); // size is > 0 because it points to another file assert!(stats.st_blksize > 0); // must be positive integer, exact number machine dependent // st_blocks depends on whether the machine's file system uses fast // or slow symlinks, so just make sure it's not negative + // (Android's st_blocks is ulonglong which is always non-negative.) assert!(stats.st_blocks >= 0); } @@ -148,14 +159,14 @@ fn test_fchmod() { fchmod(file.as_raw_fd(), mode1).unwrap(); let file_stat1 = stat(&filename).unwrap(); - assert_eq!(file_stat1.st_mode as mode_t & 0o7777, mode1.bits()); + assert_eq!(file_stat1.st_mode & 0o7777, mode1.bits()); let mut mode2 = Mode::empty(); mode2.insert(Mode::S_IROTH); fchmod(file.as_raw_fd(), mode2).unwrap(); let file_stat2 = stat(&filename).unwrap(); - assert_eq!(file_stat2.st_mode as mode_t & 0o7777, mode2.bits()); + assert_eq!(file_stat2.st_mode & 0o7777, mode2.bits()); } #[test] @@ -175,7 +186,7 @@ fn test_fchmodat() { fchmodat(Some(dirfd), filename, mode1, FchmodatFlags::FollowSymlink).unwrap(); let file_stat1 = stat(&fullpath).unwrap(); - assert_eq!(file_stat1.st_mode as mode_t & 0o7777, mode1.bits()); + assert_eq!(file_stat1.st_mode & 0o7777, mode1.bits()); chdir(tempdir.path()).unwrap(); @@ -184,7 +195,7 @@ fn test_fchmodat() { fchmodat(None, filename, mode2, FchmodatFlags::FollowSymlink).unwrap(); let file_stat2 = stat(&fullpath).unwrap(); - assert_eq!(file_stat2.st_mode as mode_t & 0o7777, mode2.bits()); + assert_eq!(file_stat2.st_mode & 0o7777, mode2.bits()); } /// Asserts that the atime and mtime in a file's metadata match expected values. @@ -304,55 +315,5 @@ fn test_mkdirat_fail() { let dirfd = fcntl::open(&tempdir.path().join(not_dir_filename), fcntl::OFlag::O_CREAT, stat::Mode::empty()).unwrap(); let result = mkdirat(dirfd, filename, Mode::S_IRWXU).unwrap_err(); - assert_eq!(result, Errno::ENOTDIR); -} - -#[test] -#[cfg(not(any(target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "redox")))] -fn test_mknod() { - use stat::{lstat, mknod, SFlag}; - - let file_name = "test_file"; - let tempdir = tempfile::tempdir().unwrap(); - let target = tempdir.path().join(file_name); - mknod(&target, SFlag::S_IFREG, Mode::S_IRWXU, 0).unwrap(); - let mode = lstat(&target).unwrap().st_mode as mode_t; - assert!(mode & libc::S_IFREG == libc::S_IFREG); - assert!(mode & libc::S_IRWXU == libc::S_IRWXU); -} - -#[test] -#[cfg(not(any(target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "redox")))] -fn test_mknodat() { - use fcntl::{AtFlags, OFlag}; - use nix::dir::Dir; - use stat::{fstatat, mknodat, SFlag}; - - let file_name = "test_file"; - let tempdir = tempfile::tempdir().unwrap(); - let target_dir = Dir::open(tempdir.path(), OFlag::O_DIRECTORY, Mode::S_IRWXU).unwrap(); - mknodat( - target_dir.as_raw_fd(), - file_name, - SFlag::S_IFREG, - Mode::S_IRWXU, - 0, - ) - .unwrap(); - let mode = fstatat( - target_dir.as_raw_fd(), - file_name, - AtFlags::AT_SYMLINK_NOFOLLOW, - ) - .unwrap() - .st_mode as mode_t; - assert!(mode & libc::S_IFREG == libc::S_IFREG); - assert!(mode & libc::S_IRWXU == libc::S_IRWXU); + assert_eq!(result, Error::Sys(Errno::ENOTDIR)); } diff --git a/test/test_time.rs b/test/test_time.rs index dc307e5..c321352 100644 --- a/test/test_time.rs +++ b/test/test_time.rs @@ -6,12 +6,11 @@ target_os = "emscripten", ))] use nix::time::clock_getcpuclockid; -use nix::time::{clock_gettime, ClockId}; +use nix::time::{clock_getres, clock_gettime, ClockId}; -#[cfg(not(target_os = "redox"))] #[test] pub fn test_clock_getres() { - assert!(nix::time::clock_getres(ClockId::CLOCK_REALTIME).is_ok()); + assert!(clock_getres(ClockId::CLOCK_REALTIME).is_ok()); } #[test] @@ -32,7 +31,6 @@ pub fn test_clock_getcpuclockid() { assert!(clock_gettime(clock_id).is_ok()); } -#[cfg(not(target_os = "redox"))] #[test] pub fn test_clock_id_res() { assert!(ClockId::CLOCK_REALTIME.res().is_ok()); diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 61062ad..16a8a05 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -1,6 +1,6 @@ #[cfg(not(target_os = "redox"))] use nix::fcntl::{self, open, readlink}; -use nix::fcntl::OFlag; +use nix::fcntl::{fcntl, FcntlArg, FdFlag, OFlag}; use nix::unistd::*; use nix::unistd::ForkResult::*; #[cfg(not(target_os = "redox"))] @@ -10,25 +10,27 @@ use nix::sys::stat::{self, Mode, SFlag}; #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] use nix::pty::{posix_openpt, grantpt, unlockpt, ptsname}; use nix::errno::Errno; -use std::env; -#[cfg(not(any(target_os = "fuchsia", target_os = "redox")))] +#[cfg(not(target_os = "redox"))] +use nix::Error; +use std::{env, iter}; +#[cfg(not(target_os = "redox"))] use std::ffi::CString; #[cfg(not(target_os = "redox"))] use std::fs::DirBuilder; use std::fs::{self, File}; use std::io::Write; use std::os::unix::prelude::*; -#[cfg(not(any(target_os = "fuchsia", target_os = "redox")))] +#[cfg(not(target_os = "redox"))] use std::path::Path; use tempfile::{tempdir, tempfile}; -use libc::{_exit, mode_t, off_t}; +use libc::{_exit, off_t}; use crate::*; #[test] #[cfg(not(any(target_os = "netbsd")))] fn test_fork_and_waitpid() { - let _m = crate::FORK_MTX.lock(); + let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); // Safe: Child only calls `_exit`, which is signal-safe match unsafe{fork()}.expect("Error: Fork Failed") { @@ -56,7 +58,7 @@ fn test_fork_and_waitpid() { #[test] fn test_wait() { // Grab FORK_MTX so wait doesn't reap a different test's child process - let _m = crate::FORK_MTX.lock(); + let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); // Safe: Child only calls `_exit`, which is signal-safe match unsafe{fork()}.expect("Error: Fork Failed") { @@ -100,7 +102,7 @@ fn test_mkfifo() { mkfifo(&mkfifo_fifo, Mode::S_IRUSR).unwrap(); let stats = stat::stat(&mkfifo_fifo).unwrap(); - let typ = stat::SFlag::from_bits_truncate(stats.st_mode as mode_t); + let typ = stat::SFlag::from_bits_truncate(stats.st_mode); assert!(typ == SFlag::S_IFIFO); } @@ -116,7 +118,7 @@ fn test_mkfifo_directory() { target_os = "macos", target_os = "ios", target_os = "android", target_os = "redox")))] fn test_mkfifoat_none() { - let _m = crate::CWD_LOCK.read(); + let _m = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); let tempdir = tempdir().unwrap(); let mkfifoat_fifo = tempdir.path().join("mkfifoat_fifo"); @@ -133,8 +135,6 @@ fn test_mkfifoat_none() { target_os = "macos", target_os = "ios", target_os = "android", target_os = "redox")))] fn test_mkfifoat() { - use nix::fcntl; - let tempdir = tempdir().unwrap(); let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); let mkfifoat_name = "mkfifoat_name"; @@ -151,10 +151,10 @@ fn test_mkfifoat() { target_os = "macos", target_os = "ios", target_os = "android", target_os = "redox")))] fn test_mkfifoat_directory_none() { - let _m = crate::CWD_LOCK.read(); + let _m = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); // mkfifoat should fail if a directory is given - assert!(mkfifoat(None, &env::temp_dir(), Mode::S_IRUSR).is_err()); + assert!(!mkfifoat(None, &env::temp_dir(), Mode::S_IRUSR).is_ok()); } #[test] @@ -168,7 +168,7 @@ fn test_mkfifoat_directory() { let mkfifoat_dir = "mkfifoat_dir"; stat::mkdirat(dirfd, mkfifoat_dir, Mode::S_IRUSR).unwrap(); - assert!(mkfifoat(Some(dirfd), mkfifoat_dir, Mode::S_IRUSR).is_err()); + assert!(!mkfifoat(Some(dirfd), mkfifoat_dir, Mode::S_IRUSR).is_ok()); } #[test] @@ -206,7 +206,7 @@ fn test_setgroups() { // Skip this test when not run as root as `setgroups()` requires root. skip_if_not_root!("test_setgroups"); - let _m = crate::GROUPS_MTX.lock(); + let _m = crate::GROUPS_MTX.lock().expect("Mutex got poisoned by another test"); // Save the existing groups let old_groups = getgroups().unwrap(); @@ -224,17 +224,13 @@ 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", - target_os = "fuchsia", - target_os = "illumos")))] +#[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. skip_if_not_root!("test_initgroups"); - let _m = crate::GROUPS_MTX.lock(); + let _m = crate::GROUPS_MTX.lock().expect("Mutex got poisoned by another test"); // Save the existing groups let old_groups = getgroups().unwrap(); @@ -258,7 +254,7 @@ fn test_initgroups() { setgroups(&old_groups).unwrap(); } -#[cfg(not(any(target_os = "fuchsia", target_os = "redox")))] +#[cfg(not(target_os = "redox"))] macro_rules! execve_test_factory( ($test_name:ident, $syscall:ident, $exe: expr $(, $pathname:expr, $flags:expr)*) => ( @@ -304,7 +300,7 @@ macro_rules! execve_test_factory( skip_if_seccomp!($test_name); } - let m = crate::FORK_MTX.lock(); + let m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); // The `exec`d process will write to `writer`, and we'll read that // data from `reader`. let (reader, writer) = pipe().unwrap(); @@ -370,12 +366,10 @@ cfg_if!{ 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", - target_os = "illumos", target_os = "ios", target_os = "macos", target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] { + target_os = "openbsd"))] { execve_test_factory!(test_execve, execve, CString::new("/bin/sh").unwrap().as_c_str()); // No fexecve() on DragonFly, ios, macos, NetBSD, OpenBSD. // @@ -441,9 +435,9 @@ fn test_getcwd() { // kicks in. Note: One path cannot be longer than 255 bytes // (NAME_MAX) whole path cannot be longer than PATH_MAX (usually // 4096 on linux, 1024 on macos) - let mut inner_tmp_dir = tmpdir_path; + let mut inner_tmp_dir = tmpdir_path.to_path_buf(); for _ in 0..5 { - let newdir = "a".repeat(100); + let newdir = iter::repeat("a").take(100).collect::<String>(); inner_tmp_dir.push(newdir); assert!(mkdir(inner_tmp_dir.as_path(), Mode::S_IRWXU).is_ok()); } @@ -549,7 +543,7 @@ cfg_if!{ if #[cfg(any(target_os = "android", target_os = "linux"))] { macro_rules! require_acct{ () => { - require_capability!("test_acct", CAP_SYS_PACCT); + require_capability!(CAP_SYS_PACCT); } } } else if #[cfg(target_os = "freebsd")] { @@ -575,7 +569,7 @@ fn test_acct() { use std::process::Command; use std::{thread, time}; - let _m = crate::FORK_MTX.lock(); + let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); require_acct!(); let file = NamedTempFile::new().unwrap(); @@ -624,34 +618,15 @@ fn test_sysconf_unsupported() { assert!(open_max.expect("sysconf failed").is_none()) } - -#[cfg(any(target_os = "android", target_os = "linux"))] -#[test] -fn test_getresuid() { - let resuids = getresuid().unwrap(); - assert!(resuids.real.as_raw() != libc::uid_t::max_value()); - assert!(resuids.effective.as_raw() != libc::uid_t::max_value()); - assert!(resuids.saved.as_raw() != libc::uid_t::max_value()); -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -#[test] -fn test_getresgid() { - let resgids = getresgid().unwrap(); - assert!(resgids.real.as_raw() != libc::gid_t::max_value()); - assert!(resgids.effective.as_raw() != libc::gid_t::max_value()); - assert!(resgids.saved.as_raw() != libc::gid_t::max_value()); -} - // Test that we can create a pair of pipes. No need to verify that they pass // data; that's the domain of the OS, not nix. #[test] fn test_pipe() { let (fd0, fd1) = pipe().unwrap(); - let m0 = stat::SFlag::from_bits_truncate(stat::fstat(fd0).unwrap().st_mode as mode_t); + let m0 = stat::SFlag::from_bits_truncate(stat::fstat(fd0).unwrap().st_mode); // S_IFIFO means it's a pipe assert_eq!(m0, SFlag::S_IFIFO); - let m1 = stat::SFlag::from_bits_truncate(stat::fstat(fd1).unwrap().st_mode as mode_t); + let m1 = stat::SFlag::from_bits_truncate(stat::fstat(fd1).unwrap().st_mode); assert_eq!(m1, SFlag::S_IFIFO); } @@ -661,16 +636,12 @@ fn test_pipe() { target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", - target_os = "illumos", target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_os = "redox", - target_os = "solaris"))] + target_os = "redox"))] #[test] fn test_pipe2() { - use nix::fcntl::{fcntl, FcntlArg, FdFlag}; - let (fd0, fd1) = pipe2(OFlag::O_CLOEXEC).unwrap(); let f0 = FdFlag::from_bits_truncate(fcntl(fd0, FcntlArg::F_GETFD).unwrap()); assert!(f0.contains(FdFlag::FD_CLOEXEC)); @@ -735,7 +706,7 @@ fn test_alarm() { }; // Maybe other tests that fork interfere with this one? - let _m = crate::SIGNAL_MTX.lock(); + let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); let handler = SigHandler::Handler(alarm_signal_handler); let signal_action = SigAction::new(handler, SaFlags::SA_RESTART, SigSet::empty()); @@ -750,7 +721,7 @@ fn test_alarm() { // Overwriting an alarm should return the old alarm. assert_eq!(alarm::set(1), Some(60)); - // We should be woken up after 1 second by the alarm, so we'll sleep for 3 + // We should be woken up after 1 second by the alarm, so we'll sleep for 2 // seconds to be sure. let starttime = Instant::now(); loop { @@ -773,7 +744,7 @@ fn test_alarm() { #[test] #[cfg(not(target_os = "redox"))] fn test_canceling_alarm() { - let _m = crate::SIGNAL_MTX.lock(); + let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); assert_eq!(alarm::cancel(), None); @@ -784,7 +755,7 @@ fn test_canceling_alarm() { #[test] #[cfg(not(target_os = "redox"))] fn test_symlinkat() { - let _m = crate::CWD_LOCK.read(); + let _m = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); let tempdir = tempdir().unwrap(); @@ -883,7 +854,7 @@ fn test_linkat_newdirfd_none() { #[test] #[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))] fn test_linkat_no_follow_symlink() { - let _m = crate::CWD_LOCK.read(); + let _m = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); let tempdir = tempdir().unwrap(); let oldfilename = "foo.txt"; @@ -920,7 +891,7 @@ fn test_linkat_no_follow_symlink() { #[test] #[cfg(not(target_os = "redox"))] fn test_linkat_follow_symlink() { - let _m = crate::CWD_LOCK.read(); + let _m = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); let tempdir = tempdir().unwrap(); let oldfilename = "foo.txt"; @@ -947,9 +918,7 @@ fn test_linkat_follow_symlink() { let newfilestat = stat::stat(&newfilepath).unwrap(); // Check the file type of the new link - assert_eq!((stat::SFlag::from_bits_truncate(newfilestat.st_mode as mode_t) & SFlag::S_IFMT), - SFlag::S_IFREG - ); + assert!((stat::SFlag::from_bits_truncate(newfilestat.st_mode) & SFlag::S_IFMT) == SFlag::S_IFREG); // Check the number of hard links to the original file assert_eq!(newfilestat.st_nlink, 2); @@ -970,7 +939,7 @@ fn test_unlinkat_dir_noremovedir() { // Attempt unlink dir at relative path without proper flag let err_result = unlinkat(Some(dirfd), dirname, UnlinkatFlags::NoRemoveDir).unwrap_err(); - assert!(err_result == Errno::EISDIR || err_result == Errno::EPERM); + assert!(err_result == Error::Sys(Errno::EISDIR) || err_result == Error::Sys(Errno::EPERM)); } #[test] @@ -1013,7 +982,7 @@ fn test_unlinkat_file() { fn test_access_not_existing() { let tempdir = tempdir().unwrap(); let dir = tempdir.path().join("does_not_exist.txt"); - assert_eq!(access(&dir, AccessFlags::F_OK).err().unwrap(), + assert_eq!(access(&dir, AccessFlags::F_OK).err().unwrap().as_errno().unwrap(), Errno::ENOENT); } @@ -1025,22 +994,13 @@ fn test_access_file_exists() { assert!(access(&path, AccessFlags::R_OK | AccessFlags::W_OK).is_ok()); } -#[cfg(not(target_os = "redox"))] -#[test] -fn test_user_into_passwd() { - // get the UID of the "nobody" user - let nobody = User::from_name("nobody").unwrap().unwrap(); - let pwd: libc::passwd = nobody.into(); - let _: User = (&pwd).into(); -} - /// Tests setting the filesystem UID with `setfsuid`. #[cfg(any(target_os = "linux", target_os = "android"))] #[test] fn test_setfsuid() { use std::os::unix::fs::PermissionsExt; use std::{fs, io, thread}; - require_capability!("test_setfsuid", CAP_SETUID); + require_capability!(CAP_SETUID); // get the UID of the "nobody" user let nobody = User::from_name("nobody").unwrap().unwrap(); @@ -1051,7 +1011,7 @@ fn test_setfsuid() { dbg!(&temp_path); let temp_path_2 = (&temp_path).to_path_buf(); let mut permissions = fs::metadata(&temp_path).unwrap().permissions(); - permissions.set_mode(0o640); + permissions.set_mode(640); // spawn a new thread where to test setfsuid thread::spawn(move || { @@ -1101,13 +1061,13 @@ fn test_ttyname() { fn test_ttyname_not_pty() { let fd = File::open("/dev/zero").unwrap(); assert!(fd.as_raw_fd() > 0); - assert_eq!(ttyname(fd.as_raw_fd()), Err(Errno::ENOTTY)); + assert_eq!(ttyname(fd.as_raw_fd()), Err(Error::Sys(Errno::ENOTTY))); } #[test] #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] fn test_ttyname_invalid_fd() { - assert_eq!(ttyname(-1), Err(Errno::EBADF)); + assert_eq!(ttyname(-1), Err(Error::Sys(Errno::EBADF))); } #[test] |