mirror of
https://github.com/uutils/coreutils
synced 2024-11-17 02:08:09 +00:00
change ~ remove (now unneeded) vendored nix-v0.23.1-patched
This commit is contained in:
parent
774e72551b
commit
d22f3e239c
112 changed files with 0 additions and 34875 deletions
274
vendor/nix-v0.23.1-patched/.cirrus.yml
vendored
274
vendor/nix-v0.23.1-patched/.cirrus.yml
vendored
|
@ -1,274 +0,0 @@
|
|||
cargo_cache:
|
||||
folder: $CARGO_HOME/registry
|
||||
fingerprint_script: cat Cargo.lock || echo ""
|
||||
|
||||
env:
|
||||
# Build by default; don't just check
|
||||
BUILD: build
|
||||
CLIPPYFLAGS: -D warnings
|
||||
RUSTFLAGS: -D warnings
|
||||
RUSTDOCFLAGS: -D warnings
|
||||
TOOL: cargo
|
||||
# The MSRV
|
||||
TOOLCHAIN: 1.46.0
|
||||
ZFLAGS:
|
||||
|
||||
# Tests that don't require executing the build binaries
|
||||
build: &BUILD
|
||||
build_script:
|
||||
- . $HOME/.cargo/env || true
|
||||
- $TOOL +$TOOLCHAIN $BUILD $ZFLAGS --target $TARGET --all-targets
|
||||
- $TOOL +$TOOLCHAIN doc $ZFLAGS --no-deps --target $TARGET
|
||||
- $TOOL +$TOOLCHAIN clippy $ZFLAGS --target $TARGET -- $CLIPPYFLAGS
|
||||
|
||||
# Tests that do require executing the binaries
|
||||
test: &TEST
|
||||
<< : *BUILD
|
||||
test_script:
|
||||
- . $HOME/.cargo/env || true
|
||||
- $TOOL +$TOOLCHAIN test --target $TARGET
|
||||
|
||||
# Test FreeBSD in a full VM. Test the i686 target too, in the
|
||||
# same VM. The binary will be built in 32-bit mode, but will execute on a
|
||||
# 64-bit kernel and in a 64-bit environment. Our tests don't execute any of
|
||||
# the system's binaries, so the environment shouldn't matter.
|
||||
task:
|
||||
name: FreeBSD amd64 & i686
|
||||
env:
|
||||
TARGET: x86_64-unknown-freebsd
|
||||
freebsd_instance:
|
||||
image: freebsd-12-2-release-amd64
|
||||
setup_script:
|
||||
- fetch https://sh.rustup.rs -o rustup.sh
|
||||
- sh rustup.sh -y --profile=minimal --default-toolchain $TOOLCHAIN
|
||||
- . $HOME/.cargo/env
|
||||
- rustup target add i686-unknown-freebsd
|
||||
- rustup component add --toolchain $TOOLCHAIN clippy
|
||||
<< : *TEST
|
||||
i386_test_script:
|
||||
- . $HOME/.cargo/env
|
||||
- cargo build --target i686-unknown-freebsd
|
||||
- cargo doc --no-deps --target i686-unknown-freebsd
|
||||
- cargo test --target i686-unknown-freebsd
|
||||
before_cache_script: rm -rf $CARGO_HOME/registry/index
|
||||
|
||||
# Test OSX in a full VM
|
||||
task:
|
||||
matrix:
|
||||
- name: OSX x86_64
|
||||
env:
|
||||
TARGET: x86_64-apple-darwin
|
||||
osx_instance:
|
||||
image: catalina-xcode
|
||||
setup_script:
|
||||
- curl --proto '=https' --tlsv1.2 -sSf -o rustup.sh https://sh.rustup.rs
|
||||
- sh rustup.sh -y --profile=minimal --default-toolchain $TOOLCHAIN
|
||||
- . $HOME/.cargo/env
|
||||
- rustup component add --toolchain $TOOLCHAIN clippy
|
||||
<< : *TEST
|
||||
before_cache_script: rm -rf $CARGO_HOME/registry/index
|
||||
|
||||
# Use cross for QEMU-based testing
|
||||
# cross needs to execute Docker, so we must use Cirrus's Docker Builder task.
|
||||
task:
|
||||
env:
|
||||
RUST_TEST_THREADS: 1 # QEMU works best with 1 thread
|
||||
HOME: /tmp/home
|
||||
PATH: $HOME/.cargo/bin:$PATH
|
||||
RUSTFLAGS: --cfg qemu -D warnings
|
||||
TOOL: cross
|
||||
matrix:
|
||||
- name: Linux arm gnueabi
|
||||
env:
|
||||
TARGET: arm-unknown-linux-gnueabi
|
||||
- name: Linux armv7 gnueabihf
|
||||
env:
|
||||
TARGET: armv7-unknown-linux-gnueabihf
|
||||
- name: Linux i686
|
||||
env:
|
||||
TARGET: i686-unknown-linux-gnu
|
||||
- name: Linux i686 musl
|
||||
env:
|
||||
TARGET: i686-unknown-linux-musl
|
||||
- name: Linux MIPS
|
||||
env:
|
||||
TARGET: mips-unknown-linux-gnu
|
||||
- name: Linux MIPS64
|
||||
env:
|
||||
TARGET: mips64-unknown-linux-gnuabi64
|
||||
- name: Linux MIPS64 el
|
||||
env:
|
||||
TARGET: mips64el-unknown-linux-gnuabi64
|
||||
- name: Linux mipsel
|
||||
env:
|
||||
TARGET: mipsel-unknown-linux-gnu
|
||||
- name: Linux powerpc64le
|
||||
env:
|
||||
TARGET: powerpc64le-unknown-linux-gnu
|
||||
compute_engine_instance:
|
||||
image_project: cirrus-images
|
||||
image: family/docker-builder
|
||||
platform: linux
|
||||
cpu: 1 # Since QEMU will only use 1 thread
|
||||
memory: 4G
|
||||
setup_script:
|
||||
- mkdir /tmp/home
|
||||
- curl --proto '=https' --tlsv1.2 -sSf -o rustup.sh https://sh.rustup.rs
|
||||
- sh rustup.sh -y --profile=minimal --default-toolchain $TOOLCHAIN
|
||||
- . $HOME/.cargo/env
|
||||
- cargo install cross
|
||||
<< : *TEST
|
||||
before_cache_script: rm -rf $CARGO_HOME/registry/index
|
||||
|
||||
# Tasks for Linux native builds
|
||||
task:
|
||||
matrix:
|
||||
- name: Rust Stable
|
||||
container:
|
||||
image: rust:latest
|
||||
env:
|
||||
TARGET: x86_64-unknown-linux-gnu
|
||||
TOOLCHAIN:
|
||||
- name: Linux aarch64
|
||||
arm_container:
|
||||
image: rust:1.46
|
||||
env:
|
||||
RUSTFLAGS: --cfg graviton -D warnings
|
||||
TARGET: aarch64-unknown-linux-gnu
|
||||
- name: Linux x86_64
|
||||
container:
|
||||
image: rust:1.46
|
||||
env:
|
||||
TARGET: x86_64-unknown-linux-gnu
|
||||
- name: Linux x86_64 musl
|
||||
container:
|
||||
image: rust:1.46
|
||||
env:
|
||||
TARGET: x86_64-unknown-linux-musl
|
||||
setup_script:
|
||||
- rustup target add $TARGET
|
||||
- rustup component add clippy
|
||||
<< : *TEST
|
||||
before_cache_script: rm -rf $CARGO_HOME/registry/index
|
||||
|
||||
# Tasks for cross-compiling, but no testing
|
||||
task:
|
||||
container:
|
||||
image: rust:1.46
|
||||
env:
|
||||
BUILD: check
|
||||
matrix:
|
||||
# Cross claims to support Android, but when it tries to run Nix's tests it
|
||||
# reports undefined symbol references.
|
||||
- name: Android aarch64
|
||||
env:
|
||||
TARGET: aarch64-linux-android
|
||||
- name: Android arm
|
||||
env:
|
||||
TARGET: arm-linux-androideabi
|
||||
- name: Android armv7
|
||||
env:
|
||||
TARGET: armv7-linux-androideabi
|
||||
- name: Android i686
|
||||
env:
|
||||
TARGET: i686-linux-android
|
||||
- name: Android x86_64
|
||||
env:
|
||||
TARGET: x86_64-linux-android
|
||||
- name: Linux arm-musleabi
|
||||
env:
|
||||
TARGET: arm-unknown-linux-musleabi
|
||||
- name: Fuchsia x86_64
|
||||
env:
|
||||
TARGET: x86_64-fuchsia
|
||||
- name: Illumos
|
||||
env:
|
||||
TARGET: x86_64-unknown-illumos
|
||||
# illumos toolchain isn't available via rustup until 1.50
|
||||
TOOLCHAIN: 1.50.0
|
||||
container:
|
||||
image: rust:1.50
|
||||
# Cross claims to support running tests on iOS, but it actually doesn't.
|
||||
# https://github.com/rust-embedded/cross/issues/535
|
||||
- name: iOS aarch64
|
||||
env:
|
||||
TARGET: aarch64-apple-ios
|
||||
# Rustup only supports cross-building from arbitrary hosts for iOS at
|
||||
# 1.49.0 and above. Below that it's possible to cross-build from an OSX
|
||||
# host, but OSX VMs are more expensive than Linux VMs.
|
||||
TOOLCHAIN: 1.49.0
|
||||
- name: iOS x86_64
|
||||
env:
|
||||
TARGET: x86_64-apple-ios
|
||||
TOOLCHAIN: 1.49.0
|
||||
# Cross testing on powerpc fails with "undefined reference to renameat2".
|
||||
# Perhaps cross is using too-old a version?
|
||||
- name: Linux powerpc
|
||||
env:
|
||||
TARGET: powerpc-unknown-linux-gnu
|
||||
# Cross claims to support Linux powerpc64, but it really doesn't.
|
||||
# https://github.com/rust-embedded/cross/issues/441
|
||||
- name: Linux powerpc64
|
||||
env:
|
||||
TARGET: powerpc64-unknown-linux-gnu
|
||||
- name: Linux s390x
|
||||
env:
|
||||
TARGET: s390x-unknown-linux-gnu
|
||||
- name: Linux x32
|
||||
env:
|
||||
TARGET: x86_64-unknown-linux-gnux32
|
||||
- name: NetBSD x86_64
|
||||
env:
|
||||
TARGET: x86_64-unknown-netbsd
|
||||
- name: Redox x86_64
|
||||
env:
|
||||
TARGET: x86_64-unknown-redox
|
||||
# Redox requires a nightly compiler.
|
||||
# If stuff breaks, change nightly to the date in the toolchain_*
|
||||
# directory at https://static.redox-os.org
|
||||
TOOLCHAIN: nightly-2020-08-04
|
||||
setup_script:
|
||||
- rustup target add $TARGET
|
||||
- rustup toolchain install $TOOLCHAIN --profile minimal --target $TARGET
|
||||
- rustup component add --toolchain $TOOLCHAIN clippy
|
||||
<< : *BUILD
|
||||
before_cache_script: rm -rf $CARGO_HOME/registry/index
|
||||
|
||||
# Rust Tier 3 targets can't use Rustup
|
||||
task:
|
||||
container:
|
||||
image: rustlang/rust:nightly
|
||||
env:
|
||||
BUILD: check
|
||||
# Must allow here rather than in lib.rs because this lint doesn't exist
|
||||
# prior to Rust 1.57.0
|
||||
# https://github.com/rust-lang/rust-clippy/issues/7718
|
||||
CLIPPYFLAGS: -D warnings -A clippy::if_then_panic
|
||||
TOOLCHAIN: nightly
|
||||
ZFLAGS: -Zbuild-std
|
||||
matrix:
|
||||
- name: DragonFly BSD x86_64
|
||||
env:
|
||||
TARGET: x86_64-unknown-dragonfly
|
||||
- name: OpenBSD x86_64
|
||||
env:
|
||||
TARGET: x86_64-unknown-openbsd
|
||||
setup_script:
|
||||
- rustup component add rust-src
|
||||
<< : *BUILD
|
||||
before_cache_script: rm -rf $CARGO_HOME/registry/index
|
||||
|
||||
# Test that we can build with the lowest version of all dependencies.
|
||||
# "cargo test" doesn't work because some of our dev-dependencies, like
|
||||
# rand, can't build with their own minimal dependencies.
|
||||
task:
|
||||
name: Minver
|
||||
env:
|
||||
TOOLCHAIN: nightly
|
||||
container:
|
||||
image: rustlang/rust:nightly
|
||||
setup_script:
|
||||
- cargo update -Zminimal-versions
|
||||
script:
|
||||
- cargo check
|
||||
before_cache_script: rm -rf $CARGO_HOME/registry/index
|
1
vendor/nix-v0.23.1-patched/.gitattributes
vendored
1
vendor/nix-v0.23.1-patched/.gitattributes
vendored
|
@ -1 +0,0 @@
|
|||
/CHANGELOG.md merge=union
|
10
vendor/nix-v0.23.1-patched/.gitignore
vendored
10
vendor/nix-v0.23.1-patched/.gitignore
vendored
|
@ -1,10 +0,0 @@
|
|||
syntax: glob
|
||||
Cargo.lock
|
||||
target
|
||||
*.diff
|
||||
*.rej
|
||||
*.orig
|
||||
.*.swn
|
||||
.*.swo
|
||||
.*.swp
|
||||
*.a
|
1227
vendor/nix-v0.23.1-patched/CHANGELOG.md
vendored
1227
vendor/nix-v0.23.1-patched/CHANGELOG.md
vendored
File diff suppressed because it is too large
Load diff
114
vendor/nix-v0.23.1-patched/CONTRIBUTING.md
vendored
114
vendor/nix-v0.23.1-patched/CONTRIBUTING.md
vendored
|
@ -1,114 +0,0 @@
|
|||
# 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
|
86
vendor/nix-v0.23.1-patched/CONVENTIONS.md
vendored
86
vendor/nix-v0.23.1-patched/CONVENTIONS.md
vendored
|
@ -1,86 +0,0 @@
|
|||
# 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
|
74
vendor/nix-v0.23.1-patched/Cargo.toml
vendored
74
vendor/nix-v0.23.1-patched/Cargo.toml
vendored
|
@ -1,74 +0,0 @@
|
|||
[package]
|
||||
name = "nix"
|
||||
description = "Rust friendly bindings to *nix APIs"
|
||||
edition = "2018"
|
||||
version = "0.23.1"
|
||||
authors = ["The nix-rust Project Developers"]
|
||||
repository = "https://github.com/nix-rust/nix"
|
||||
license = "MIT"
|
||||
categories = ["os::unix-apis"]
|
||||
include = ["src/**/*", "LICENSE", "README.md", "CHANGELOG.md"]
|
||||
|
||||
[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"
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
libc = { version = "0.2.102", features = [ "extra_traits" ] }
|
||||
bitflags = "1.3.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"
|
||||
lazy_static = "1.2"
|
||||
rand = "0.8"
|
||||
tempfile = "3.2.0"
|
||||
semver = "1.0.0"
|
||||
|
||||
[target.'cfg(any(target_os = "android", target_os = "linux"))'.dev-dependencies]
|
||||
caps = "0.5.1"
|
||||
|
||||
[target.'cfg(target_os = "freebsd")'.dev-dependencies]
|
||||
sysctl = "0.1"
|
||||
|
||||
[[test]]
|
||||
name = "test"
|
||||
path = "test/test.rs"
|
||||
|
||||
[[test]]
|
||||
name = "test-aio-drop"
|
||||
path = "test/sys/test_aio_drop.rs"
|
||||
|
||||
[[test]]
|
||||
name = "test-clearenv"
|
||||
path = "test/test_clearenv.rs"
|
||||
|
||||
[[test]]
|
||||
name = "test-lio-listio-resubmit"
|
||||
path = "test/sys/test_lio_listio_resubmit.rs"
|
||||
|
||||
[[test]]
|
||||
name = "test-mount"
|
||||
path = "test/test_mount.rs"
|
||||
harness = false
|
||||
|
||||
[[test]]
|
||||
name = "test-ptymaster-drop"
|
||||
path = "test/test_ptymaster_drop.rs"
|
5
vendor/nix-v0.23.1-patched/Cross.toml
vendored
5
vendor/nix-v0.23.1-patched/Cross.toml
vendored
|
@ -1,5 +0,0 @@
|
|||
[build.env]
|
||||
passthrough = [
|
||||
"RUSTFLAGS",
|
||||
"RUST_TEST_THREADS"
|
||||
]
|
21
vendor/nix-v0.23.1-patched/LICENSE
vendored
21
vendor/nix-v0.23.1-patched/LICENSE
vendored
|
@ -1,21 +0,0 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Carl Lerche + nix-rust Authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
102
vendor/nix-v0.23.1-patched/README.md
vendored
102
vendor/nix-v0.23.1-patched/README.md
vendored
|
@ -1,102 +0,0 @@
|
|||
# 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)
|
||||
|
||||
[Documentation (Releases)](https://docs.rs/nix/)
|
||||
|
||||
Nix seeks to provide friendly bindings to various *nix platform APIs (Linux, Darwin,
|
||||
...). The goal is to not provide a 100% unified interface, but to unify
|
||||
what can be while still providing platform specific APIs.
|
||||
|
||||
For many system APIs, Nix provides a safe alternative to the unsafe APIs
|
||||
exposed by the [libc crate](https://github.com/rust-lang/libc). This is done by
|
||||
wrapping the libc functionality with types/abstractions that enforce legal/safe
|
||||
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
|
||||
call:
|
||||
|
||||
```rust,ignore
|
||||
// libc api (unsafe, requires handling return code/errno)
|
||||
pub unsafe extern fn gethostname(name: *mut c_char, len: size_t) -> c_int;
|
||||
|
||||
// nix api (returns a nix::Result<CStr>)
|
||||
pub fn gethostname<'a>(buffer: &'a mut [u8]) -> Result<&'a CStr>;
|
||||
```
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
nix target support consists of two tiers. While nix attempts to support all
|
||||
platforms supported by [libc](https://github.com/rust-lang/libc), only some
|
||||
platforms are actively supported due to either technical or manpower
|
||||
limitations. Support for platforms is split into three tiers:
|
||||
|
||||
* Tier 1 - Builds and tests for this target are run in CI. Failures of either
|
||||
block the inclusion of new code.
|
||||
* Tier 2 - Builds for this target are run in CI. Failures during the build
|
||||
blocks the inclusion of new code. Tests may be run, but failures
|
||||
in tests don't block the inclusion of new code.
|
||||
* Tier 3 - Builds for this target are run in CI. Failures during the build
|
||||
*do not* block the inclusion of new code. Testing may be run, but
|
||||
failures in tests don't block the inclusion of new code.
|
||||
|
||||
The following targets are supported by `nix`:
|
||||
|
||||
Tier 1:
|
||||
* aarch64-unknown-linux-gnu
|
||||
* arm-unknown-linux-gnueabi
|
||||
* armv7-unknown-linux-gnueabihf
|
||||
* i686-unknown-freebsd
|
||||
* i686-unknown-linux-gnu
|
||||
* i686-unknown-linux-musl
|
||||
* mips-unknown-linux-gnu
|
||||
* mips64-unknown-linux-gnuabi64
|
||||
* mips64el-unknown-linux-gnuabi64
|
||||
* mipsel-unknown-linux-gnu
|
||||
* powerpc64le-unknown-linux-gnu
|
||||
* x86_64-apple-darwin
|
||||
* x86_64-unknown-freebsd
|
||||
* x86_64-unknown-linux-gnu
|
||||
* x86_64-unknown-linux-musl
|
||||
|
||||
Tier 2:
|
||||
* aarch64-apple-ios
|
||||
* aarch64-linux-android
|
||||
* arm-linux-androideabi
|
||||
* arm-unknown-linux-musleabi
|
||||
* armv7-linux-androideabi
|
||||
* i686-linux-android
|
||||
* powerpc-unknown-linux-gnu
|
||||
* s390x-unknown-linux-gnu
|
||||
* x86_64-apple-ios
|
||||
* x86_64-linux-android
|
||||
* x86_64-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
|
||||
|
||||
## Minimum Supported Rust Version (MSRV)
|
||||
|
||||
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.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are very welcome. Please See [CONTRIBUTING](CONTRIBUTING.md) for
|
||||
additional details.
|
||||
|
||||
Feel free to join us in [the nix-rust/nix](https://gitter.im/nix-rust/nix) channel on Gitter to
|
||||
discuss `nix` development.
|
||||
|
||||
## License
|
||||
|
||||
Nix is licensed under the MIT license. See [LICENSE](LICENSE) for more details.
|
18
vendor/nix-v0.23.1-patched/RELEASE_PROCEDURE.md
vendored
18
vendor/nix-v0.23.1-patched/RELEASE_PROCEDURE.md
vendored
|
@ -1,18 +0,0 @@
|
|||
This document lists the steps that lead to a successful release of the Nix
|
||||
library.
|
||||
|
||||
# Before Release
|
||||
|
||||
Nix uses [cargo release](https://github.com/crate-ci/cargo-release) to automate
|
||||
the release process. Based on changes since the last release, pick a new
|
||||
version number following semver conventions. For nix, a change that drops
|
||||
support for some Rust versions counts as a breaking change, and requires a
|
||||
major bump.
|
||||
|
||||
The release is prepared as follows:
|
||||
|
||||
- Ask for a new libc version if, necessary. It usually is. Then update the
|
||||
dependency in Cargo.toml accordingly.
|
||||
- Confirm that everything's ready for a release by running
|
||||
`cargo release --dry-run <patch|minor|major>`
|
||||
- Create the release with `cargo release <patch|minor|major>`
|
49
vendor/nix-v0.23.1-patched/bors.toml
vendored
49
vendor/nix-v0.23.1-patched/bors.toml
vendored
|
@ -1,49 +0,0 @@
|
|||
status = [
|
||||
"Android aarch64",
|
||||
"Android arm",
|
||||
"Android armv7",
|
||||
"Android i686",
|
||||
"Android x86_64",
|
||||
"DragonFly BSD x86_64",
|
||||
"FreeBSD amd64 & i686",
|
||||
"Fuchsia x86_64",
|
||||
"Linux MIPS",
|
||||
"Linux MIPS64 el",
|
||||
"Linux MIPS64",
|
||||
"Linux aarch64",
|
||||
"Linux arm gnueabi",
|
||||
"Linux arm-musleabi",
|
||||
"Linux armv7 gnueabihf",
|
||||
"Linux i686 musl",
|
||||
"Linux i686",
|
||||
"Linux mipsel",
|
||||
"Linux powerpc",
|
||||
"Linux powerpc64",
|
||||
"Linux powerpc64le",
|
||||
"Linux s390x",
|
||||
"Linux x32",
|
||||
"Linux x86_64 musl",
|
||||
"Linux x86_64",
|
||||
"Minver",
|
||||
"NetBSD x86_64",
|
||||
"OpenBSD x86_64",
|
||||
"OSX x86_64",
|
||||
"Redox x86_64",
|
||||
"Rust Stable",
|
||||
"iOS aarch64",
|
||||
"iOS x86_64",
|
||||
"Illumos",
|
||||
]
|
||||
|
||||
# Set bors's timeout to 1 hour
|
||||
#
|
||||
# bors's timeout should always be at least twice as long as the test suite
|
||||
# takes. This is to allow the CI provider to fast-fail a test; if one of the
|
||||
# builders immediately reports a failure, then bors will move on to the next
|
||||
# batch, leaving the slower builders to work through the already-doomed run and
|
||||
# the next one.
|
||||
#
|
||||
# At the time this was written, nix's test suite took about twenty minutes to
|
||||
# run. The timeout was raised to one hour to give nix room to grow and time
|
||||
# for delays on Cirrus's end.
|
||||
timeout_sec = 3600
|
5
vendor/nix-v0.23.1-patched/release.toml
vendored
5
vendor/nix-v0.23.1-patched/release.toml
vendored
|
@ -1,5 +0,0 @@
|
|||
no-dev-version = true
|
||||
pre-release-replacements = [
|
||||
{ file="CHANGELOG.md", search="Unreleased", replace="{{version}}" },
|
||||
{ file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}" }
|
||||
]
|
246
vendor/nix-v0.23.1-patched/src/dir.rs
vendored
246
vendor/nix-v0.23.1-patched/src/dir.rs
vendored
|
@ -1,246 +0,0 @@
|
|||
use crate::{Error, NixPath, Result};
|
||||
use crate::errno::Errno;
|
||||
use crate::fcntl::{self, OFlag};
|
||||
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
|
||||
use std::ptr;
|
||||
use std::ffi;
|
||||
use crate::sys;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use libc::{dirent64 as dirent, readdir64_r as readdir_r};
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
use libc::{dirent, readdir_r};
|
||||
|
||||
/// An open directory.
|
||||
///
|
||||
/// This is a lower-level interface than `std::fs::ReadDir`. Notable differences:
|
||||
/// * can be opened from a file descriptor (as returned by `openat`, perhaps before knowing
|
||||
/// if the path represents a file or directory).
|
||||
/// * implements `AsRawFd`, so it can be passed to `fstat`, `openat`, etc.
|
||||
/// The file descriptor continues to be owned by the `Dir`, so callers must not keep a `RawFd`
|
||||
/// after the `Dir` is dropped.
|
||||
/// * can be iterated through multiple times without closing and reopening the file
|
||||
/// descriptor. Each iteration rewinds when finished.
|
||||
/// * returns entries for `.` (current directory) and `..` (parent directory).
|
||||
/// * returns entries' names as a `CStr` (no allocation or conversion beyond whatever libc
|
||||
/// does).
|
||||
#[derive(Debug, Eq, Hash, PartialEq)]
|
||||
pub struct Dir(
|
||||
ptr::NonNull<libc::DIR>
|
||||
);
|
||||
|
||||
impl Dir {
|
||||
/// Opens the given path as with `fcntl::open`.
|
||||
pub fn open<P: ?Sized + NixPath>(path: &P, oflag: OFlag,
|
||||
mode: sys::stat::Mode) -> Result<Self> {
|
||||
let fd = fcntl::open(path, oflag, mode)?;
|
||||
Dir::from_fd(fd)
|
||||
}
|
||||
|
||||
/// Opens the given path as with `fcntl::openat`.
|
||||
pub fn openat<P: ?Sized + NixPath>(dirfd: RawFd, path: &P, oflag: OFlag,
|
||||
mode: sys::stat::Mode) -> Result<Self> {
|
||||
let fd = fcntl::openat(dirfd, path, oflag, mode)?;
|
||||
Dir::from_fd(fd)
|
||||
}
|
||||
|
||||
/// Converts from a descriptor-based object, closing the descriptor on success or failure.
|
||||
#[inline]
|
||||
pub fn from<F: IntoRawFd>(fd: F) -> Result<Self> {
|
||||
Dir::from_fd(fd.into_raw_fd())
|
||||
}
|
||||
|
||||
/// 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 e = Error::last();
|
||||
unsafe { libc::close(fd) };
|
||||
e
|
||||
})?;
|
||||
Ok(Dir(d))
|
||||
}
|
||||
|
||||
/// Returns an iterator of `Result<Entry>` which rewinds when finished.
|
||||
pub fn iter(&mut self) -> Iter {
|
||||
Iter(self)
|
||||
}
|
||||
}
|
||||
|
||||
// `Dir` is not `Sync`. With the current implementation, it could be, but according to
|
||||
// https://www.gnu.org/software/libc/manual/html_node/Reading_002fClosing-Directory.html,
|
||||
// future versions of POSIX are likely to obsolete `readdir_r` and specify that it's unsafe to
|
||||
// call `readdir` simultaneously from multiple threads.
|
||||
//
|
||||
// `Dir` is safe to pass from one thread to another, as it's not reference-counted.
|
||||
unsafe impl Send for Dir {}
|
||||
|
||||
impl AsRawFd for Dir {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
unsafe { libc::dirfd(self.0.as_ptr()) }
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
panic!("Closing an invalid file descriptor!");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn next(dir: &mut Dir) -> Option<Result<Entry>> {
|
||||
unsafe {
|
||||
// Note: POSIX specifies that portable applications should dynamically allocate a
|
||||
// buffer with room for a `d_name` field of size `pathconf(..., _PC_NAME_MAX)` plus 1
|
||||
// for the NUL byte. It doesn't look like the std library does this; it just uses
|
||||
// fixed-sized buffers (and libc's dirent seems to be sized so this is appropriate).
|
||||
// Probably fine here too then.
|
||||
let mut ent = std::mem::MaybeUninit::<dirent>::uninit();
|
||||
let mut result = ptr::null_mut();
|
||||
if let Err(e) = Errno::result(
|
||||
readdir_r(dir.0.as_ptr(), ent.as_mut_ptr(), &mut result))
|
||||
{
|
||||
return Some(Err(e));
|
||||
}
|
||||
if result.is_null() {
|
||||
return None;
|
||||
}
|
||||
assert_eq!(result, ent.as_mut_ptr());
|
||||
Some(Ok(Entry(ent.assume_init())))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, Hash, PartialEq)]
|
||||
pub struct Iter<'d>(&'d mut Dir);
|
||||
|
||||
impl<'d> Iterator for Iter<'d> {
|
||||
type Item = Result<Entry>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
next(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> Drop for Iter<'d> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { libc::rewinddir((self.0).0.as_ptr()) }
|
||||
}
|
||||
}
|
||||
|
||||
/// The return type of [Dir::into_iter]
|
||||
#[derive(Debug, Eq, Hash, PartialEq)]
|
||||
pub struct OwningIter(Dir);
|
||||
|
||||
impl Iterator for OwningIter {
|
||||
type Item = Result<Entry>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
next(&mut self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for Dir {
|
||||
type Item = Result<Entry>;
|
||||
type IntoIter = OwningIter;
|
||||
|
||||
/// Creates a owning iterator, that is, one that takes ownership of the
|
||||
/// `Dir`. The `Dir` cannot be used after calling this. This can be useful
|
||||
/// when you have a function that both creates a `Dir` instance and returns
|
||||
/// an `Iterator`.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```
|
||||
/// use nix::{dir::Dir, fcntl::OFlag, sys::stat::Mode};
|
||||
/// use std::{iter::Iterator, string::String};
|
||||
///
|
||||
/// fn ls_upper(dirname: &str) -> impl Iterator<Item=String> {
|
||||
/// let d = Dir::open(dirname, OFlag::O_DIRECTORY, Mode::S_IXUSR).unwrap();
|
||||
/// d.into_iter().map(|x| x.unwrap().file_name().as_ref().to_string_lossy().to_ascii_uppercase())
|
||||
/// }
|
||||
/// ```
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
OwningIter(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// A directory entry, similar to `std::fs::DirEntry`.
|
||||
///
|
||||
/// Note that unlike the std version, this may represent the `.` or `..` entries.
|
||||
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
|
||||
#[repr(transparent)]
|
||||
pub struct Entry(dirent);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum Type {
|
||||
Fifo,
|
||||
CharacterDevice,
|
||||
Directory,
|
||||
BlockDevice,
|
||||
File,
|
||||
Symlink,
|
||||
Socket,
|
||||
}
|
||||
|
||||
impl Entry {
|
||||
/// Returns the inode number (`d_ino`) of the underlying `dirent`.
|
||||
#[cfg(any(target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_os = "haiku",
|
||||
target_os = "illumos",
|
||||
target_os = "ios",
|
||||
target_os = "l4re",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "solaris"))]
|
||||
pub fn ino(&self) -> u64 {
|
||||
self.0.d_ino as u64
|
||||
}
|
||||
|
||||
/// Returns the inode number (`d_fileno`) of the underlying `dirent`.
|
||||
#[cfg(not(any(target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_os = "haiku",
|
||||
target_os = "illumos",
|
||||
target_os = "ios",
|
||||
target_os = "l4re",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "solaris")))]
|
||||
#[allow(clippy::useless_conversion)] // Not useless on all OSes
|
||||
pub fn ino(&self) -> u64 {
|
||||
u64::from(self.0.d_fileno)
|
||||
}
|
||||
|
||||
/// Returns the bare file name of this directory entry without any other leading path component.
|
||||
pub fn file_name(&self) -> &ffi::CStr {
|
||||
unsafe { ::std::ffi::CStr::from_ptr(self.0.d_name.as_ptr()) }
|
||||
}
|
||||
|
||||
/// Returns the type of this directory entry, if known.
|
||||
///
|
||||
/// See platform `readdir(3)` or `dirent(5)` manpage for when the file type is known;
|
||||
/// 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),
|
||||
libc::DT_DIR => Some(Type::Directory),
|
||||
libc::DT_BLK => Some(Type::BlockDevice),
|
||||
libc::DT_REG => Some(Type::File),
|
||||
libc::DT_LNK => Some(Type::Symlink),
|
||||
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
|
||||
}
|
||||
}
|
66
vendor/nix-v0.23.1-patched/src/env.rs
vendored
66
vendor/nix-v0.23.1-patched/src/env.rs
vendored
|
@ -1,66 +0,0 @@
|
|||
//! 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 {}
|
||||
|
||||
/// 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`].
|
||||
///
|
||||
/// On platforms where libc does not provide `clearenv()`, a fallback
|
||||
/// implementation will be used that iterates over all environment variables and
|
||||
/// removes them one-by-one.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is not threadsafe and can cause undefined behavior in
|
||||
/// combination with `std::env` or other program components that access the
|
||||
/// environment. See, for example, the discussion on `std::env::remove_var`; this
|
||||
/// function is a case of an "inherently unsafe non-threadsafe API" dealing with
|
||||
/// the environment.
|
||||
///
|
||||
/// The caller must ensure no other threads access the process environment while
|
||||
/// this function executes and that no raw pointers to an element of libc's
|
||||
/// `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> {
|
||||
let ret;
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "fuchsia",
|
||||
target_os = "wasi",
|
||||
target_env = "wasi",
|
||||
target_env = "uclibc",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten"))] {
|
||||
ret = libc::clearenv();
|
||||
} else {
|
||||
use std::env;
|
||||
for (name, _) in env::vars_os() {
|
||||
env::remove_var(name);
|
||||
}
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ret == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ClearEnvError)
|
||||
}
|
||||
}
|
2723
vendor/nix-v0.23.1-patched/src/errno.rs
vendored
2723
vendor/nix-v0.23.1-patched/src/errno.rs
vendored
File diff suppressed because it is too large
Load diff
696
vendor/nix-v0.23.1-patched/src/fcntl.rs
vendored
696
vendor/nix-v0.23.1-patched/src/fcntl.rs
vendored
|
@ -1,696 +0,0 @@
|
|||
use crate::errno::Errno;
|
||||
use libc::{self, c_char, c_int, c_uint, size_t, ssize_t};
|
||||
use std::ffi::OsString;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use std::os::raw;
|
||||
use std::os::unix::ffi::OsStringExt;
|
||||
use std::os::unix::io::RawFd;
|
||||
use crate::sys::stat::Mode;
|
||||
use crate::{NixPath, Result};
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
use std::ptr; // For splice and copy_file_range
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
use crate::sys::uio::IoVec; // For vmsplice
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
any(target_os = "wasi", target_env = "wasi"),
|
||||
target_env = "uclibc",
|
||||
target_os = "freebsd"
|
||||
))]
|
||||
pub use self::posix_fadvise::*;
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
libc_bitflags! {
|
||||
pub struct AtFlags: c_int {
|
||||
AT_REMOVEDIR;
|
||||
AT_SYMLINK_FOLLOW;
|
||||
AT_SYMLINK_NOFOLLOW;
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
AT_NO_AUTOMOUNT;
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
AT_EMPTY_PATH;
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
AT_EACCESS;
|
||||
}
|
||||
}
|
||||
|
||||
libc_bitflags!(
|
||||
/// Configuration options for opened files.
|
||||
pub struct OFlag: c_int {
|
||||
/// Mask for the access mode of the file.
|
||||
O_ACCMODE;
|
||||
/// Use alternate I/O semantics.
|
||||
#[cfg(target_os = "netbsd")]
|
||||
O_ALT_IO;
|
||||
/// Open the file in append-only mode.
|
||||
O_APPEND;
|
||||
/// Generate a signal when input or output becomes possible.
|
||||
#[cfg(not(any(target_os = "illumos", target_os = "solaris")))]
|
||||
O_ASYNC;
|
||||
/// Closes the file descriptor once an `execve` call is made.
|
||||
///
|
||||
/// Also sets the file offset to the beginning of the file.
|
||||
O_CLOEXEC;
|
||||
/// Create the file if it does not exist.
|
||||
O_CREAT;
|
||||
/// Try to minimize cache effects of the I/O for this file.
|
||||
#[cfg(any(target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd"))]
|
||||
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",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"))]
|
||||
O_DSYNC;
|
||||
/// Error out if a file was not created.
|
||||
O_EXCL;
|
||||
/// Open for execute only.
|
||||
#[cfg(target_os = "freebsd")]
|
||||
O_EXEC;
|
||||
/// Open with an exclusive file lock.
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "redox"))]
|
||||
O_EXLOCK;
|
||||
/// Same as `O_SYNC`.
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
all(target_os = "linux", not(target_env = "musl")),
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "redox"))]
|
||||
O_FSYNC;
|
||||
/// Allow files whose sizes can't be represented in an `off_t` to be opened.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
O_LARGEFILE;
|
||||
/// Do not update the file last access time during `read(2)`s.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
O_NOATIME;
|
||||
/// Don't attach the device as the process' controlling terminal.
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
O_NOCTTY;
|
||||
/// Same as `O_NONBLOCK`.
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
O_NDELAY;
|
||||
/// `open()` will fail if the given path is a symbolic link.
|
||||
O_NOFOLLOW;
|
||||
/// When possible, open the file in nonblocking mode.
|
||||
O_NONBLOCK;
|
||||
/// Don't deliver `SIGPIPE`.
|
||||
#[cfg(target_os = "netbsd")]
|
||||
O_NOSIGPIPE;
|
||||
/// Obtain a file descriptor for low-level access.
|
||||
///
|
||||
/// The file itself is not opened and other file operations will fail.
|
||||
#[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
|
||||
O_PATH;
|
||||
/// Only allow reading.
|
||||
///
|
||||
/// This should not be combined with `O_WRONLY` or `O_RDWR`.
|
||||
O_RDONLY;
|
||||
/// Allow both reading and writing.
|
||||
///
|
||||
/// This should not be combined with `O_WRONLY` or `O_RDONLY`.
|
||||
O_RDWR;
|
||||
/// Similar to `O_DSYNC` but applies to `read`s instead.
|
||||
#[cfg(any(target_os = "linux", target_os = "netbsd", target_os = "openbsd"))]
|
||||
O_RSYNC;
|
||||
/// Skip search permission checks.
|
||||
#[cfg(target_os = "netbsd")]
|
||||
O_SEARCH;
|
||||
/// Open with a shared file lock.
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "redox"))]
|
||||
O_SHLOCK;
|
||||
/// Implicitly follow each `write()` with an `fsync()`.
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
O_SYNC;
|
||||
/// Create an unnamed temporary file.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
O_TMPFILE;
|
||||
/// Truncate an existing regular file to 0 length if it allows writing.
|
||||
O_TRUNC;
|
||||
/// Restore default TTY attributes.
|
||||
#[cfg(target_os = "freebsd")]
|
||||
O_TTY_INIT;
|
||||
/// Only allow writing.
|
||||
///
|
||||
/// This should not be combined with `O_RDONLY` or `O_RDWR`.
|
||||
O_WRONLY;
|
||||
}
|
||||
);
|
||||
|
||||
// The conversion is not identical on all operating systems.
|
||||
#[allow(clippy::useless_conversion)]
|
||||
pub fn open<P: ?Sized + NixPath>(path: &P, oflag: OFlag, mode: Mode) -> Result<RawFd> {
|
||||
let fd = path.with_nix_path(|cstr| {
|
||||
unsafe { libc::open(cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) }
|
||||
})?;
|
||||
|
||||
Errno::result(fd)
|
||||
}
|
||||
|
||||
// The conversion is not identical on all operating systems.
|
||||
#[allow(clippy::useless_conversion)]
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
pub fn openat<P: ?Sized + NixPath>(
|
||||
dirfd: RawFd,
|
||||
path: &P,
|
||||
oflag: OFlag,
|
||||
mode: Mode,
|
||||
) -> Result<RawFd> {
|
||||
let fd = path.with_nix_path(|cstr| {
|
||||
unsafe { libc::openat(dirfd, cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) }
|
||||
})?;
|
||||
Errno::result(fd)
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
pub fn renameat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
|
||||
old_dirfd: Option<RawFd>,
|
||||
old_path: &P1,
|
||||
new_dirfd: Option<RawFd>,
|
||||
new_path: &P2,
|
||||
) -> Result<()> {
|
||||
let res = old_path.with_nix_path(|old_cstr| {
|
||||
new_path.with_nix_path(|new_cstr| unsafe {
|
||||
libc::renameat(
|
||||
at_rawfd(old_dirfd),
|
||||
old_cstr.as_ptr(),
|
||||
at_rawfd(new_dirfd),
|
||||
new_cstr.as_ptr(),
|
||||
)
|
||||
})
|
||||
})??;
|
||||
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();
|
||||
Ok(OsString::from_vec(v.to_vec()))
|
||||
}
|
||||
|
||||
fn readlink_maybe_at<P: ?Sized + NixPath>(
|
||||
dirfd: Option<RawFd>,
|
||||
path: &P,
|
||||
v: &mut Vec<u8>,
|
||||
) -> Result<libc::ssize_t> {
|
||||
path.with_nix_path(|cstr| unsafe {
|
||||
match dirfd {
|
||||
#[cfg(target_os = "redox")]
|
||||
Some(_) => unreachable!(),
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
Some(dirfd) => libc::readlinkat(
|
||||
dirfd,
|
||||
cstr.as_ptr(),
|
||||
v.as_mut_ptr() as *mut c_char,
|
||||
v.capacity() as size_t,
|
||||
),
|
||||
None => libc::readlink(
|
||||
cstr.as_ptr(),
|
||||
v.as_mut_ptr() as *mut c_char,
|
||||
v.capacity() as size_t,
|
||||
),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn inner_readlink<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P) -> Result<OsString> {
|
||||
let mut v = Vec::with_capacity(libc::PATH_MAX as usize);
|
||||
// simple case: result is strictly less than `PATH_MAX`
|
||||
let res = readlink_maybe_at(dirfd, path, &mut v)?;
|
||||
let len = Errno::result(res)?;
|
||||
debug_assert!(len >= 0);
|
||||
if (len as usize) < v.capacity() {
|
||||
return wrap_readlink_result(v, res);
|
||||
}
|
||||
// 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)
|
||||
.unwrap_or(0);
|
||||
let mut try_size = if reported_size > 0 {
|
||||
// Note: even if `lstat`'s apparently valid answer turns out to be
|
||||
// wrong, we will still read the full symlink no matter what.
|
||||
reported_size as usize + 1
|
||||
} else {
|
||||
// If lstat doesn't cooperate, or reports an error, be a little less
|
||||
// precise.
|
||||
(libc::PATH_MAX as usize).max(128) << 1
|
||||
};
|
||||
loop {
|
||||
v.reserve_exact(try_size);
|
||||
let res = readlink_maybe_at(dirfd, path, &mut v)?;
|
||||
let len = Errno::result(res)?;
|
||||
debug_assert!(len >= 0);
|
||||
if (len as usize) < v.capacity() {
|
||||
break wrap_readlink_result(v, res);
|
||||
} else {
|
||||
// Ugh! Still not big enough!
|
||||
match try_size.checked_shl(1) {
|
||||
Some(next_size) => try_size = next_size,
|
||||
// It's absurd that this would happen, but handle it sanely
|
||||
// anyway.
|
||||
None => break Err(Errno::ENAMETOOLONG),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn readlink<P: ?Sized + NixPath>(path: &P) -> Result<OsString> {
|
||||
inner_readlink(None, path)
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
pub fn readlinkat<P: ?Sized + NixPath>(dirfd: RawFd, path: &P) -> Result<OsString> {
|
||||
inner_readlink(Some(dirfd), path)
|
||||
}
|
||||
|
||||
/// Computes the raw fd consumed by a function of the form `*at`.
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
pub(crate) fn at_rawfd(fd: Option<RawFd>) -> raw::c_int {
|
||||
match fd {
|
||||
None => libc::AT_FDCWD,
|
||||
Some(fd) => fd,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
libc_bitflags!(
|
||||
/// Additional flags for file sealing, which allows for limiting operations on a file.
|
||||
pub struct SealFlag: c_int {
|
||||
/// Prevents further calls to `fcntl()` with `F_ADD_SEALS`.
|
||||
F_SEAL_SEAL;
|
||||
/// The file cannot be reduced in size.
|
||||
F_SEAL_SHRINK;
|
||||
/// The size of the file cannot be increased.
|
||||
F_SEAL_GROW;
|
||||
/// The file contents cannot be modified.
|
||||
F_SEAL_WRITE;
|
||||
}
|
||||
);
|
||||
|
||||
libc_bitflags!(
|
||||
/// Additional configuration flags for `fcntl`'s `F_SETFD`.
|
||||
pub struct FdFlag: c_int {
|
||||
/// The file descriptor will automatically be closed during a successful `execve(2)`.
|
||||
FD_CLOEXEC;
|
||||
}
|
||||
);
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[derive(Debug, Eq, Hash, PartialEq)]
|
||||
#[non_exhaustive]
|
||||
pub enum FcntlArg<'a> {
|
||||
F_DUPFD(RawFd),
|
||||
F_DUPFD_CLOEXEC(RawFd),
|
||||
F_GETFD,
|
||||
F_SETFD(FdFlag), // FD_FLAGS
|
||||
F_GETFL,
|
||||
F_SETFL(OFlag), // O_NONBLOCK
|
||||
F_SETLK(&'a libc::flock),
|
||||
F_SETLKW(&'a libc::flock),
|
||||
F_GETLK(&'a mut libc::flock),
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
F_OFD_SETLK(&'a libc::flock),
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
F_OFD_SETLKW(&'a libc::flock),
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
F_OFD_GETLK(&'a mut libc::flock),
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
F_ADD_SEALS(SealFlag),
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
F_GET_SEALS,
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
F_FULLFSYNC,
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
F_GETPIPE_SZ,
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
F_SETPIPE_SZ(c_int),
|
||||
// TODO: Rest of flags
|
||||
}
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
|
||||
#[non_exhaustive]
|
||||
pub enum FcntlArg {
|
||||
F_DUPFD(RawFd),
|
||||
F_DUPFD_CLOEXEC(RawFd),
|
||||
F_GETFD,
|
||||
F_SETFD(FdFlag), // FD_FLAGS
|
||||
F_GETFL,
|
||||
F_SETFL(OFlag), // O_NONBLOCK
|
||||
}
|
||||
pub use self::FcntlArg::*;
|
||||
|
||||
// TODO: Figure out how to handle value fcntl returns
|
||||
pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result<c_int> {
|
||||
let res = unsafe {
|
||||
match arg {
|
||||
F_DUPFD(rawfd) => libc::fcntl(fd, libc::F_DUPFD, rawfd),
|
||||
F_DUPFD_CLOEXEC(rawfd) => libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, rawfd),
|
||||
F_GETFD => libc::fcntl(fd, libc::F_GETFD),
|
||||
F_SETFD(flag) => libc::fcntl(fd, libc::F_SETFD, flag.bits()),
|
||||
F_GETFL => libc::fcntl(fd, libc::F_GETFL),
|
||||
F_SETFL(flag) => libc::fcntl(fd, libc::F_SETFL, flag.bits()),
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
F_SETLK(flock) => libc::fcntl(fd, libc::F_SETLK, flock),
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
F_SETLKW(flock) => libc::fcntl(fd, libc::F_SETLKW, flock),
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
F_GETLK(flock) => libc::fcntl(fd, libc::F_GETLK, flock),
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
F_OFD_SETLK(flock) => libc::fcntl(fd, libc::F_OFD_SETLK, flock),
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
F_OFD_SETLKW(flock) => libc::fcntl(fd, libc::F_OFD_SETLKW, flock),
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
F_OFD_GETLK(flock) => libc::fcntl(fd, libc::F_OFD_GETLK, flock),
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
F_ADD_SEALS(flag) => libc::fcntl(fd, libc::F_ADD_SEALS, flag.bits()),
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
F_GET_SEALS => libc::fcntl(fd, libc::F_GET_SEALS),
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
F_FULLFSYNC => libc::fcntl(fd, libc::F_FULLFSYNC),
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
F_GETPIPE_SZ => libc::fcntl(fd, libc::F_GETPIPE_SZ),
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
F_SETPIPE_SZ(size) => libc::fcntl(fd, libc::F_SETPIPE_SZ, size),
|
||||
}
|
||||
};
|
||||
|
||||
Errno::result(res)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
#[non_exhaustive]
|
||||
pub enum FlockArg {
|
||||
LockShared,
|
||||
LockExclusive,
|
||||
Unlock,
|
||||
LockSharedNonblock,
|
||||
LockExclusiveNonblock,
|
||||
UnlockNonblock,
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
pub fn flock(fd: RawFd, arg: FlockArg) -> Result<()> {
|
||||
use self::FlockArg::*;
|
||||
|
||||
let res = unsafe {
|
||||
match arg {
|
||||
LockShared => libc::flock(fd, libc::LOCK_SH),
|
||||
LockExclusive => libc::flock(fd, libc::LOCK_EX),
|
||||
Unlock => libc::flock(fd, libc::LOCK_UN),
|
||||
LockSharedNonblock => libc::flock(fd, libc::LOCK_SH | libc::LOCK_NB),
|
||||
LockExclusiveNonblock => libc::flock(fd, libc::LOCK_EX | libc::LOCK_NB),
|
||||
UnlockNonblock => libc::flock(fd, libc::LOCK_UN | libc::LOCK_NB),
|
||||
}
|
||||
};
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
libc_bitflags! {
|
||||
/// Additional flags to `splice` and friends.
|
||||
pub struct SpliceFFlags: c_uint {
|
||||
/// Request that pages be moved instead of copied.
|
||||
///
|
||||
/// Not applicable to `vmsplice`.
|
||||
SPLICE_F_MOVE;
|
||||
/// Do not block on I/O.
|
||||
SPLICE_F_NONBLOCK;
|
||||
/// Hint that more data will be coming in a subsequent splice.
|
||||
///
|
||||
/// Not applicable to `vmsplice`.
|
||||
SPLICE_F_MORE;
|
||||
/// Gift the user pages to the kernel.
|
||||
///
|
||||
/// Not applicable to `splice`.
|
||||
SPLICE_F_GIFT;
|
||||
}
|
||||
}
|
||||
|
||||
/// Copy a range of data from one file to another
|
||||
///
|
||||
/// The `copy_file_range` system call performs an in-kernel copy between
|
||||
/// file descriptors `fd_in` and `fd_out` without the additional cost of
|
||||
/// transferring data from the kernel to user space and then back into the
|
||||
/// kernel. It copies up to `len` bytes of data from file descriptor `fd_in` to
|
||||
/// file descriptor `fd_out`, overwriting any data that exists within the
|
||||
/// requested range of the target file.
|
||||
///
|
||||
/// If the `off_in` and/or `off_out` arguments are used, the values
|
||||
/// will be mutated to reflect the new position within the file after
|
||||
/// copying. If they are not used, the relevant filedescriptors will be seeked
|
||||
/// to the new position.
|
||||
///
|
||||
/// On successful completion the number of bytes actually copied will be
|
||||
/// returned.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
pub fn copy_file_range(
|
||||
fd_in: RawFd,
|
||||
off_in: Option<&mut libc::loff_t>,
|
||||
fd_out: RawFd,
|
||||
off_out: Option<&mut libc::loff_t>,
|
||||
len: usize,
|
||||
) -> Result<usize> {
|
||||
let off_in = off_in
|
||||
.map(|offset| offset as *mut libc::loff_t)
|
||||
.unwrap_or(ptr::null_mut());
|
||||
let off_out = off_out
|
||||
.map(|offset| offset as *mut libc::loff_t)
|
||||
.unwrap_or(ptr::null_mut());
|
||||
|
||||
let ret = unsafe {
|
||||
libc::syscall(
|
||||
libc::SYS_copy_file_range,
|
||||
fd_in,
|
||||
off_in,
|
||||
fd_out,
|
||||
off_out,
|
||||
len,
|
||||
0,
|
||||
)
|
||||
};
|
||||
Errno::result(ret).map(|r| r as usize)
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub fn splice(
|
||||
fd_in: RawFd,
|
||||
off_in: Option<&mut libc::loff_t>,
|
||||
fd_out: RawFd,
|
||||
off_out: Option<&mut libc::loff_t>,
|
||||
len: usize,
|
||||
flags: SpliceFFlags,
|
||||
) -> Result<usize> {
|
||||
let off_in = off_in
|
||||
.map(|offset| offset as *mut libc::loff_t)
|
||||
.unwrap_or(ptr::null_mut());
|
||||
let off_out = off_out
|
||||
.map(|offset| offset as *mut libc::loff_t)
|
||||
.unwrap_or(ptr::null_mut());
|
||||
|
||||
let ret = unsafe { libc::splice(fd_in, off_in, fd_out, off_out, len, flags.bits()) };
|
||||
Errno::result(ret).map(|r| r as usize)
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub fn tee(fd_in: RawFd, fd_out: RawFd, len: usize, flags: SpliceFFlags) -> Result<usize> {
|
||||
let ret = unsafe { libc::tee(fd_in, fd_out, len, flags.bits()) };
|
||||
Errno::result(ret).map(|r| r as usize)
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub fn vmsplice(fd: RawFd, iov: &[IoVec<&[u8]>], flags: SpliceFFlags) -> Result<usize> {
|
||||
let ret = unsafe {
|
||||
libc::vmsplice(
|
||||
fd,
|
||||
iov.as_ptr() as *const libc::iovec,
|
||||
iov.len(),
|
||||
flags.bits(),
|
||||
)
|
||||
};
|
||||
Errno::result(ret).map(|r| r as usize)
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux"))]
|
||||
libc_bitflags!(
|
||||
/// Mode argument flags for fallocate determining operation performed on a given range.
|
||||
pub struct FallocateFlags: c_int {
|
||||
/// File size is not changed.
|
||||
///
|
||||
/// offset + len can be greater than file size.
|
||||
FALLOC_FL_KEEP_SIZE;
|
||||
/// Deallocates space by creating a hole.
|
||||
///
|
||||
/// Must be ORed with FALLOC_FL_KEEP_SIZE. Byte range starts at offset and continues for len bytes.
|
||||
FALLOC_FL_PUNCH_HOLE;
|
||||
/// Removes byte range from a file without leaving a hole.
|
||||
///
|
||||
/// Byte range to collapse starts at offset and continues for len bytes.
|
||||
FALLOC_FL_COLLAPSE_RANGE;
|
||||
/// Zeroes space in specified byte range.
|
||||
///
|
||||
/// Byte range starts at offset and continues for len bytes.
|
||||
FALLOC_FL_ZERO_RANGE;
|
||||
/// Increases file space by inserting a hole within the file size.
|
||||
///
|
||||
/// Does not overwrite existing data. Hole starts at offset and continues for len bytes.
|
||||
FALLOC_FL_INSERT_RANGE;
|
||||
/// Shared file data extants are made private to the file.
|
||||
///
|
||||
/// Gaurantees that a subsequent write will not fail due to lack of space.
|
||||
FALLOC_FL_UNSHARE_RANGE;
|
||||
}
|
||||
);
|
||||
|
||||
/// Manipulates file space.
|
||||
///
|
||||
/// Allows the caller to directly manipulate the allocated disk space for the
|
||||
/// file referred to by fd.
|
||||
#[cfg(any(target_os = "linux"))]
|
||||
pub fn fallocate(
|
||||
fd: RawFd,
|
||||
mode: FallocateFlags,
|
||||
offset: libc::off_t,
|
||||
len: libc::off_t,
|
||||
) -> Result<()> {
|
||||
let res = unsafe { libc::fallocate(fd, mode.bits(), offset, len) };
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
any(target_os = "wasi", target_env = "wasi"),
|
||||
target_env = "uclibc",
|
||||
target_os = "freebsd"
|
||||
))]
|
||||
mod posix_fadvise {
|
||||
use crate::errno::Errno;
|
||||
use std::os::unix::io::RawFd;
|
||||
use crate::Result;
|
||||
|
||||
libc_enum! {
|
||||
#[repr(i32)]
|
||||
#[non_exhaustive]
|
||||
pub enum PosixFadviseAdvice {
|
||||
POSIX_FADV_NORMAL,
|
||||
POSIX_FADV_SEQUENTIAL,
|
||||
POSIX_FADV_RANDOM,
|
||||
POSIX_FADV_NOREUSE,
|
||||
POSIX_FADV_WILLNEED,
|
||||
POSIX_FADV_DONTNEED,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn posix_fadvise(
|
||||
fd: RawFd,
|
||||
offset: libc::off_t,
|
||||
len: libc::off_t,
|
||||
advice: PosixFadviseAdvice,
|
||||
) -> Result<()> {
|
||||
let res = unsafe { libc::posix_fadvise(fd, offset, len, advice as libc::c_int) };
|
||||
|
||||
if res == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Errno::from_i32(res))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
any(target_os = "wasi", target_env = "wasi"),
|
||||
target_os = "freebsd"
|
||||
))]
|
||||
pub fn posix_fallocate(fd: RawFd, offset: libc::off_t, len: libc::off_t) -> Result<()> {
|
||||
let res = unsafe { libc::posix_fallocate(fd, offset, len) };
|
||||
match Errno::result(res) {
|
||||
Err(err) => Err(err),
|
||||
Ok(0) => Ok(()),
|
||||
Ok(errno) => Err(Errno::from_i32(errno)),
|
||||
}
|
||||
}
|
121
vendor/nix-v0.23.1-patched/src/features.rs
vendored
121
vendor/nix-v0.23.1-patched/src/features.rs
vendored
|
@ -1,121 +0,0 @@
|
|||
//! Feature tests for OS functionality
|
||||
pub use self::os::*;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
mod os {
|
||||
use crate::sys::utsname::uname;
|
||||
|
||||
// Features:
|
||||
// * atomic cloexec on socket: 2.6.27
|
||||
// * pipe2: 2.6.27
|
||||
// * accept4: 2.6.28
|
||||
|
||||
static VERS_UNKNOWN: usize = 1;
|
||||
static VERS_2_6_18: usize = 2;
|
||||
static VERS_2_6_27: usize = 3;
|
||||
static VERS_2_6_28: usize = 4;
|
||||
static VERS_3: usize = 5;
|
||||
|
||||
#[inline]
|
||||
fn digit(dst: &mut usize, b: u8) {
|
||||
*dst *= 10;
|
||||
*dst += (b - b'0') as usize;
|
||||
}
|
||||
|
||||
fn parse_kernel_version() -> usize {
|
||||
let u = uname();
|
||||
|
||||
let mut curr: usize = 0;
|
||||
let mut major: usize = 0;
|
||||
let mut minor: usize = 0;
|
||||
let mut patch: usize = 0;
|
||||
|
||||
for b in u.release().bytes() {
|
||||
if curr >= 3 {
|
||||
break;
|
||||
}
|
||||
|
||||
match b {
|
||||
b'.' | b'-' => {
|
||||
curr += 1;
|
||||
}
|
||||
b'0'..=b'9' => {
|
||||
match curr {
|
||||
0 => digit(&mut major, b),
|
||||
1 => digit(&mut minor, b),
|
||||
_ => digit(&mut patch, b),
|
||||
}
|
||||
}
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
|
||||
if major >= 3 {
|
||||
VERS_3
|
||||
} else if major >= 2 {
|
||||
if minor >= 7 {
|
||||
VERS_UNKNOWN
|
||||
} else if minor >= 6 {
|
||||
if patch >= 28 {
|
||||
VERS_2_6_28
|
||||
} else if patch >= 27 {
|
||||
VERS_2_6_27
|
||||
} else {
|
||||
VERS_2_6_18
|
||||
}
|
||||
} else {
|
||||
VERS_UNKNOWN
|
||||
}
|
||||
} else {
|
||||
VERS_UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
fn kernel_version() -> usize {
|
||||
static mut KERNEL_VERS: usize = 0;
|
||||
|
||||
unsafe {
|
||||
if KERNEL_VERS == 0 {
|
||||
KERNEL_VERS = parse_kernel_version();
|
||||
}
|
||||
|
||||
KERNEL_VERS
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if the OS supports atomic close-on-exec for sockets
|
||||
pub fn socket_atomic_cloexec() -> bool {
|
||||
kernel_version() >= VERS_2_6_27
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_parsing_kernel_version() {
|
||||
assert!(kernel_version() > 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[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
|
||||
))]
|
||||
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 {
|
||||
false
|
||||
}
|
||||
}
|
147
vendor/nix-v0.23.1-patched/src/ifaddrs.rs
vendored
147
vendor/nix-v0.23.1-patched/src/ifaddrs.rs
vendored
|
@ -1,147 +0,0 @@
|
|||
//! Query network interface addresses
|
||||
//!
|
||||
//! Uses the Linux and/or BSD specific function `getifaddrs` to query the list
|
||||
//! of interfaces and their associated addresses.
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use std::ffi;
|
||||
use std::iter::Iterator;
|
||||
use std::mem;
|
||||
use std::option::Option;
|
||||
|
||||
use crate::{Result, Errno};
|
||||
use crate::sys::socket::SockAddr;
|
||||
use crate::net::if_::*;
|
||||
|
||||
/// Describes a single address for an interface as returned by `getifaddrs`.
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct InterfaceAddress {
|
||||
/// Name of the network interface
|
||||
pub interface_name: String,
|
||||
/// Flags as from `SIOCGIFFLAGS` ioctl
|
||||
pub flags: InterfaceFlags,
|
||||
/// Network address of this interface
|
||||
pub address: Option<SockAddr>,
|
||||
/// Netmask of this interface
|
||||
pub netmask: Option<SockAddr>,
|
||||
/// Broadcast address of this interface, if applicable
|
||||
pub broadcast: Option<SockAddr>,
|
||||
/// Point-to-point destination address
|
||||
pub destination: Option<SockAddr>,
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux"))] {
|
||||
fn get_ifu_from_sockaddr(info: &libc::ifaddrs) -> *const libc::sockaddr {
|
||||
info.ifa_ifu
|
||||
}
|
||||
} else {
|
||||
fn get_ifu_from_sockaddr(info: &libc::ifaddrs) -> *const libc::sockaddr {
|
||||
info.ifa_dstaddr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InterfaceAddress {
|
||||
/// Create an `InterfaceAddress` from the libc struct.
|
||||
fn from_libc_ifaddrs(info: &libc::ifaddrs) -> InterfaceAddress {
|
||||
let ifname = unsafe { ffi::CStr::from_ptr(info.ifa_name) };
|
||||
let address = unsafe { SockAddr::from_libc_sockaddr(info.ifa_addr) };
|
||||
let netmask = unsafe { SockAddr::from_libc_sockaddr(info.ifa_netmask) };
|
||||
let mut addr = InterfaceAddress {
|
||||
interface_name: ifname.to_string_lossy().to_string(),
|
||||
flags: InterfaceFlags::from_bits_truncate(info.ifa_flags as i32),
|
||||
address,
|
||||
netmask,
|
||||
broadcast: None,
|
||||
destination: None,
|
||||
};
|
||||
|
||||
let ifu = get_ifu_from_sockaddr(info);
|
||||
if addr.flags.contains(InterfaceFlags::IFF_POINTOPOINT) {
|
||||
addr.destination = unsafe { SockAddr::from_libc_sockaddr(ifu) };
|
||||
} else if addr.flags.contains(InterfaceFlags::IFF_BROADCAST) {
|
||||
addr.broadcast = unsafe { SockAddr::from_libc_sockaddr(ifu) };
|
||||
}
|
||||
|
||||
addr
|
||||
}
|
||||
}
|
||||
|
||||
/// Holds the results of `getifaddrs`.
|
||||
///
|
||||
/// Use the function `getifaddrs` to create this Iterator. Note that the
|
||||
/// actual list of interfaces can be iterated once and will be freed as
|
||||
/// soon as the Iterator goes out of scope.
|
||||
#[derive(Debug, Eq, Hash, PartialEq)]
|
||||
pub struct InterfaceAddressIterator {
|
||||
base: *mut libc::ifaddrs,
|
||||
next: *mut libc::ifaddrs,
|
||||
}
|
||||
|
||||
impl Drop for InterfaceAddressIterator {
|
||||
fn drop(&mut self) {
|
||||
unsafe { libc::freeifaddrs(self.base) };
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for InterfaceAddressIterator {
|
||||
type Item = InterfaceAddress;
|
||||
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
|
||||
match unsafe { self.next.as_ref() } {
|
||||
Some(ifaddr) => {
|
||||
self.next = ifaddr.ifa_next;
|
||||
Some(InterfaceAddress::from_libc_ifaddrs(ifaddr))
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get interface addresses using libc's `getifaddrs`
|
||||
///
|
||||
/// Note that the underlying implementation differs between OSes. Only the
|
||||
/// most common address families are supported by the nix crate (due to
|
||||
/// lack of time and complexity of testing). The address family is encoded
|
||||
/// in the specific variant of `SockAddr` returned for the fields `address`,
|
||||
/// `netmask`, `broadcast`, and `destination`. For any entry not supported,
|
||||
/// the returned list will contain a `None` entry.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// let addrs = nix::ifaddrs::getifaddrs().unwrap();
|
||||
/// for ifaddr in addrs {
|
||||
/// match ifaddr.address {
|
||||
/// Some(address) => {
|
||||
/// println!("interface {} address {}",
|
||||
/// ifaddr.interface_name, address);
|
||||
/// },
|
||||
/// None => {
|
||||
/// println!("interface {} with unsupported address family",
|
||||
/// ifaddr.interface_name);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub fn getifaddrs() -> Result<InterfaceAddressIterator> {
|
||||
let mut addrs = mem::MaybeUninit::<*mut libc::ifaddrs>::uninit();
|
||||
unsafe {
|
||||
Errno::result(libc::getifaddrs(addrs.as_mut_ptr())).map(|_| {
|
||||
InterfaceAddressIterator {
|
||||
base: addrs.assume_init(),
|
||||
next: addrs.assume_init(),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// Only checks if `getifaddrs` can be invoked without panicking.
|
||||
#[test]
|
||||
fn test_getifaddrs() {
|
||||
let _ = getifaddrs();
|
||||
}
|
||||
}
|
122
vendor/nix-v0.23.1-patched/src/kmod.rs
vendored
122
vendor/nix-v0.23.1-patched/src/kmod.rs
vendored
|
@ -1,122 +0,0 @@
|
|||
//! Load and unload kernel modules.
|
||||
//!
|
||||
//! For more details see
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
use crate::errno::Errno;
|
||||
use crate::Result;
|
||||
|
||||
/// Loads a kernel module from a buffer.
|
||||
///
|
||||
/// It loads an ELF image into kernel space,
|
||||
/// performs any necessary symbol relocations,
|
||||
/// initializes module parameters to values provided by the caller,
|
||||
/// and then runs the module's init function.
|
||||
///
|
||||
/// This function requires `CAP_SYS_MODULE` privilege.
|
||||
///
|
||||
/// The `module_image` argument points to a buffer containing the binary image
|
||||
/// to be loaded. The buffer should contain a valid ELF image
|
||||
/// built for the running kernel.
|
||||
///
|
||||
/// The `param_values` argument is a string containing space-delimited specifications
|
||||
/// of the values for module parameters.
|
||||
/// Each of the parameter specifications has the form:
|
||||
///
|
||||
/// `name[=value[,value...]]`
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::fs::File;
|
||||
/// use std::io::Read;
|
||||
/// use std::ffi::CString;
|
||||
/// use nix::kmod::init_module;
|
||||
///
|
||||
/// let mut f = File::open("mykernel.ko").unwrap();
|
||||
/// let mut contents: Vec<u8> = Vec::new();
|
||||
/// f.read_to_end(&mut contents).unwrap();
|
||||
/// 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.
|
||||
pub fn init_module(module_image: &[u8], param_values: &CStr) -> Result<()> {
|
||||
let res = unsafe {
|
||||
libc::syscall(
|
||||
libc::SYS_init_module,
|
||||
module_image.as_ptr(),
|
||||
module_image.len(),
|
||||
param_values.as_ptr(),
|
||||
)
|
||||
};
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
libc_bitflags!(
|
||||
/// Flags used by the `finit_module` function.
|
||||
pub struct ModuleInitFlags: libc::c_uint {
|
||||
/// Ignore symbol version hashes.
|
||||
MODULE_INIT_IGNORE_MODVERSIONS;
|
||||
/// Ignore kernel version magic.
|
||||
MODULE_INIT_IGNORE_VERMAGIC;
|
||||
}
|
||||
);
|
||||
|
||||
/// Loads a kernel module from a given file descriptor.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::fs::File;
|
||||
/// use std::ffi::CString;
|
||||
/// use nix::kmod::{finit_module, ModuleInitFlags};
|
||||
///
|
||||
/// let f = File::open("mymod.ko").unwrap();
|
||||
/// 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.
|
||||
pub fn finit_module<T: AsRawFd>(fd: &T, param_values: &CStr, flags: ModuleInitFlags) -> Result<()> {
|
||||
let res = unsafe {
|
||||
libc::syscall(
|
||||
libc::SYS_finit_module,
|
||||
fd.as_raw_fd(),
|
||||
param_values.as_ptr(),
|
||||
flags.bits(),
|
||||
)
|
||||
};
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
libc_bitflags!(
|
||||
/// Flags used by `delete_module`.
|
||||
///
|
||||
/// See [`man delete_module(2)`](https://man7.org/linux/man-pages/man2/delete_module.2.html)
|
||||
/// for a detailed description how these flags work.
|
||||
pub struct DeleteModuleFlags: libc::c_int {
|
||||
O_NONBLOCK;
|
||||
O_TRUNC;
|
||||
}
|
||||
);
|
||||
|
||||
/// Unloads the kernel module with the given name.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::ffi::CString;
|
||||
/// use nix::kmod::{delete_module, DeleteModuleFlags};
|
||||
///
|
||||
/// 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.
|
||||
pub fn delete_module(name: &CStr, flags: DeleteModuleFlags) -> Result<()> {
|
||||
let res = unsafe { libc::syscall(libc::SYS_delete_module, name.as_ptr(), flags.bits()) };
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
227
vendor/nix-v0.23.1-patched/src/lib.rs
vendored
227
vendor/nix-v0.23.1-patched/src/lib.rs
vendored
|
@ -1,227 +0,0 @@
|
|||
//! Rust friendly bindings to the various *nix system functions.
|
||||
//!
|
||||
//! Modules are structured according to the C header file that they would be
|
||||
//! defined in.
|
||||
#![crate_name = "nix"]
|
||||
#![cfg(unix)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![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;
|
||||
|
||||
// Private internal modules
|
||||
#[macro_use] mod macros;
|
||||
|
||||
// Public crates
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[allow(missing_docs)]
|
||||
pub mod dir;
|
||||
pub mod env;
|
||||
#[allow(missing_docs)]
|
||||
pub mod errno;
|
||||
pub mod features;
|
||||
#[allow(missing_docs)]
|
||||
pub mod fcntl;
|
||||
#[cfg(any(target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "illumos",
|
||||
target_os = "openbsd"))]
|
||||
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",
|
||||
target_os = "freebsd",
|
||||
target_os = "fushsia",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd"))]
|
||||
#[allow(missing_docs)]
|
||||
pub mod mqueue;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
pub mod net;
|
||||
pub mod poll;
|
||||
#[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;
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== Result / Error =====
|
||||
*
|
||||
*/
|
||||
|
||||
use libc::{c_char, PATH_MAX};
|
||||
|
||||
use std::{ptr, result};
|
||||
use std::ffi::{CStr, OsStr};
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use errno::Errno;
|
||||
|
||||
/// Nix Result Type
|
||||
pub type Result<T> = result::Result<T, Errno>;
|
||||
|
||||
/// Nix's main 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.
|
||||
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;
|
||||
}
|
||||
|
||||
impl NixPath for str {
|
||||
fn is_empty(&self) -> bool {
|
||||
NixPath::is_empty(OsStr::new(self))
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
NixPath::len(OsStr::new(self))
|
||||
}
|
||||
|
||||
fn with_nix_path<T, F>(&self, f: F) -> Result<T>
|
||||
where F: FnOnce(&CStr) -> T {
|
||||
OsStr::new(self).with_nix_path(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl NixPath for OsStr {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.as_bytes().is_empty()
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.as_bytes().len()
|
||||
}
|
||||
|
||||
fn with_nix_path<T, F>(&self, f: F) -> Result<T>
|
||||
where F: FnOnce(&CStr) -> T {
|
||||
self.as_bytes().with_nix_path(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl NixPath for CStr {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.to_bytes().is_empty()
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.to_bytes().len()
|
||||
}
|
||||
|
||||
fn with_nix_path<T, F>(&self, f: F) -> Result<T>
|
||||
where F: FnOnce(&CStr) -> T {
|
||||
// Equivalence with the [u8] impl.
|
||||
if self.len() >= PATH_MAX as usize {
|
||||
return Err(Errno::ENAMETOOLONG)
|
||||
}
|
||||
|
||||
Ok(f(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl NixPath for [u8] {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.is_empty()
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
|
||||
fn with_nix_path<T, F>(&self, f: F) -> Result<T>
|
||||
where F: FnOnce(&CStr) -> T {
|
||||
let mut buf = [0u8; PATH_MAX as usize];
|
||||
|
||||
if self.len() >= PATH_MAX as usize {
|
||||
return Err(Errno::ENAMETOOLONG)
|
||||
}
|
||||
|
||||
match self.iter().position(|b| *b == 0) {
|
||||
Some(_) => Err(Errno::EINVAL),
|
||||
None => {
|
||||
unsafe {
|
||||
// TODO: Replace with bytes::copy_memory. rust-lang/rust#24028
|
||||
ptr::copy_nonoverlapping(self.as_ptr(), buf.as_mut_ptr(), self.len());
|
||||
Ok(f(CStr::from_ptr(buf.as_ptr() as *const c_char)))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NixPath for Path {
|
||||
fn is_empty(&self) -> bool {
|
||||
NixPath::is_empty(self.as_os_str())
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
NixPath::len(self.as_os_str())
|
||||
}
|
||||
|
||||
fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
|
||||
self.as_os_str().with_nix_path(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl NixPath for PathBuf {
|
||||
fn is_empty(&self) -> bool {
|
||||
NixPath::is_empty(self.as_os_str())
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
NixPath::len(self.as_os_str())
|
||||
}
|
||||
|
||||
fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
|
||||
self.as_os_str().with_nix_path(f)
|
||||
}
|
||||
}
|
311
vendor/nix-v0.23.1-patched/src/macros.rs
vendored
311
vendor/nix-v0.23.1-patched/src/macros.rs
vendored
|
@ -1,311 +0,0 @@
|
|||
/// The `libc_bitflags!` macro helps with a common use case of defining a public bitflags type
|
||||
/// with values from the libc crate. It is used the same way as the `bitflags!` macro, except
|
||||
/// that only the name of the flag value has to be given.
|
||||
///
|
||||
/// The `libc` crate must be in scope with the name `libc`.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// libc_bitflags!{
|
||||
/// pub struct ProtFlags: libc::c_int {
|
||||
/// PROT_NONE;
|
||||
/// PROT_READ;
|
||||
/// /// PROT_WRITE enables write protect
|
||||
/// PROT_WRITE;
|
||||
/// PROT_EXEC;
|
||||
/// #[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
/// PROT_GROWSDOWN;
|
||||
/// #[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
/// PROT_GROWSUP;
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Example with casting, due to a mistake in libc. In this example, the
|
||||
/// various flags have different types, so we cast the broken ones to the right
|
||||
/// type.
|
||||
///
|
||||
/// ```
|
||||
/// libc_bitflags!{
|
||||
/// pub struct SaFlags: libc::c_ulong {
|
||||
/// SA_NOCLDSTOP as libc::c_ulong;
|
||||
/// SA_NOCLDWAIT;
|
||||
/// SA_NODEFER as libc::c_ulong;
|
||||
/// SA_ONSTACK;
|
||||
/// SA_RESETHAND as libc::c_ulong;
|
||||
/// SA_RESTART as libc::c_ulong;
|
||||
/// SA_SIGINFO;
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
macro_rules! libc_bitflags {
|
||||
(
|
||||
$(#[$outer:meta])*
|
||||
pub struct $BitFlags:ident: $T:ty {
|
||||
$(
|
||||
$(#[$inner:ident $($args:tt)*])*
|
||||
$Flag:ident $(as $cast:ty)*;
|
||||
)+
|
||||
}
|
||||
) => {
|
||||
::bitflags::bitflags! {
|
||||
$(#[$outer])*
|
||||
pub struct $BitFlags: $T {
|
||||
$(
|
||||
$(#[$inner $($args)*])*
|
||||
const $Flag = libc::$Flag $(as $cast)*;
|
||||
)+
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// The `libc_enum!` macro helps with a common use case of defining an enum exclusively using
|
||||
/// values from the `libc` crate. This macro supports both `pub` and private `enum`s.
|
||||
///
|
||||
/// The `libc` crate must be in scope with the name `libc`.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// libc_enum!{
|
||||
/// pub enum ProtFlags {
|
||||
/// 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,
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
macro_rules! libc_enum {
|
||||
// Exit rule.
|
||||
(@make_enum
|
||||
name: $BitFlags:ident,
|
||||
{
|
||||
$v:vis
|
||||
attrs: [$($attrs:tt)*],
|
||||
entries: [$($entries:tt)*],
|
||||
}
|
||||
) => {
|
||||
$($attrs)*
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
$v enum $BitFlags {
|
||||
$($entries)*
|
||||
}
|
||||
};
|
||||
|
||||
// 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
|
||||
attrs: $attrs:tt,
|
||||
from_type: $repr:path,
|
||||
},
|
||||
$entries:tt,
|
||||
$try_froms:tt;
|
||||
) => {
|
||||
libc_enum! {
|
||||
@make_enum
|
||||
name: $BitFlags,
|
||||
{
|
||||
$v
|
||||
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)*];
|
||||
#[$attr:meta] $($tail:tt)*
|
||||
) => {
|
||||
libc_enum! {
|
||||
@accumulate_entries
|
||||
name: $BitFlags,
|
||||
$prefix,
|
||||
[
|
||||
$($entries)*
|
||||
#[$attr]
|
||||
],
|
||||
[
|
||||
$($try_froms)*
|
||||
#[$attr]
|
||||
];
|
||||
$($tail)*
|
||||
}
|
||||
};
|
||||
|
||||
// Munch last ident if not followed by a comma.
|
||||
(@accumulate_entries
|
||||
name: $BitFlags:ident,
|
||||
$prefix:tt,
|
||||
[$($entries:tt)*],
|
||||
[$($try_froms: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)*
|
||||
) => {
|
||||
libc_enum! {
|
||||
@accumulate_entries
|
||||
name: $BitFlags,
|
||||
$prefix,
|
||||
[
|
||||
$($entries)*
|
||||
$entry = libc::$entry,
|
||||
],
|
||||
[
|
||||
$($try_froms)*
|
||||
libc::$entry => Ok($BitFlags::$entry),
|
||||
];
|
||||
$($tail)*
|
||||
}
|
||||
};
|
||||
|
||||
// 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)*
|
||||
) => {
|
||||
libc_enum! {
|
||||
@accumulate_entries
|
||||
name: $BitFlags,
|
||||
$prefix,
|
||||
[
|
||||
$($entries)*
|
||||
$entry = libc::$entry as $ty,
|
||||
],
|
||||
[
|
||||
$($try_froms)*
|
||||
libc::$entry as $ty => Ok($BitFlags::$entry),
|
||||
];
|
||||
$($tail)*
|
||||
}
|
||||
};
|
||||
|
||||
// Entry rule.
|
||||
(
|
||||
$(#[$attr:meta])*
|
||||
$v:vis enum $BitFlags:ident {
|
||||
$($vals:tt)*
|
||||
}
|
||||
) => {
|
||||
libc_enum! {
|
||||
@accumulate_entries
|
||||
name: $BitFlags,
|
||||
{
|
||||
$v
|
||||
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)*
|
||||
}
|
||||
};
|
||||
}
|
426
vendor/nix-v0.23.1-patched/src/mount/bsd.rs
vendored
426
vendor/nix-v0.23.1-patched/src/mount/bsd.rs
vendored
|
@ -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)
|
||||
}
|
111
vendor/nix-v0.23.1-patched/src/mount/linux.rs
vendored
111
vendor/nix-v0.23.1-patched/src/mount/linux.rs
vendored
|
@ -1,111 +0,0 @@
|
|||
#![allow(missing_docs)]
|
||||
use libc::{self, c_ulong, c_int};
|
||||
use crate::{Result, NixPath};
|
||||
use crate::errno::Errno;
|
||||
|
||||
libc_bitflags!(
|
||||
pub struct MsFlags: c_ulong {
|
||||
/// Mount read-only
|
||||
MS_RDONLY;
|
||||
/// Ignore suid and sgid bits
|
||||
MS_NOSUID;
|
||||
/// Disallow access to device special files
|
||||
MS_NODEV;
|
||||
/// Disallow program execution
|
||||
MS_NOEXEC;
|
||||
/// Writes are synced at once
|
||||
MS_SYNCHRONOUS;
|
||||
/// Alter flags of a mounted FS
|
||||
MS_REMOUNT;
|
||||
/// Allow mandatory locks on a FS
|
||||
MS_MANDLOCK;
|
||||
/// Directory modifications are synchronous
|
||||
MS_DIRSYNC;
|
||||
/// Do not update access times
|
||||
MS_NOATIME;
|
||||
/// Do not update directory access times
|
||||
MS_NODIRATIME;
|
||||
/// Linux 2.4.0 - Bind directory at different place
|
||||
MS_BIND;
|
||||
MS_MOVE;
|
||||
MS_REC;
|
||||
MS_SILENT;
|
||||
MS_POSIXACL;
|
||||
MS_UNBINDABLE;
|
||||
MS_PRIVATE;
|
||||
MS_SLAVE;
|
||||
MS_SHARED;
|
||||
MS_RELATIME;
|
||||
MS_KERNMOUNT;
|
||||
MS_I_VERSION;
|
||||
MS_STRICTATIME;
|
||||
MS_LAZYTIME;
|
||||
MS_ACTIVE;
|
||||
MS_NOUSER;
|
||||
MS_RMT_MASK;
|
||||
MS_MGC_VAL;
|
||||
MS_MGC_MSK;
|
||||
}
|
||||
);
|
||||
|
||||
libc_bitflags!(
|
||||
pub struct MntFlags: c_int {
|
||||
MNT_FORCE;
|
||||
MNT_DETACH;
|
||||
MNT_EXPIRE;
|
||||
}
|
||||
);
|
||||
|
||||
pub fn mount<P1: ?Sized + NixPath, P2: ?Sized + NixPath, P3: ?Sized + NixPath, P4: ?Sized + NixPath>(
|
||||
source: Option<&P1>,
|
||||
target: &P2,
|
||||
fstype: Option<&P3>,
|
||||
flags: MsFlags,
|
||||
data: Option<&P4>) -> Result<()> {
|
||||
|
||||
fn with_opt_nix_path<P, T, F>(p: Option<&P>, f: F) -> Result<T>
|
||||
where P: ?Sized + NixPath,
|
||||
F: FnOnce(*const libc::c_char) -> T
|
||||
{
|
||||
match p {
|
||||
Some(path) => path.with_nix_path(|p_str| f(p_str.as_ptr())),
|
||||
None => Ok(f(std::ptr::null()))
|
||||
}
|
||||
}
|
||||
|
||||
let res = with_opt_nix_path(source, |s| {
|
||||
target.with_nix_path(|t| {
|
||||
with_opt_nix_path(fstype, |ty| {
|
||||
with_opt_nix_path(data, |d| {
|
||||
unsafe {
|
||||
libc::mount(
|
||||
s,
|
||||
t.as_ptr(),
|
||||
ty,
|
||||
flags.bits,
|
||||
d as *const libc::c_void
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
})????;
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
pub fn umount<P: ?Sized + NixPath>(target: &P) -> Result<()> {
|
||||
let res = target.with_nix_path(|cstr| {
|
||||
unsafe { libc::umount(cstr.as_ptr()) }
|
||||
})?;
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
pub fn umount2<P: ?Sized + NixPath>(target: &P, flags: MntFlags) -> Result<()> {
|
||||
let res = target.with_nix_path(|cstr| {
|
||||
unsafe { libc::umount2(cstr.as_ptr(), flags.bits) }
|
||||
})?;
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
21
vendor/nix-v0.23.1-patched/src/mount/mod.rs
vendored
21
vendor/nix-v0.23.1-patched/src/mount/mod.rs
vendored
|
@ -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::*;
|
178
vendor/nix-v0.23.1-patched/src/mqueue.rs
vendored
178
vendor/nix-v0.23.1-patched/src/mqueue.rs
vendored
|
@ -1,178 +0,0 @@
|
|||
//! Posix Message Queue functions
|
||||
//!
|
||||
//! [Further reading and details on the C API](https://man7.org/linux/man-pages/man7/mq_overview.7.html)
|
||||
|
||||
use crate::Result;
|
||||
use crate::errno::Errno;
|
||||
|
||||
use libc::{self, c_char, mqd_t, size_t};
|
||||
use std::ffi::CString;
|
||||
use crate::sys::stat::Mode;
|
||||
use std::mem;
|
||||
|
||||
libc_bitflags!{
|
||||
pub struct MQ_OFlag: libc::c_int {
|
||||
O_RDONLY;
|
||||
O_WRONLY;
|
||||
O_RDWR;
|
||||
O_CREAT;
|
||||
O_EXCL;
|
||||
O_NONBLOCK;
|
||||
O_CLOEXEC;
|
||||
}
|
||||
}
|
||||
|
||||
libc_bitflags!{
|
||||
pub struct FdFlag: libc::c_int {
|
||||
FD_CLOEXEC;
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct MqAttr {
|
||||
mq_attr: libc::mq_attr,
|
||||
}
|
||||
|
||||
// x32 compatibility
|
||||
// See https://sourceware.org/bugzilla/show_bug.cgi?id=21279
|
||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
|
||||
pub type mq_attr_member_t = i64;
|
||||
#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))]
|
||||
pub type mq_attr_member_t = libc::c_long;
|
||||
|
||||
impl MqAttr {
|
||||
pub fn new(mq_flags: mq_attr_member_t,
|
||||
mq_maxmsg: mq_attr_member_t,
|
||||
mq_msgsize: mq_attr_member_t,
|
||||
mq_curmsgs: mq_attr_member_t)
|
||||
-> MqAttr
|
||||
{
|
||||
let mut attr = mem::MaybeUninit::<libc::mq_attr>::uninit();
|
||||
unsafe {
|
||||
let p = attr.as_mut_ptr();
|
||||
(*p).mq_flags = mq_flags;
|
||||
(*p).mq_maxmsg = mq_maxmsg;
|
||||
(*p).mq_msgsize = mq_msgsize;
|
||||
(*p).mq_curmsgs = mq_curmsgs;
|
||||
MqAttr { mq_attr: attr.assume_init() }
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn flags(&self) -> mq_attr_member_t {
|
||||
self.mq_attr.mq_flags
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Open a message queue
|
||||
///
|
||||
/// See also [`mq_open(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_open.html)
|
||||
// The mode.bits cast is only lossless on some OSes
|
||||
#[allow(clippy::cast_lossless)]
|
||||
pub fn mq_open(name: &CString,
|
||||
oflag: MQ_OFlag,
|
||||
mode: Mode,
|
||||
attr: Option<&MqAttr>)
|
||||
-> Result<mqd_t> {
|
||||
let res = match attr {
|
||||
Some(mq_attr) => unsafe {
|
||||
libc::mq_open(name.as_ptr(),
|
||||
oflag.bits(),
|
||||
mode.bits() as libc::c_int,
|
||||
&mq_attr.mq_attr as *const libc::mq_attr)
|
||||
},
|
||||
None => unsafe { libc::mq_open(name.as_ptr(), oflag.bits()) },
|
||||
};
|
||||
Errno::result(res)
|
||||
}
|
||||
|
||||
/// Remove a message queue
|
||||
///
|
||||
/// See also [`mq_unlink(2)`](https://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)
|
||||
}
|
||||
|
||||
/// Close a message queue
|
||||
///
|
||||
/// See also [`mq_close(2)`](https://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)
|
||||
}
|
||||
|
||||
/// Receive a message from a message queue
|
||||
///
|
||||
/// See also [`mq_receive(2)`](https://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 {
|
||||
libc::mq_receive(mqdes,
|
||||
message.as_mut_ptr() as *mut c_char,
|
||||
len,
|
||||
msg_prio as *mut u32)
|
||||
};
|
||||
Errno::result(res).map(|r| r as usize)
|
||||
}
|
||||
|
||||
/// Send a message to a message queue
|
||||
///
|
||||
/// See also [`mq_send(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html)
|
||||
pub fn mq_send(mqdes: mqd_t, message: &[u8], msq_prio: u32) -> Result<()> {
|
||||
let res = unsafe {
|
||||
libc::mq_send(mqdes,
|
||||
message.as_ptr() as *const c_char,
|
||||
message.len(),
|
||||
msq_prio)
|
||||
};
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
/// Get message queue attributes
|
||||
///
|
||||
/// See also [`mq_getattr(2)`](https://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()) };
|
||||
Errno::result(res).map(|_| unsafe{MqAttr { mq_attr: attr.assume_init() }})
|
||||
}
|
||||
|
||||
/// Set the attributes of the message queue. Only `O_NONBLOCK` can be set, everything else will be ignored
|
||||
/// 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)
|
||||
pub fn mq_setattr(mqd: mqd_t, newattr: &MqAttr) -> Result<MqAttr> {
|
||||
let mut attr = mem::MaybeUninit::<libc::mq_attr>::uninit();
|
||||
let res = unsafe {
|
||||
libc::mq_setattr(mqd, &newattr.mq_attr as *const libc::mq_attr, attr.as_mut_ptr())
|
||||
};
|
||||
Errno::result(res).map(|_| unsafe{ MqAttr { mq_attr: attr.assume_init() }})
|
||||
}
|
||||
|
||||
/// 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()),
|
||||
oldattr.mq_attr.mq_maxmsg,
|
||||
oldattr.mq_attr.mq_msgsize,
|
||||
oldattr.mq_attr.mq_curmsgs);
|
||||
mq_setattr(mqd, &newattr)
|
||||
}
|
||||
|
||||
/// Convenience function.
|
||||
/// Removes `O_NONBLOCK` attribute for a given message queue descriptor
|
||||
/// Returns the old attributes
|
||||
pub fn mq_remove_nonblock(mqd: mqd_t) -> Result<MqAttr> {
|
||||
let oldattr = mq_getattr(mqd)?;
|
||||
let newattr = MqAttr::new(0,
|
||||
oldattr.mq_attr.mq_maxmsg,
|
||||
oldattr.mq_attr.mq_msgsize,
|
||||
oldattr.mq_attr.mq_curmsgs);
|
||||
mq_setattr(mqd, &newattr)
|
||||
}
|
411
vendor/nix-v0.23.1-patched/src/net/if_.rs
vendored
411
vendor/nix-v0.23.1-patched/src/net/if_.rs
vendored
|
@ -1,411 +0,0 @@
|
|||
//! Network interface name resolution.
|
||||
//!
|
||||
//! 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;
|
||||
|
||||
/// Resolve an interface into a interface number.
|
||||
pub fn if_nametoindex<P: ?Sized + NixPath>(name: &P) -> Result<c_uint> {
|
||||
let if_index = name.with_nix_path(|name| unsafe { libc::if_nametoindex(name.as_ptr()) })?;
|
||||
|
||||
if if_index == 0 {
|
||||
Err(Error::last())
|
||||
} else {
|
||||
Ok(if_index)
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
IFF_UP;
|
||||
/// Valid broadcast address set. (see
|
||||
/// [`netdevice(7)`](https://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))
|
||||
IFF_DEBUG;
|
||||
/// Interface is a loopback interface. (see
|
||||
/// [`netdevice(7)`](https://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))
|
||||
IFF_POINTOPOINT;
|
||||
/// Avoid use of trailers. (see
|
||||
/// [`netdevice(7)`](https://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))
|
||||
#[cfg(any(target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "fuchsia",
|
||||
target_os = "illumos",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "solaris"))]
|
||||
IFF_RUNNING;
|
||||
/// No arp protocol, L2 destination address not set. (see
|
||||
/// [`netdevice(7)`](https://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))
|
||||
IFF_PROMISC;
|
||||
/// Receive all multicast packets. (see
|
||||
/// [`netdevice(7)`](https://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))
|
||||
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
|
||||
IFF_MASTER;
|
||||
/// transmission in progress, tx hardware queue is full
|
||||
#[cfg(any(target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "ios"))]
|
||||
IFF_OACTIVE;
|
||||
/// Protocol code on board.
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
IFF_INTELLIGENT;
|
||||
/// Slave of a load balancing bundle. (see
|
||||
/// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
|
||||
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
|
||||
IFF_SLAVE;
|
||||
/// Can't hear own transmissions.
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "osx"))]
|
||||
IFF_SIMPLEX;
|
||||
/// Supports multicast. (see
|
||||
/// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
|
||||
IFF_MULTICAST;
|
||||
/// Per link layer defined bit.
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "ios"))]
|
||||
IFF_LINK0;
|
||||
/// Multicast using broadcast.
|
||||
#[cfg(any(target_os = "illumos", 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))
|
||||
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
|
||||
IFF_PORTSEL;
|
||||
/// Per link layer defined bit.
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "ios"))]
|
||||
IFF_LINK1;
|
||||
/// Non-unique address.
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
IFF_UNNUMBERED;
|
||||
/// Auto media selection active. (see
|
||||
/// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
|
||||
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
|
||||
IFF_AUTOMEDIA;
|
||||
/// Per link layer defined bit.
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "ios"))]
|
||||
IFF_LINK2;
|
||||
/// Use alternate physical connection.
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "ios"))]
|
||||
IFF_ALTPHYS;
|
||||
/// DHCP controls interface.
|
||||
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
|
||||
IFF_DHCPRUNNING;
|
||||
/// The addresses are lost when the interface goes down. (see
|
||||
/// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
|
||||
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
|
||||
IFF_DYNAMIC;
|
||||
/// Do not advertise.
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
IFF_PRIVATE;
|
||||
/// Driver signals L1 up. Volatile.
|
||||
#[cfg(any(target_os = "fuchsia", target_os = "linux"))]
|
||||
IFF_LOWER_UP;
|
||||
/// Interface is in polling mode.
|
||||
#[cfg(any(target_os = "dragonfly"))]
|
||||
IFF_POLLING_COMPAT;
|
||||
/// Unconfigurable using ioctl(2).
|
||||
#[cfg(any(target_os = "freebsd"))]
|
||||
IFF_CANTCONFIG;
|
||||
/// Do not transmit packets.
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
IFF_NOXMIT;
|
||||
/// Driver signals dormant. Volatile.
|
||||
#[cfg(any(target_os = "fuchsia", target_os = "linux"))]
|
||||
IFF_DORMANT;
|
||||
/// User-requested promisc mode.
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
|
||||
IFF_PPROMISC;
|
||||
/// Just on-link subnet.
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
IFF_NOLOCAL;
|
||||
/// Echo sent packets. Volatile.
|
||||
#[cfg(any(target_os = "fuchsia", target_os = "linux"))]
|
||||
IFF_ECHO;
|
||||
/// User-requested monitor mode.
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
|
||||
IFF_MONITOR;
|
||||
/// Address is deprecated.
|
||||
#[cfg(any(target_os = "illumos", 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"))]
|
||||
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"))]
|
||||
IFF_ROUTER;
|
||||
/// Interface is in polling mode.
|
||||
#[cfg(any(target_os = "dragonfly"))]
|
||||
IFF_IDIRECT;
|
||||
/// Interface is winding down
|
||||
#[cfg(any(target_os = "freebsd"))]
|
||||
IFF_DYING;
|
||||
/// No NUD on interface.
|
||||
#[cfg(any(target_os = "illumos", 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"))]
|
||||
IFF_ANYCAST;
|
||||
/// Don't exchange routing info.
|
||||
#[cfg(any(target_os = "illumos", 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)
|
||||
#[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"))]
|
||||
IFF_IPV4;
|
||||
/// IPv6 interface.
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
IFF_IPV6;
|
||||
/// in.mpathd test address
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
IFF_NOFAILOVER;
|
||||
/// Interface has failed
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
IFF_FAILED;
|
||||
/// Interface is a hot-spare
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
IFF_STANDBY;
|
||||
/// Functioning but not used
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
IFF_INACTIVE;
|
||||
/// Interface is offline
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
IFF_OFFLINE;
|
||||
#[cfg(target_os = "solaris")]
|
||||
IFF_COS_ENABLED;
|
||||
/// Prefer as source addr.
|
||||
#[cfg(target_os = "solaris")]
|
||||
IFF_PREFERRED;
|
||||
/// RFC3041
|
||||
#[cfg(target_os = "solaris")]
|
||||
IFF_TEMPORARY;
|
||||
/// MTU set with SIOCSLIFMTU
|
||||
#[cfg(target_os = "solaris")]
|
||||
IFF_FIXEDMTU;
|
||||
/// Cannot send / receive packets
|
||||
#[cfg(target_os = "solaris")]
|
||||
IFF_VIRTUAL;
|
||||
/// Local address in use
|
||||
#[cfg(target_os = "solaris")]
|
||||
IFF_DUPLICATE;
|
||||
/// IPMP IP interface
|
||||
#[cfg(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::*;
|
4
vendor/nix-v0.23.1-patched/src/net/mod.rs
vendored
4
vendor/nix-v0.23.1-patched/src/net/mod.rs
vendored
|
@ -1,4 +0,0 @@
|
|||
//! Functionality involving network interfaces
|
||||
// To avoid clashing with the keyword "if", we use "if_" as the module name.
|
||||
// The original header is called "net/if.h".
|
||||
pub mod if_;
|
163
vendor/nix-v0.23.1-patched/src/poll.rs
vendored
163
vendor/nix-v0.23.1-patched/src/poll.rs
vendored
|
@ -1,163 +0,0 @@
|
|||
//! Wait for events to trigger on specific file descriptors
|
||||
#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
|
||||
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 crate::Result;
|
||||
use crate::errno::Errno;
|
||||
|
||||
/// This is a wrapper around `libc::pollfd`.
|
||||
///
|
||||
/// It's meant to be used as an argument to the [`poll`](fn.poll.html) and
|
||||
/// [`ppoll`](fn.ppoll.html) functions to specify the events of interest
|
||||
/// for a specific file descriptor.
|
||||
///
|
||||
/// After a call to `poll` or `ppoll`, the events that occured can be
|
||||
/// retrieved by calling [`revents()`](#method.revents) on the `PollFd`.
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct PollFd {
|
||||
pollfd: libc::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 {
|
||||
PollFd {
|
||||
pollfd: libc::pollfd {
|
||||
fd,
|
||||
events: events.bits(),
|
||||
revents: PollFlags::empty().bits(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// 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.
|
||||
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! {
|
||||
/// These flags define the different events that can be monitored by `poll` and `ppoll`
|
||||
pub struct PollFlags: libc::c_short {
|
||||
/// There is data to read.
|
||||
POLLIN;
|
||||
/// There is some exceptional condition on the file descriptor.
|
||||
///
|
||||
/// 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)).
|
||||
/// * 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)).
|
||||
/// * A cgroup.events file has been modified (see
|
||||
/// [cgroups(7)](https://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
|
||||
/// `O_NONBLOCK` is set).
|
||||
POLLOUT;
|
||||
/// Equivalent to [`POLLIN`](constant.POLLIN.html)
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
POLLRDNORM;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
/// Equivalent to [`POLLOUT`](constant.POLLOUT.html)
|
||||
POLLWRNORM;
|
||||
/// Priority band data can be read (generally unused on Linux).
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
POLLRDBAND;
|
||||
/// Priority data may be written.
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
POLLWRBAND;
|
||||
/// Error condition (only returned in
|
||||
/// [`PollFd::revents`](struct.PollFd.html#method.revents);
|
||||
/// ignored in [`PollFd::new`](struct.PollFd.html#method.new)).
|
||||
/// This bit is also set for a file descriptor referring to the
|
||||
/// write end of a pipe when the read end has been closed.
|
||||
POLLERR;
|
||||
/// Hang up (only returned in [`PollFd::revents`](struct.PollFd.html#method.revents);
|
||||
/// ignored in [`PollFd::new`](struct.PollFd.html#method.new)).
|
||||
/// Note that when reading from a channel such as a pipe or a stream
|
||||
/// socket, this event merely indicates that the peer closed its
|
||||
/// end of the channel. Subsequent reads from the channel will
|
||||
/// return 0 (end of file) only after all outstanding data in the
|
||||
/// channel has been consumed.
|
||||
POLLHUP;
|
||||
/// Invalid request: `fd` not open (only returned in
|
||||
/// [`PollFd::revents`](struct.PollFd.html#method.revents);
|
||||
/// ignored in [`PollFd::new`](struct.PollFd.html#method.new)).
|
||||
POLLNVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/// `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))
|
||||
///
|
||||
/// `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.
|
||||
///
|
||||
/// The `timeout` argument specifies the number of milliseconds that `poll()`
|
||||
/// should block waiting for a file descriptor to become ready. The call
|
||||
/// will block until either:
|
||||
///
|
||||
/// * a file descriptor becomes ready;
|
||||
/// * the call is interrupted by a signal handler; or
|
||||
/// * the timeout expires.
|
||||
///
|
||||
/// Note that the timeout interval will be rounded up to the system clock
|
||||
/// granularity, and kernel scheduling delays mean that the blocking
|
||||
/// interval may overrun by a small amount. Specifying a negative value
|
||||
/// in timeout means an infinite timeout. Specifying a timeout of zero
|
||||
/// causes `poll()` to return immediately, even if no file descriptors are
|
||||
/// ready.
|
||||
pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result<libc::c_int> {
|
||||
let res = unsafe {
|
||||
libc::poll(fds.as_mut_ptr() as *mut libc::pollfd,
|
||||
fds.len() as libc::nfds_t,
|
||||
timeout)
|
||||
};
|
||||
|
||||
Errno::result(res)
|
||||
}
|
||||
|
||||
/// `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))
|
||||
///
|
||||
/// `ppoll` behaves like `poll`, but let you specify what signals may interrupt it
|
||||
/// with the `sigmask` argument. If you want `ppoll` to block indefinitely,
|
||||
/// specify `None` as `timeout` (it is like `timeout = -1` for `poll`).
|
||||
///
|
||||
#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
|
||||
pub fn ppoll(fds: &mut [PollFd], timeout: Option<TimeSpec>, sigmask: SigSet) -> Result<libc::c_int> {
|
||||
let timeout = timeout.as_ref().map_or(core::ptr::null(), |r| r.as_ref());
|
||||
let res = unsafe {
|
||||
libc::ppoll(fds.as_mut_ptr() as *mut libc::pollfd,
|
||||
fds.len() as libc::nfds_t,
|
||||
timeout,
|
||||
sigmask.as_ref())
|
||||
};
|
||||
Errno::result(res)
|
||||
}
|
348
vendor/nix-v0.23.1-patched/src/pty.rs
vendored
348
vendor/nix-v0.23.1-patched/src/pty.rs
vendored
|
@ -1,348 +0,0 @@
|
|||
//! Create master and slave virtual pseudo-terminals (PTYs)
|
||||
|
||||
pub use libc::pid_t as SessionId;
|
||||
pub use libc::winsize as Winsize;
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::io;
|
||||
use std::mem;
|
||||
use std::os::unix::prelude::*;
|
||||
|
||||
use crate::sys::termios::Termios;
|
||||
use crate::unistd::{self, ForkResult, Pid};
|
||||
use crate::{Result, fcntl};
|
||||
use crate::errno::Errno;
|
||||
|
||||
/// Representation of a master/slave pty pair
|
||||
///
|
||||
/// This is returned by `openpty`. Note that this type does *not* implement `Drop`, so the user
|
||||
/// must manually close the file descriptors.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct OpenptyResult {
|
||||
/// The master port in a virtual pty pair
|
||||
pub master: RawFd,
|
||||
/// The slave port in a virtual pty pair
|
||||
pub slave: RawFd,
|
||||
}
|
||||
|
||||
/// Representation of a master with a forked pty
|
||||
///
|
||||
/// This is returned by `forkpty`. Note that this type does *not* implement `Drop`, so the user
|
||||
/// must manually close the file descriptors.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct ForkptyResult {
|
||||
/// The master port in a virtual pty pair
|
||||
pub master: RawFd,
|
||||
/// Metadata about forked process
|
||||
pub fork_result: ForkResult,
|
||||
}
|
||||
|
||||
|
||||
/// Representation of the Master device in a master/slave pty pair
|
||||
///
|
||||
/// While this datatype is a thin wrapper around `RawFd`, it enforces that the available PTY
|
||||
/// functions are given the correct file descriptor. Additionally this type implements `Drop`,
|
||||
/// so that when it's consumed or goes out of scope, it's automatically cleaned-up.
|
||||
#[derive(Debug, Eq, Hash, PartialEq)]
|
||||
pub struct PtyMaster(RawFd);
|
||||
|
||||
impl AsRawFd for PtyMaster {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for PtyMaster {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
let fd = self.0;
|
||||
mem::forget(self);
|
||||
fd
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for PtyMaster {
|
||||
fn drop(&mut self) {
|
||||
// On drop, we ignore errors like EINTR and EIO because there's no clear
|
||||
// way to handle them, we can't return anything, and (on FreeBSD at
|
||||
// least) the file descriptor is deallocated in these cases. However,
|
||||
// we must panic on EBADF, because it is always an error to close an
|
||||
// invalid file descriptor. That frequently indicates a double-close
|
||||
// condition, which can cause confusing errors for future I/O
|
||||
// operations.
|
||||
let e = unistd::close(self.0);
|
||||
if e == Err(Errno::EBADF) {
|
||||
panic!("Closing an invalid file descriptor!");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
impl io::Write for PtyMaster {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
unistd::write(self.0, buf).map_err(io::Error::from)
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Grant access to a slave pseudoterminal (see
|
||||
/// [`grantpt(3)`](https://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());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Open a pseudoterminal device (see
|
||||
/// [`posix_openpt(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_openpt.html))
|
||||
///
|
||||
/// `posix_openpt()` returns a file descriptor to an existing unused pseuterminal master device.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// A common use case with this function is to open both a master and slave PTY pair. This can be
|
||||
/// done as follows:
|
||||
///
|
||||
/// ```
|
||||
/// use std::path::Path;
|
||||
/// use nix::fcntl::{OFlag, open};
|
||||
/// use nix::pty::{grantpt, posix_openpt, ptsname, unlockpt};
|
||||
/// use nix::sys::stat::Mode;
|
||||
///
|
||||
/// # #[allow(dead_code)]
|
||||
/// # fn run() -> nix::Result<()> {
|
||||
/// // Open a new PTY master
|
||||
/// let master_fd = posix_openpt(OFlag::O_RDWR)?;
|
||||
///
|
||||
/// // Allow a slave to be generated for it
|
||||
/// grantpt(&master_fd)?;
|
||||
/// unlockpt(&master_fd)?;
|
||||
///
|
||||
/// // Get the name of the slave
|
||||
/// let slave_name = unsafe { ptsname(&master_fd) }?;
|
||||
///
|
||||
/// // Try to open the slave
|
||||
/// let _slave_fd = open(Path::new(&slave_name), OFlag::O_RDWR, Mode::empty())?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn posix_openpt(flags: fcntl::OFlag) -> Result<PtyMaster> {
|
||||
let fd = unsafe {
|
||||
libc::posix_openpt(flags.bits())
|
||||
};
|
||||
|
||||
if fd < 0 {
|
||||
return Err(Errno::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()` returns the name of the slave pseudoterminal device corresponding to the master
|
||||
/// referred to by `fd`.
|
||||
///
|
||||
/// This value is useful for opening the slave pty once the master has already been opened with
|
||||
/// `posix_openpt()`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `ptsname()` mutates global variables and is *not* threadsafe.
|
||||
/// Mutating global variables is always considered `unsafe` by Rust and this
|
||||
/// function is marked as `unsafe` to reflect that.
|
||||
///
|
||||
/// For a threadsafe and non-`unsafe` alternative on Linux, see `ptsname_r()`.
|
||||
#[inline]
|
||||
pub unsafe fn ptsname(fd: &PtyMaster) -> Result<String> {
|
||||
let name_ptr = libc::ptsname(fd.as_raw_fd());
|
||||
if name_ptr.is_null() {
|
||||
return Err(Errno::last());
|
||||
}
|
||||
|
||||
let name = CStr::from_ptr(name_ptr);
|
||||
Ok(name.to_string_lossy().into_owned())
|
||||
}
|
||||
|
||||
/// Get the name of the slave pseudoterminal (see
|
||||
/// [`ptsname(3)`](https://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
|
||||
/// POSIX standard and is instead a Linux-specific extension.
|
||||
///
|
||||
/// This value is useful for opening the slave ptty once the master has already been opened with
|
||||
/// `posix_openpt()`.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[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 name = cname.to_string_lossy().into_owned();
|
||||
Ok(name)
|
||||
}
|
||||
|
||||
/// Unlock a pseudoterminal master/slave pseudoterminal pair (see
|
||||
/// [`unlockpt(3)`](https://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
|
||||
/// pseuoterminal.
|
||||
#[inline]
|
||||
pub fn unlockpt(fd: &PtyMaster) -> Result<()> {
|
||||
if unsafe { libc::unlockpt(fd.as_raw_fd()) } < 0 {
|
||||
return Err(Errno::last());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
/// 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)).
|
||||
///
|
||||
/// 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`.
|
||||
#[inline]
|
||||
pub fn openpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>>>(winsize: T, termios: U) -> Result<OpenptyResult> {
|
||||
use std::ptr;
|
||||
|
||||
let mut slave = mem::MaybeUninit::<libc::c_int>::uninit();
|
||||
let mut master = mem::MaybeUninit::<libc::c_int>::uninit();
|
||||
let ret = {
|
||||
match (termios.into(), winsize.into()) {
|
||||
(Some(termios), Some(winsize)) => {
|
||||
let inner_termios = termios.get_libc_termios();
|
||||
unsafe {
|
||||
libc::openpty(
|
||||
master.as_mut_ptr(),
|
||||
slave.as_mut_ptr(),
|
||||
ptr::null_mut(),
|
||||
&*inner_termios as *const libc::termios as *mut _,
|
||||
winsize as *const Winsize as *mut _,
|
||||
)
|
||||
}
|
||||
}
|
||||
(None, Some(winsize)) => {
|
||||
unsafe {
|
||||
libc::openpty(
|
||||
master.as_mut_ptr(),
|
||||
slave.as_mut_ptr(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
winsize as *const Winsize as *mut _,
|
||||
)
|
||||
}
|
||||
}
|
||||
(Some(termios), None) => {
|
||||
let inner_termios = termios.get_libc_termios();
|
||||
unsafe {
|
||||
libc::openpty(
|
||||
master.as_mut_ptr(),
|
||||
slave.as_mut_ptr(),
|
||||
ptr::null_mut(),
|
||||
&*inner_termios as *const libc::termios as *mut _,
|
||||
ptr::null_mut(),
|
||||
)
|
||||
}
|
||||
}
|
||||
(None, None) => {
|
||||
unsafe {
|
||||
libc::openpty(
|
||||
master.as_mut_ptr(),
|
||||
slave.as_mut_ptr(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Errno::result(ret)?;
|
||||
|
||||
unsafe {
|
||||
Ok(OpenptyResult {
|
||||
master: master.assume_init(),
|
||||
slave: slave.assume_init(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// 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)).
|
||||
///
|
||||
/// 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>>>(
|
||||
winsize: T,
|
||||
termios: U,
|
||||
) -> Result<ForkptyResult> {
|
||||
use std::ptr;
|
||||
|
||||
let mut master = mem::MaybeUninit::<libc::c_int>::uninit();
|
||||
|
||||
let term = match termios.into() {
|
||||
Some(termios) => {
|
||||
let inner_termios = termios.get_libc_termios();
|
||||
&*inner_termios as *const libc::termios as *mut _
|
||||
},
|
||||
None => ptr::null_mut(),
|
||||
};
|
||||
|
||||
let win = winsize
|
||||
.into()
|
||||
.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 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,
|
||||
})
|
||||
}
|
282
vendor/nix-v0.23.1-patched/src/sched.rs
vendored
282
vendor/nix-v0.23.1-patched/src/sched.rs
vendored
|
@ -1,282 +0,0 @@
|
|||
//! 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"))]
|
||||
pub use self::sched_linux_like::*;
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
mod sched_linux_like {
|
||||
use crate::errno::Errno;
|
||||
use libc::{self, c_int, c_void};
|
||||
use std::mem;
|
||||
use std::option::Option;
|
||||
use std::os::unix::io::RawFd;
|
||||
use crate::unistd::Pid;
|
||||
use crate::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_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_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.
|
||||
/// CpuSets are used by sched_setaffinity and
|
||||
/// sched_getaffinity for example.
|
||||
///
|
||||
/// This is a wrapper around `libc::cpu_set_t`.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct CpuSet {
|
||||
cpu_set: libc::cpu_set_t,
|
||||
}
|
||||
|
||||
impl CpuSet {
|
||||
/// Create a new and empty CpuSet.
|
||||
pub fn new() -> CpuSet {
|
||||
CpuSet {
|
||||
cpu_set: unsafe { mem::zeroed() },
|
||||
}
|
||||
}
|
||||
|
||||
/// Test to see if a CPU is in the CpuSet.
|
||||
/// `field` is the CPU id to test
|
||||
pub fn is_set(&self, field: usize) -> Result<bool> {
|
||||
if field >= CpuSet::count() {
|
||||
Err(Errno::EINVAL)
|
||||
} else {
|
||||
Ok(unsafe { libc::CPU_ISSET(field, &self.cpu_set) })
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a CPU to CpuSet.
|
||||
/// `field` is the CPU id to add
|
||||
pub fn set(&mut self, field: usize) -> Result<()> {
|
||||
if field >= CpuSet::count() {
|
||||
Err(Errno::EINVAL)
|
||||
} else {
|
||||
unsafe { libc::CPU_SET(field, &mut self.cpu_set); }
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove a CPU from CpuSet.
|
||||
/// `field` is the CPU id to remove
|
||||
pub fn unset(&mut self, field: usize) -> Result<()> {
|
||||
if field >= CpuSet::count() {
|
||||
Err(Errno::EINVAL)
|
||||
} else {
|
||||
unsafe { libc::CPU_CLR(field, &mut self.cpu_set);}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the maximum number of CPU in CpuSet
|
||||
pub const fn count() -> usize {
|
||||
8 * mem::size_of::<libc::cpu_set_t>()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CpuSet {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// `sched_setaffinity` set a thread's CPU affinity mask
|
||||
/// ([`sched_setaffinity(2)`](https://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.
|
||||
///
|
||||
/// The `cpuset` argument specifies the set of CPUs on which the thread
|
||||
/// will be eligible to run.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Binding the current thread to CPU 0 can be done as follows:
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use nix::sched::{CpuSet, sched_setaffinity};
|
||||
/// use nix::unistd::Pid;
|
||||
///
|
||||
/// let mut cpu_set = CpuSet::new();
|
||||
/// cpu_set.set(0);
|
||||
/// sched_setaffinity(Pid::from_raw(0), &cpu_set);
|
||||
/// ```
|
||||
pub fn sched_setaffinity(pid: Pid, cpuset: &CpuSet) -> Result<()> {
|
||||
let res = unsafe {
|
||||
libc::sched_setaffinity(
|
||||
pid.into(),
|
||||
mem::size_of::<CpuSet>() as libc::size_t,
|
||||
&cpuset.cpu_set,
|
||||
)
|
||||
};
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
/// `sched_getaffinity` get a thread's CPU affinity mask
|
||||
/// ([`sched_getaffinity(2)`](https://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.
|
||||
///
|
||||
/// Returned `cpuset` is the set of CPUs on which the thread
|
||||
/// is eligible to run.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Checking if the current thread can run on CPU 0 can be done as follows:
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use nix::sched::sched_getaffinity;
|
||||
/// use nix::unistd::Pid;
|
||||
///
|
||||
/// let cpu_set = sched_getaffinity(Pid::from_raw(0)).unwrap();
|
||||
/// if cpu_set.is_set(0).unwrap() {
|
||||
/// println!("Current thread can run on CPU 0");
|
||||
/// }
|
||||
/// ```
|
||||
pub fn sched_getaffinity(pid: Pid) -> Result<CpuSet> {
|
||||
let mut cpuset = CpuSet::new();
|
||||
let res = unsafe {
|
||||
libc::sched_getaffinity(
|
||||
pid.into(),
|
||||
mem::size_of::<CpuSet>() as libc::size_t,
|
||||
&mut cpuset.cpu_set,
|
||||
)
|
||||
};
|
||||
|
||||
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],
|
||||
flags: CloneFlags,
|
||||
signal: Option<c_int>,
|
||||
) -> Result<Pid> {
|
||||
extern "C" fn callback(data: *mut CloneCb) -> c_int {
|
||||
let cb: &mut CloneCb = unsafe { &mut *data };
|
||||
(*cb)() as c_int
|
||||
}
|
||||
|
||||
let res = unsafe {
|
||||
let combined = flags.bits() | signal.unwrap_or(0);
|
||||
let ptr = stack.as_mut_ptr().add(stack.len());
|
||||
let ptr_aligned = ptr.sub(ptr as usize % 16);
|
||||
libc::clone(
|
||||
mem::transmute(
|
||||
callback as extern "C" fn(*mut Box<dyn FnMut() -> isize>) -> i32,
|
||||
),
|
||||
ptr_aligned as *mut c_void,
|
||||
combined,
|
||||
&mut cb as *mut _ as *mut c_void,
|
||||
)
|
||||
};
|
||||
|
||||
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()) };
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
}
|
||||
|
||||
/// Explicitly yield the processor to other threads.
|
||||
///
|
||||
/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_yield.html)
|
||||
pub fn sched_yield() -> Result<()> {
|
||||
let res = unsafe { libc::sched_yield() };
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
1122
vendor/nix-v0.23.1-patched/src/sys/aio.rs
vendored
1122
vendor/nix-v0.23.1-patched/src/sys/aio.rs
vendored
File diff suppressed because it is too large
Load diff
109
vendor/nix-v0.23.1-patched/src/sys/epoll.rs
vendored
109
vendor/nix-v0.23.1-patched/src/sys/epoll.rs
vendored
|
@ -1,109 +0,0 @@
|
|||
use crate::Result;
|
||||
use crate::errno::Errno;
|
||||
use libc::{self, c_int};
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::ptr;
|
||||
use std::mem;
|
||||
|
||||
libc_bitflags!(
|
||||
pub struct EpollFlags: c_int {
|
||||
EPOLLIN;
|
||||
EPOLLPRI;
|
||||
EPOLLOUT;
|
||||
EPOLLRDNORM;
|
||||
EPOLLRDBAND;
|
||||
EPOLLWRNORM;
|
||||
EPOLLWRBAND;
|
||||
EPOLLMSG;
|
||||
EPOLLERR;
|
||||
EPOLLHUP;
|
||||
EPOLLRDHUP;
|
||||
#[cfg(target_os = "linux")] // Added in 4.5; not in Android.
|
||||
EPOLLEXCLUSIVE;
|
||||
#[cfg(not(target_arch = "mips"))]
|
||||
EPOLLWAKEUP;
|
||||
EPOLLONESHOT;
|
||||
EPOLLET;
|
||||
}
|
||||
);
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
#[repr(i32)]
|
||||
#[non_exhaustive]
|
||||
pub enum EpollOp {
|
||||
EpollCtlAdd = libc::EPOLL_CTL_ADD,
|
||||
EpollCtlDel = libc::EPOLL_CTL_DEL,
|
||||
EpollCtlMod = libc::EPOLL_CTL_MOD,
|
||||
}
|
||||
|
||||
libc_bitflags!{
|
||||
pub struct EpollCreateFlags: c_int {
|
||||
EPOLL_CLOEXEC;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
#[repr(transparent)]
|
||||
pub struct EpollEvent {
|
||||
event: libc::epoll_event,
|
||||
}
|
||||
|
||||
impl EpollEvent {
|
||||
pub fn new(events: EpollFlags, data: u64) -> Self {
|
||||
EpollEvent { event: libc::epoll_event { events: events.bits() as u32, u64: data } }
|
||||
}
|
||||
|
||||
pub fn empty() -> Self {
|
||||
unsafe { mem::zeroed::<EpollEvent>() }
|
||||
}
|
||||
|
||||
pub fn events(&self) -> EpollFlags {
|
||||
EpollFlags::from_bits(self.event.events as c_int).unwrap()
|
||||
}
|
||||
|
||||
pub fn data(&self) -> u64 {
|
||||
self.event.u64
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn epoll_create() -> Result<RawFd> {
|
||||
let res = unsafe { libc::epoll_create(1024) };
|
||||
|
||||
Errno::result(res)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn epoll_create1(flags: EpollCreateFlags) -> Result<RawFd> {
|
||||
let res = unsafe { libc::epoll_create1(flags.bits()) };
|
||||
|
||||
Errno::result(res)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn epoll_ctl<'a, T>(epfd: RawFd, op: EpollOp, fd: RawFd, event: T) -> Result<()>
|
||||
where T: Into<Option<&'a mut EpollEvent>>
|
||||
{
|
||||
let mut event: Option<&mut EpollEvent> = event.into();
|
||||
if event.is_none() && op != EpollOp::EpollCtlDel {
|
||||
Err(Errno::EINVAL)
|
||||
} else {
|
||||
let res = unsafe {
|
||||
if let Some(ref mut event) = event {
|
||||
libc::epoll_ctl(epfd, op as c_int, fd, &mut event.event)
|
||||
} else {
|
||||
libc::epoll_ctl(epfd, op as c_int, fd, ptr::null_mut())
|
||||
}
|
||||
};
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn epoll_wait(epfd: RawFd, events: &mut [EpollEvent], timeout_ms: isize) -> Result<usize> {
|
||||
let res = unsafe {
|
||||
libc::epoll_wait(epfd, events.as_mut_ptr() as *mut libc::epoll_event, events.len() as c_int, timeout_ms as c_int)
|
||||
};
|
||||
|
||||
Errno::result(res).map(|r| r as usize)
|
||||
}
|
348
vendor/nix-v0.23.1-patched/src/sys/event.rs
vendored
348
vendor/nix-v0.23.1-patched/src/sys/event.rs
vendored
|
@ -1,348 +0,0 @@
|
|||
/* TOOD: Implement for other kqueue based systems
|
||||
*/
|
||||
|
||||
use crate::{Errno, Result};
|
||||
#[cfg(not(target_os = "netbsd"))]
|
||||
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;
|
||||
|
||||
// Redefine kevent in terms of programmer-friendly enums and bitfields.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct KEvent {
|
||||
kevent: libc::kevent,
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
|
||||
target_os = "ios", target_os = "macos",
|
||||
target_os = "openbsd"))]
|
||||
type type_of_udata = *mut libc::c_void;
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
|
||||
target_os = "ios", target_os = "macos"))]
|
||||
type type_of_data = intptr_t;
|
||||
#[cfg(any(target_os = "netbsd"))]
|
||||
type type_of_udata = intptr_t;
|
||||
#[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
|
||||
type type_of_data = i64;
|
||||
|
||||
#[cfg(target_os = "netbsd")]
|
||||
type type_of_event_filter = u32;
|
||||
#[cfg(not(target_os = "netbsd"))]
|
||||
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
|
||||
#[cfg(target_os = "freebsd")]
|
||||
EVFILT_EMPTY,
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
EVFILT_EXCEPT,
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos"))]
|
||||
EVFILT_FS,
|
||||
#[cfg(target_os = "freebsd")]
|
||||
EVFILT_LIO,
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
EVFILT_MACHPORT,
|
||||
EVFILT_PROC,
|
||||
/// Returns events associated with the process referenced by a given
|
||||
/// process descriptor, created by `pdfork()`. The events to monitor are:
|
||||
///
|
||||
/// - NOTE_EXIT: the process has exited. The exit status will be stored in data.
|
||||
#[cfg(target_os = "freebsd")]
|
||||
EVFILT_PROCDESC,
|
||||
EVFILT_READ,
|
||||
/// Returns whenever an asynchronous `sendfile()` call completes.
|
||||
#[cfg(target_os = "freebsd")]
|
||||
EVFILT_SENDFILE,
|
||||
EVFILT_SIGNAL,
|
||||
EVFILT_TIMER,
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos"))]
|
||||
EVFILT_USER,
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
EVFILT_VM,
|
||||
EVFILT_VNODE,
|
||||
EVFILT_WRITE,
|
||||
}
|
||||
impl TryFrom<type_of_event_filter>
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
|
||||
target_os = "ios", target_os = "macos",
|
||||
target_os = "openbsd"))]
|
||||
pub type type_of_event_flag = u16;
|
||||
#[cfg(any(target_os = "netbsd"))]
|
||||
pub type type_of_event_flag = u32;
|
||||
libc_bitflags!{
|
||||
pub struct EventFlag: type_of_event_flag {
|
||||
EV_ADD;
|
||||
EV_CLEAR;
|
||||
EV_DELETE;
|
||||
EV_DISABLE;
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
|
||||
target_os = "ios", target_os = "macos",
|
||||
target_os = "netbsd", target_os = "openbsd"))]
|
||||
EV_DISPATCH;
|
||||
#[cfg(target_os = "freebsd")]
|
||||
EV_DROP;
|
||||
EV_ENABLE;
|
||||
EV_EOF;
|
||||
EV_ERROR;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
EV_FLAG0;
|
||||
EV_FLAG1;
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
EV_NODATA;
|
||||
EV_ONESHOT;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
EV_OOBAND;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
EV_POLL;
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
|
||||
target_os = "ios", target_os = "macos",
|
||||
target_os = "netbsd", target_os = "openbsd"))]
|
||||
EV_RECEIPT;
|
||||
EV_SYSFLAGS;
|
||||
}
|
||||
}
|
||||
|
||||
libc_bitflags!(
|
||||
pub struct FilterFlag: u32 {
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
NOTE_ABSOLUTE;
|
||||
NOTE_ATTRIB;
|
||||
NOTE_CHILD;
|
||||
NOTE_DELETE;
|
||||
#[cfg(target_os = "openbsd")]
|
||||
NOTE_EOF;
|
||||
NOTE_EXEC;
|
||||
NOTE_EXIT;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
NOTE_EXITSTATUS;
|
||||
NOTE_EXTEND;
|
||||
#[cfg(any(target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly"))]
|
||||
NOTE_FFAND;
|
||||
#[cfg(any(target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly"))]
|
||||
NOTE_FFCOPY;
|
||||
#[cfg(any(target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly"))]
|
||||
NOTE_FFCTRLMASK;
|
||||
#[cfg(any(target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly"))]
|
||||
NOTE_FFLAGSMASK;
|
||||
#[cfg(any(target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly"))]
|
||||
NOTE_FFNOP;
|
||||
#[cfg(any(target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly"))]
|
||||
NOTE_FFOR;
|
||||
NOTE_FORK;
|
||||
NOTE_LINK;
|
||||
NOTE_LOWAT;
|
||||
#[cfg(target_os = "freebsd")]
|
||||
NOTE_MSECONDS;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
NOTE_NONE;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
|
||||
NOTE_NSECONDS;
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
NOTE_OOB;
|
||||
NOTE_PCTRLMASK;
|
||||
NOTE_PDATAMASK;
|
||||
NOTE_RENAME;
|
||||
NOTE_REVOKE;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
|
||||
NOTE_SECONDS;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
NOTE_SIGNAL;
|
||||
NOTE_TRACK;
|
||||
NOTE_TRACKERR;
|
||||
#[cfg(any(target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly"))]
|
||||
NOTE_TRIGGER;
|
||||
#[cfg(target_os = "openbsd")]
|
||||
NOTE_TRUNCATE;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
|
||||
NOTE_USECONDS;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
NOTE_VM_ERROR;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
NOTE_VM_PRESSURE;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
NOTE_VM_PRESSURE_SUDDEN_TERMINATE;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
NOTE_VM_PRESSURE_TERMINATE;
|
||||
NOTE_WRITE;
|
||||
}
|
||||
);
|
||||
|
||||
pub fn kqueue() -> Result<RawFd> {
|
||||
let res = unsafe { libc::kqueue() };
|
||||
|
||||
Errno::result(res)
|
||||
}
|
||||
|
||||
|
||||
// KEvent can't derive Send because on some operating systems, udata is defined
|
||||
// as a void*. However, KEvent's public API always treats udata as an intptr_t,
|
||||
// which is safe to Send.
|
||||
unsafe impl Send for KEvent {
|
||||
}
|
||||
|
||||
impl KEvent {
|
||||
pub fn new(ident: uintptr_t, filter: EventFilter, flags: EventFlag,
|
||||
fflags:FilterFlag, data: intptr_t, udata: intptr_t) -> KEvent {
|
||||
KEvent { kevent: libc::kevent {
|
||||
ident,
|
||||
filter: filter as type_of_event_filter,
|
||||
flags: flags.bits(),
|
||||
fflags: fflags.bits(),
|
||||
data: data as type_of_data,
|
||||
udata: udata as type_of_udata
|
||||
} }
|
||||
}
|
||||
|
||||
pub fn ident(&self) -> uintptr_t {
|
||||
self.kevent.ident
|
||||
}
|
||||
|
||||
pub fn filter(&self) -> Result<EventFilter> {
|
||||
self.kevent.filter.try_into()
|
||||
}
|
||||
|
||||
pub fn flags(&self) -> EventFlag {
|
||||
EventFlag::from_bits(self.kevent.flags).unwrap()
|
||||
}
|
||||
|
||||
pub fn fflags(&self) -> FilterFlag {
|
||||
FilterFlag::from_bits(self.kevent.fflags).unwrap()
|
||||
}
|
||||
|
||||
pub fn data(&self) -> intptr_t {
|
||||
self.kevent.data as intptr_t
|
||||
}
|
||||
|
||||
pub fn udata(&self) -> intptr_t {
|
||||
self.kevent.udata as intptr_t
|
||||
}
|
||||
}
|
||||
|
||||
pub fn kevent(kq: RawFd,
|
||||
changelist: &[KEvent],
|
||||
eventlist: &mut [KEvent],
|
||||
timeout_ms: usize) -> Result<usize> {
|
||||
|
||||
// Convert ms to timespec
|
||||
let timeout = timespec {
|
||||
tv_sec: (timeout_ms / 1000) as time_t,
|
||||
tv_nsec: ((timeout_ms % 1000) * 1_000_000) as c_long
|
||||
};
|
||||
|
||||
kevent_ts(kq, changelist, eventlist, Some(timeout))
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "openbsd"))]
|
||||
type type_of_nchanges = c_int;
|
||||
#[cfg(target_os = "netbsd")]
|
||||
type type_of_nchanges = size_t;
|
||||
|
||||
pub fn kevent_ts(kq: RawFd,
|
||||
changelist: &[KEvent],
|
||||
eventlist: &mut [KEvent],
|
||||
timeout_opt: Option<timespec>) -> Result<usize> {
|
||||
|
||||
let res = unsafe {
|
||||
libc::kevent(
|
||||
kq,
|
||||
changelist.as_ptr() as *const libc::kevent,
|
||||
changelist.len() as type_of_nchanges,
|
||||
eventlist.as_mut_ptr() as *mut libc::kevent,
|
||||
eventlist.len() as type_of_nchanges,
|
||||
if let Some(ref timeout) = timeout_opt {timeout as *const timespec} else {ptr::null()})
|
||||
};
|
||||
|
||||
Errno::result(res).map(|r| r as usize)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn ev_set(ev: &mut KEvent,
|
||||
ident: usize,
|
||||
filter: EventFilter,
|
||||
flags: EventFlag,
|
||||
fflags: FilterFlag,
|
||||
udata: intptr_t) {
|
||||
|
||||
ev.kevent.ident = ident as uintptr_t;
|
||||
ev.kevent.filter = filter as type_of_event_filter;
|
||||
ev.kevent.flags = flags.bits();
|
||||
ev.kevent.fflags = fflags.bits();
|
||||
ev.kevent.data = 0;
|
||||
ev.kevent.udata = udata as type_of_udata;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_struct_kevent() {
|
||||
use std::mem;
|
||||
|
||||
let udata : intptr_t = 12345;
|
||||
|
||||
let actual = KEvent::new(0xdead_beef,
|
||||
EventFilter::EVFILT_READ,
|
||||
EventFlag::EV_ONESHOT | EventFlag::EV_ADD,
|
||||
FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT,
|
||||
0x1337,
|
||||
udata);
|
||||
assert_eq!(0xdead_beef, actual.ident());
|
||||
let filter = actual.kevent.filter;
|
||||
assert_eq!(libc::EVFILT_READ, filter);
|
||||
assert_eq!(libc::EV_ONESHOT | libc::EV_ADD, actual.flags().bits());
|
||||
assert_eq!(libc::NOTE_CHILD | libc::NOTE_EXIT, actual.fflags().bits());
|
||||
assert_eq!(0x1337, actual.data() 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());
|
||||
}
|
17
vendor/nix-v0.23.1-patched/src/sys/eventfd.rs
vendored
17
vendor/nix-v0.23.1-patched/src/sys/eventfd.rs
vendored
|
@ -1,17 +0,0 @@
|
|||
use std::os::unix::io::RawFd;
|
||||
use crate::Result;
|
||||
use crate::errno::Errno;
|
||||
|
||||
libc_bitflags! {
|
||||
pub struct EfdFlags: libc::c_int {
|
||||
EFD_CLOEXEC; // Since Linux 2.6.27
|
||||
EFD_NONBLOCK; // Since Linux 2.6.27
|
||||
EFD_SEMAPHORE; // Since Linux 2.6.30
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eventfd(initval: libc::c_uint, flags: EfdFlags) -> Result<RawFd> {
|
||||
let res = unsafe { libc::eventfd(initval, flags.bits()) };
|
||||
|
||||
Errno::result(res).map(|r| r as RawFd)
|
||||
}
|
233
vendor/nix-v0.23.1-patched/src/sys/inotify.rs
vendored
233
vendor/nix-v0.23.1-patched/src/sys/inotify.rs
vendored
|
@ -1,233 +0,0 @@
|
|||
//! Monitoring API for filesystem events.
|
||||
//!
|
||||
//! 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).
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Monitor all events happening in directory "test":
|
||||
//! ```no_run
|
||||
//! # use nix::sys::inotify::{AddWatchFlags,InitFlags,Inotify};
|
||||
//! #
|
||||
//! // We create a new inotify instance.
|
||||
//! let instance = Inotify::init(InitFlags::empty()).unwrap();
|
||||
//!
|
||||
//! // We add a new watch on directory "test" for all events.
|
||||
//! let wd = instance.add_watch("test", AddWatchFlags::IN_ALL_EVENTS).unwrap();
|
||||
//!
|
||||
//! loop {
|
||||
//! // We read from our inotify instance for events.
|
||||
//! let events = instance.read_events().unwrap();
|
||||
//! println!("Events: {:?}", events);
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
use libc::{
|
||||
c_char,
|
||||
c_int,
|
||||
};
|
||||
use std::ffi::{OsString,OsStr,CStr};
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::mem::{MaybeUninit, size_of};
|
||||
use std::os::unix::io::{RawFd,AsRawFd,FromRawFd};
|
||||
use std::ptr;
|
||||
use crate::unistd::read;
|
||||
use crate::Result;
|
||||
use crate::NixPath;
|
||||
use crate::errno::Errno;
|
||||
|
||||
libc_bitflags! {
|
||||
/// Configuration options for [`inotify_add_watch`](fn.inotify_add_watch.html).
|
||||
pub struct AddWatchFlags: u32 {
|
||||
IN_ACCESS;
|
||||
IN_MODIFY;
|
||||
IN_ATTRIB;
|
||||
IN_CLOSE_WRITE;
|
||||
IN_CLOSE_NOWRITE;
|
||||
IN_OPEN;
|
||||
IN_MOVED_FROM;
|
||||
IN_MOVED_TO;
|
||||
IN_CREATE;
|
||||
IN_DELETE;
|
||||
IN_DELETE_SELF;
|
||||
IN_MOVE_SELF;
|
||||
|
||||
IN_UNMOUNT;
|
||||
IN_Q_OVERFLOW;
|
||||
IN_IGNORED;
|
||||
|
||||
IN_CLOSE;
|
||||
IN_MOVE;
|
||||
|
||||
IN_ONLYDIR;
|
||||
IN_DONT_FOLLOW;
|
||||
|
||||
IN_ISDIR;
|
||||
IN_ONESHOT;
|
||||
IN_ALL_EVENTS;
|
||||
}
|
||||
}
|
||||
|
||||
libc_bitflags! {
|
||||
/// Configuration options for [`inotify_init1`](fn.inotify_init1.html).
|
||||
pub struct InitFlags: c_int {
|
||||
IN_CLOEXEC;
|
||||
IN_NONBLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
/// An inotify instance. This is also a file descriptor, you can feed it to
|
||||
/// other interfaces consuming file descriptors, epoll for example.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Inotify {
|
||||
fd: RawFd
|
||||
}
|
||||
|
||||
/// 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.
|
||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub struct WatchDescriptor {
|
||||
wd: i32
|
||||
}
|
||||
|
||||
/// A single inotify event.
|
||||
///
|
||||
/// For more documentation see, [inotify(7)](https://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.
|
||||
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.
|
||||
pub cookie: u32,
|
||||
/// Filename. This field exists only if the event was triggered for a file
|
||||
/// inside the watched directory.
|
||||
pub name: Option<OsString>
|
||||
}
|
||||
|
||||
impl Inotify {
|
||||
/// Initialize a new inotify instance.
|
||||
///
|
||||
/// 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).
|
||||
pub fn init(flags: InitFlags) -> Result<Inotify> {
|
||||
let res = Errno::result(unsafe {
|
||||
libc::inotify_init1(flags.bits())
|
||||
});
|
||||
|
||||
res.map(|fd| Inotify { fd })
|
||||
}
|
||||
|
||||
/// Adds a new watch on the target file or directory.
|
||||
///
|
||||
/// 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).
|
||||
pub fn add_watch<P: ?Sized + NixPath>(self,
|
||||
path: &P,
|
||||
mask: AddWatchFlags)
|
||||
-> Result<WatchDescriptor>
|
||||
{
|
||||
let res = path.with_nix_path(|cstr| {
|
||||
unsafe {
|
||||
libc::inotify_add_watch(self.fd, cstr.as_ptr(), mask.bits())
|
||||
}
|
||||
})?;
|
||||
|
||||
Errno::result(res).map(|wd| WatchDescriptor { wd })
|
||||
}
|
||||
|
||||
/// Removes an existing watch using the watch descriptor returned by
|
||||
/// inotify_add_watch.
|
||||
///
|
||||
/// 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).
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn rm_watch(self, wd: WatchDescriptor) -> Result<()> {
|
||||
let res = unsafe { libc::inotify_rm_watch(self.fd, wd.wd) };
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
pub fn rm_watch(self, wd: WatchDescriptor) -> Result<()> {
|
||||
let res = unsafe { libc::inotify_rm_watch(self.fd, wd.wd as u32) };
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// 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>> {
|
||||
let header_size = size_of::<libc::inotify_event>();
|
||||
const BUFSIZ: usize = 4096;
|
||||
let mut buffer = [0u8; BUFSIZ];
|
||||
let mut events = Vec::new();
|
||||
let mut offset = 0;
|
||||
|
||||
let nread = read(self.fd, &mut buffer)?;
|
||||
|
||||
while (nread - offset) >= header_size {
|
||||
let event = unsafe {
|
||||
let mut event = MaybeUninit::<libc::inotify_event>::uninit();
|
||||
ptr::copy_nonoverlapping(
|
||||
buffer.as_ptr().add(offset),
|
||||
event.as_mut_ptr() as *mut u8,
|
||||
(BUFSIZ - offset).min(header_size)
|
||||
);
|
||||
event.assume_init()
|
||||
};
|
||||
|
||||
let name = match event.len {
|
||||
0 => None,
|
||||
_ => {
|
||||
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())
|
||||
}
|
||||
};
|
||||
|
||||
events.push(InotifyEvent {
|
||||
wd: WatchDescriptor { wd: event.wd },
|
||||
mask: AddWatchFlags::from_bits_truncate(event.mask),
|
||||
cookie: event.cookie,
|
||||
name
|
||||
});
|
||||
|
||||
offset += header_size + event.len as usize;
|
||||
}
|
||||
|
||||
Ok(events)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Inotify {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.fd
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for Inotify {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||
Inotify { fd }
|
||||
}
|
||||
}
|
109
vendor/nix-v0.23.1-patched/src/sys/ioctl/bsd.rs
vendored
109
vendor/nix-v0.23.1-patched/src/sys/ioctl/bsd.rs
vendored
|
@ -1,109 +0,0 @@
|
|||
/// 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;
|
||||
|
||||
mod consts {
|
||||
use crate::sys::ioctl::ioctl_num_type;
|
||||
#[doc(hidden)]
|
||||
pub const VOID: ioctl_num_type = 0x2000_0000;
|
||||
#[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;
|
||||
#[doc(hidden)]
|
||||
pub const IOCPARM_MASK: ioctl_num_type = 0x1fff;
|
||||
}
|
||||
|
||||
pub use self::consts::*;
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! ioc {
|
||||
($inout:expr, $group:expr, $num:expr, $len:expr) => (
|
||||
$inout | (($len as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::IOCPARM_MASK) << 16) | (($group as $crate::sys::ioctl::ioctl_num_type) << 8) | ($num as $crate::sys::ioctl::ioctl_num_type)
|
||||
)
|
||||
}
|
||||
|
||||
/// Generate an ioctl request code for a command that passes no data.
|
||||
///
|
||||
/// This is equivalent to the `_IO()` macro exposed by the C ioctl API.
|
||||
///
|
||||
/// You should only use this macro directly if the `ioctl` you're working
|
||||
/// with is "bad" and you cannot use `ioctl_none!()` directly.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate nix;
|
||||
/// const KVMIO: u8 = 0xAE;
|
||||
/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03));
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! request_code_none {
|
||||
($g:expr, $n:expr) => (ioc!($crate::sys::ioctl::VOID, $g, $n, 0))
|
||||
}
|
||||
|
||||
/// Generate an ioctl request code for a command that passes an integer
|
||||
///
|
||||
/// This is equivalent to the `_IOWINT()` macro exposed by the C ioctl API.
|
||||
///
|
||||
/// You should only use this macro directly if the `ioctl` you're working
|
||||
/// with is "bad" and you cannot use `ioctl_write_int!()` directly.
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! request_code_write_int {
|
||||
($g:expr, $n:expr) => (ioc!($crate::sys::ioctl::VOID, $g, $n, ::std::mem::size_of::<$crate::libc::c_int>()))
|
||||
}
|
||||
|
||||
/// Generate an ioctl request code for a command that reads.
|
||||
///
|
||||
/// This is equivalent to the `_IOR()` macro exposed by the C ioctl API.
|
||||
///
|
||||
/// You should only use this macro directly if the `ioctl` you're working
|
||||
/// with is "bad" and you cannot use `ioctl_read!()` directly.
|
||||
///
|
||||
/// The read/write direction is relative to userland, so this
|
||||
/// command would be userland is reading and the kernel is
|
||||
/// writing.
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! request_code_read {
|
||||
($g:expr, $n:expr, $len:expr) => (ioc!($crate::sys::ioctl::OUT, $g, $n, $len))
|
||||
}
|
||||
|
||||
/// Generate an ioctl request code for a command that writes.
|
||||
///
|
||||
/// This is equivalent to the `_IOW()` macro exposed by the C ioctl API.
|
||||
///
|
||||
/// You should only use this macro directly if the `ioctl` you're working
|
||||
/// with is "bad" and you cannot use `ioctl_write!()` directly.
|
||||
///
|
||||
/// The read/write direction is relative to userland, so this
|
||||
/// command would be userland is writing and the kernel is
|
||||
/// reading.
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! request_code_write {
|
||||
($g:expr, $n:expr, $len:expr) => (ioc!($crate::sys::ioctl::IN, $g, $n, $len))
|
||||
}
|
||||
|
||||
/// Generate an ioctl request code for a command that reads and writes.
|
||||
///
|
||||
/// This is equivalent to the `_IOWR()` macro exposed by the C ioctl API.
|
||||
///
|
||||
/// You should only use this macro directly if the `ioctl` you're working
|
||||
/// with is "bad" and you cannot use `ioctl_readwrite!()` directly.
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! request_code_readwrite {
|
||||
($g:expr, $n:expr, $len:expr) => (ioc!($crate::sys::ioctl::INOUT, $g, $n, $len))
|
||||
}
|
141
vendor/nix-v0.23.1-patched/src/sys/ioctl/linux.rs
vendored
141
vendor/nix-v0.23.1-patched/src/sys/ioctl/linux.rs
vendored
|
@ -1,141 +0,0 @@
|
|||
/// The datatype used for the ioctl number
|
||||
#[cfg(any(target_os = "android", target_env = "musl"))]
|
||||
#[doc(hidden)]
|
||||
pub type ioctl_num_type = ::libc::c_int;
|
||||
#[cfg(not(any(target_os = "android", target_env = "musl")))]
|
||||
#[doc(hidden)]
|
||||
pub type ioctl_num_type = ::libc::c_ulong;
|
||||
/// The datatype used for the 3rd argument
|
||||
#[doc(hidden)]
|
||||
pub type ioctl_param_type = ::libc::c_ulong;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub const NRBITS: ioctl_num_type = 8;
|
||||
#[doc(hidden)]
|
||||
pub const TYPEBITS: ioctl_num_type = 8;
|
||||
|
||||
#[cfg(any(target_arch = "mips", target_arch = "mips64", target_arch = "powerpc", target_arch = "powerpc64", target_arch = "sparc64"))]
|
||||
mod consts {
|
||||
#[doc(hidden)]
|
||||
pub const NONE: u8 = 1;
|
||||
#[doc(hidden)]
|
||||
pub const READ: u8 = 2;
|
||||
#[doc(hidden)]
|
||||
pub const WRITE: u8 = 4;
|
||||
#[doc(hidden)]
|
||||
pub const SIZEBITS: u8 = 13;
|
||||
#[doc(hidden)]
|
||||
pub const DIRBITS: u8 = 3;
|
||||
}
|
||||
|
||||
// "Generic" ioctl protocol
|
||||
#[cfg(any(target_arch = "x86",
|
||||
target_arch = "arm",
|
||||
target_arch = "s390x",
|
||||
target_arch = "x86_64",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "riscv64"))]
|
||||
mod consts {
|
||||
#[doc(hidden)]
|
||||
pub const NONE: u8 = 0;
|
||||
#[doc(hidden)]
|
||||
pub const READ: u8 = 2;
|
||||
#[doc(hidden)]
|
||||
pub const WRITE: u8 = 1;
|
||||
#[doc(hidden)]
|
||||
pub const SIZEBITS: u8 = 14;
|
||||
#[doc(hidden)]
|
||||
pub const DIRBITS: u8 = 2;
|
||||
}
|
||||
|
||||
pub use self::consts::*;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub const NRSHIFT: ioctl_num_type = 0;
|
||||
#[doc(hidden)]
|
||||
pub const TYPESHIFT: ioctl_num_type = NRSHIFT + NRBITS as ioctl_num_type;
|
||||
#[doc(hidden)]
|
||||
pub const SIZESHIFT: ioctl_num_type = TYPESHIFT + TYPEBITS as ioctl_num_type;
|
||||
#[doc(hidden)]
|
||||
pub const DIRSHIFT: ioctl_num_type = SIZESHIFT + SIZEBITS as ioctl_num_type;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub const NRMASK: ioctl_num_type = (1 << NRBITS) - 1;
|
||||
#[doc(hidden)]
|
||||
pub const TYPEMASK: ioctl_num_type = (1 << TYPEBITS) - 1;
|
||||
#[doc(hidden)]
|
||||
pub const SIZEMASK: ioctl_num_type = (1 << SIZEBITS) - 1;
|
||||
#[doc(hidden)]
|
||||
pub const DIRMASK: ioctl_num_type = (1 << DIRBITS) - 1;
|
||||
|
||||
/// Encode an ioctl command.
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! ioc {
|
||||
($dir:expr, $ty:expr, $nr:expr, $sz:expr) => (
|
||||
(($dir as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::DIRMASK) << $crate::sys::ioctl::DIRSHIFT) |
|
||||
(($ty as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::TYPEMASK) << $crate::sys::ioctl::TYPESHIFT) |
|
||||
(($nr as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::NRMASK) << $crate::sys::ioctl::NRSHIFT) |
|
||||
(($sz as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::SIZEMASK) << $crate::sys::ioctl::SIZESHIFT))
|
||||
}
|
||||
|
||||
/// Generate an ioctl request code for a command that passes no data.
|
||||
///
|
||||
/// This is equivalent to the `_IO()` macro exposed by the C ioctl API.
|
||||
///
|
||||
/// You should only use this macro directly if the `ioctl` you're working
|
||||
/// with is "bad" and you cannot use `ioctl_none!()` directly.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate nix;
|
||||
/// const KVMIO: u8 = 0xAE;
|
||||
/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03));
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! request_code_none {
|
||||
($ty:expr, $nr:expr) => (ioc!($crate::sys::ioctl::NONE, $ty, $nr, 0))
|
||||
}
|
||||
|
||||
/// Generate an ioctl request code for a command that reads.
|
||||
///
|
||||
/// This is equivalent to the `_IOR()` macro exposed by the C ioctl API.
|
||||
///
|
||||
/// You should only use this macro directly if the `ioctl` you're working
|
||||
/// with is "bad" and you cannot use `ioctl_read!()` directly.
|
||||
///
|
||||
/// The read/write direction is relative to userland, so this
|
||||
/// command would be userland is reading and the kernel is
|
||||
/// writing.
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! request_code_read {
|
||||
($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::READ, $ty, $nr, $sz))
|
||||
}
|
||||
|
||||
/// Generate an ioctl request code for a command that writes.
|
||||
///
|
||||
/// This is equivalent to the `_IOW()` macro exposed by the C ioctl API.
|
||||
///
|
||||
/// You should only use this macro directly if the `ioctl` you're working
|
||||
/// with is "bad" and you cannot use `ioctl_write!()` directly.
|
||||
///
|
||||
/// The read/write direction is relative to userland, so this
|
||||
/// command would be userland is writing and the kernel is
|
||||
/// reading.
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! request_code_write {
|
||||
($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::WRITE, $ty, $nr, $sz))
|
||||
}
|
||||
|
||||
/// Generate an ioctl request code for a command that reads and writes.
|
||||
///
|
||||
/// This is equivalent to the `_IOWR()` macro exposed by the C ioctl API.
|
||||
///
|
||||
/// You should only use this macro directly if the `ioctl` you're working
|
||||
/// with is "bad" and you cannot use `ioctl_readwrite!()` directly.
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! request_code_readwrite {
|
||||
($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::READ | $crate::sys::ioctl::WRITE, $ty, $nr, $sz))
|
||||
}
|
778
vendor/nix-v0.23.1-patched/src/sys/ioctl/mod.rs
vendored
778
vendor/nix-v0.23.1-patched/src/sys/ioctl/mod.rs
vendored
|
@ -1,778 +0,0 @@
|
|||
//! Provide helpers for making ioctl system calls.
|
||||
//!
|
||||
//! This library is pretty low-level and messy. `ioctl` is not fun.
|
||||
//!
|
||||
//! What is an `ioctl`?
|
||||
//! ===================
|
||||
//!
|
||||
//! The `ioctl` syscall is the grab-bag syscall on POSIX systems. Don't want to add a new
|
||||
//! syscall? Make it an `ioctl`! `ioctl` refers to both the syscall, and the commands that can be
|
||||
//! sent with it. `ioctl` stands for "IO control", and the commands are always sent to a file
|
||||
//! descriptor.
|
||||
//!
|
||||
//! It is common to see `ioctl`s used for the following purposes:
|
||||
//!
|
||||
//! * Provide read/write access to out-of-band data related to a device such as configuration
|
||||
//! (for instance, setting serial port options)
|
||||
//! * Provide a mechanism for performing full-duplex data transfers (for instance, xfer on SPI
|
||||
//! devices).
|
||||
//! * Provide access to control functions on a device (for example, on Linux you can send
|
||||
//! commands like pause, resume, and eject to the CDROM device.
|
||||
//! * Do whatever else the device driver creator thought made most sense.
|
||||
//!
|
||||
//! `ioctl`s are synchronous system calls and are similar to read and write calls in that regard.
|
||||
//! They operate on file descriptors and have an identifier that specifies what the ioctl is.
|
||||
//! Additionally they may read or write data and therefore need to pass along a data pointer.
|
||||
//! Besides the semantics of the ioctls being confusing, the generation of this identifer can also
|
||||
//! be difficult.
|
||||
//!
|
||||
//! Historically `ioctl` numbers were arbitrary hard-coded values. In Linux (before 2.6) and some
|
||||
//! unices this has changed to a more-ordered system where the ioctl numbers are partitioned into
|
||||
//! subcomponents (For linux this is documented in
|
||||
//! [`Documentation/ioctl/ioctl-number.rst`](https://elixir.bootlin.com/linux/latest/source/Documentation/userspace-api/ioctl/ioctl-number.rst)):
|
||||
//!
|
||||
//! * Number: The actual ioctl ID
|
||||
//! * Type: A grouping of ioctls for a common purpose or driver
|
||||
//! * Size: The size in bytes of the data that will be transferred
|
||||
//! * Direction: Whether there is any data and if it's read, write, or both
|
||||
//!
|
||||
//! Newer drivers should not generate complete integer identifiers for their `ioctl`s instead
|
||||
//! preferring to use the 4 components above to generate the final ioctl identifier. Because of
|
||||
//! how old `ioctl`s are, however, there are many hard-coded `ioctl` identifiers. These are
|
||||
//! commonly referred to as "bad" in `ioctl` documentation.
|
||||
//!
|
||||
//! Defining `ioctl`s
|
||||
//! =================
|
||||
//!
|
||||
//! This library provides several `ioctl_*!` macros for binding `ioctl`s. These generate public
|
||||
//! unsafe functions that can then be used for calling the ioctl. This macro has a few different
|
||||
//! ways it can be used depending on the specific ioctl you're working with.
|
||||
//!
|
||||
//! A simple `ioctl` is `SPI_IOC_RD_MODE`. This ioctl works with the SPI interface on Linux. This
|
||||
//! specific `ioctl` reads the mode of the SPI device as a `u8`. It's declared in
|
||||
//! `/include/uapi/linux/spi/spidev.h` as `_IOR(SPI_IOC_MAGIC, 1, __u8)`. Since it uses the `_IOR`
|
||||
//! macro, we know it's a `read` ioctl and can use the `ioctl_read!` macro as follows:
|
||||
//!
|
||||
//! ```
|
||||
//! # #[macro_use] extern crate nix;
|
||||
//! const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
|
||||
//! const SPI_IOC_TYPE_MODE: u8 = 1;
|
||||
//! ioctl_read!(spi_read_mode, SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, u8);
|
||||
//! # fn main() {}
|
||||
//! ```
|
||||
//!
|
||||
//! This generates the function:
|
||||
//!
|
||||
//! ```
|
||||
//! # #[macro_use] extern crate nix;
|
||||
//! # use std::mem;
|
||||
//! # use nix::{libc, Result};
|
||||
//! # use nix::errno::Errno;
|
||||
//! # use nix::libc::c_int as c_int;
|
||||
//! # const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
|
||||
//! # const SPI_IOC_TYPE_MODE: u8 = 1;
|
||||
//! pub unsafe fn spi_read_mode(fd: c_int, data: *mut u8) -> Result<c_int> {
|
||||
//! let res = libc::ioctl(fd, request_code_read!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, mem::size_of::<u8>()), data);
|
||||
//! Errno::result(res)
|
||||
//! }
|
||||
//! # fn main() {}
|
||||
//! ```
|
||||
//!
|
||||
//! The return value for the wrapper functions generated by the `ioctl_*!` macros are `nix::Error`s.
|
||||
//! These are generated by assuming the return value of the ioctl is `-1` on error and everything
|
||||
//! else is a valid return value. If this is not the case, `Result::map` can be used to map some
|
||||
//! of the range of "good" values (-Inf..-2, 0..Inf) into a smaller range in a helper function.
|
||||
//!
|
||||
//! Writing `ioctl`s generally use pointers as their data source and these should use the
|
||||
//! `ioctl_write_ptr!`. But in some cases an `int` is passed directly. For these `ioctl`s use the
|
||||
//! `ioctl_write_int!` macro. This variant does not take a type as the last argument:
|
||||
//!
|
||||
//! ```
|
||||
//! # #[macro_use] extern crate nix;
|
||||
//! const HCI_IOC_MAGIC: u8 = b'k';
|
||||
//! const HCI_IOC_HCIDEVUP: u8 = 1;
|
||||
//! ioctl_write_int!(hci_dev_up, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP);
|
||||
//! # fn main() {}
|
||||
//! ```
|
||||
//!
|
||||
//! Some `ioctl`s don't transfer any data, and those should use `ioctl_none!`. This macro
|
||||
//! doesn't take a type and so it is declared similar to the `write_int` variant shown above.
|
||||
//!
|
||||
//! The mode for a given `ioctl` should be clear from the documentation if it has good
|
||||
//! documentation. Otherwise it will be clear based on the macro used to generate the `ioctl`
|
||||
//! number where `_IO`, `_IOR`, `_IOW`, and `_IOWR` map to "none", "read", "write_*", and "readwrite"
|
||||
//! 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
|
||||
//! large number of `ioctl`s and describes their argument data type.
|
||||
//!
|
||||
//! Using "bad" `ioctl`s
|
||||
//! --------------------
|
||||
//!
|
||||
//! As mentioned earlier, there are many old `ioctl`s that do not use the newer method of
|
||||
//! generating `ioctl` numbers and instead use hardcoded values. These can be used with the
|
||||
//! `ioctl_*_bad!` macros. This naming comes from the Linux kernel which refers to these
|
||||
//! `ioctl`s as "bad". These are a different variant as they bypass calling the macro that generates
|
||||
//! the ioctl number and instead use the defined value directly.
|
||||
//!
|
||||
//! For example the `TCGETS` `ioctl` reads a `termios` data structure for a given file descriptor.
|
||||
//! It's defined as `0x5401` in `ioctls.h` on Linux and can be implemented as:
|
||||
//!
|
||||
//! ```
|
||||
//! # #[macro_use] extern crate nix;
|
||||
//! # #[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
//! # use nix::libc::TCGETS as TCGETS;
|
||||
//! # #[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
//! # use nix::libc::termios as termios;
|
||||
//! # #[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
//! ioctl_read_bad!(tcgets, TCGETS, termios);
|
||||
//! # fn main() {}
|
||||
//! ```
|
||||
//!
|
||||
//! The generated function has the same form as that generated by `ioctl_read!`:
|
||||
//!
|
||||
//! ```text
|
||||
//! pub unsafe fn tcgets(fd: c_int, data: *mut termios) -> Result<c_int>;
|
||||
//! ```
|
||||
//!
|
||||
//! Working with Arrays
|
||||
//! -------------------
|
||||
//!
|
||||
//! Some `ioctl`s work with entire arrays of elements. These are supported by the `ioctl_*_buf`
|
||||
//! family of macros: `ioctl_read_buf`, `ioctl_write_buf`, and `ioctl_readwrite_buf`. Note that
|
||||
//! there are no "bad" versions for working with buffers. The generated functions include a `len`
|
||||
//! argument to specify the number of elements (where the type of each element is specified in the
|
||||
//! macro).
|
||||
//!
|
||||
//! Again looking to the SPI `ioctl`s on Linux for an example, there is a `SPI_IOC_MESSAGE` `ioctl`
|
||||
//! that queues up multiple SPI messages by writing an entire array of `spi_ioc_transfer` structs.
|
||||
//! `linux/spi/spidev.h` defines a macro to calculate the `ioctl` number like:
|
||||
//!
|
||||
//! ```C
|
||||
//! #define SPI_IOC_MAGIC 'k'
|
||||
//! #define SPI_MSGSIZE(N) ...
|
||||
//! #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
|
||||
//! ```
|
||||
//!
|
||||
//! The `SPI_MSGSIZE(N)` calculation is already handled by the `ioctl_*!` macros, so all that's
|
||||
//! needed to define this `ioctl` is:
|
||||
//!
|
||||
//! ```
|
||||
//! # #[macro_use] extern crate nix;
|
||||
//! const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
|
||||
//! const SPI_IOC_TYPE_MESSAGE: u8 = 0;
|
||||
//! # pub struct spi_ioc_transfer(u64);
|
||||
//! ioctl_write_buf!(spi_transfer, SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, spi_ioc_transfer);
|
||||
//! # fn main() {}
|
||||
//! ```
|
||||
//!
|
||||
//! This generates a function like:
|
||||
//!
|
||||
//! ```
|
||||
//! # #[macro_use] extern crate nix;
|
||||
//! # use std::mem;
|
||||
//! # use nix::{libc, Result};
|
||||
//! # use nix::errno::Errno;
|
||||
//! # use nix::libc::c_int as c_int;
|
||||
//! # const SPI_IOC_MAGIC: u8 = b'k';
|
||||
//! # const SPI_IOC_TYPE_MESSAGE: u8 = 0;
|
||||
//! # pub struct spi_ioc_transfer(u64);
|
||||
//! pub unsafe fn spi_message(fd: c_int, data: &mut [spi_ioc_transfer]) -> Result<c_int> {
|
||||
//! let res = libc::ioctl(fd,
|
||||
//! request_code_write!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, data.len() * mem::size_of::<spi_ioc_transfer>()),
|
||||
//! data);
|
||||
//! Errno::result(res)
|
||||
//! }
|
||||
//! # fn main() {}
|
||||
//! ```
|
||||
//!
|
||||
//! Finding `ioctl` Documentation
|
||||
//! -----------------------------
|
||||
//!
|
||||
//! For Linux, look at your system's headers. For example, `/usr/include/linux/input.h` has a lot
|
||||
//! of lines defining macros which use `_IO`, `_IOR`, `_IOW`, `_IOC`, and `_IOWR`. Some `ioctl`s are
|
||||
//! documented directly in the headers defining their constants, but others have more extensive
|
||||
//! documentation in man pages (like termios' `ioctl`s which are in `tty_ioctl(4)`).
|
||||
//!
|
||||
//! Documenting the Generated Functions
|
||||
//! ===================================
|
||||
//!
|
||||
//! In many cases, users will wish for the functions generated by the `ioctl`
|
||||
//! macro to be public and documented. For this reason, the generated functions
|
||||
//! are public by default. If you wish to hide the ioctl, you will need to put
|
||||
//! them in a private module.
|
||||
//!
|
||||
//! For documentation, it is possible to use doc comments inside the `ioctl_*!` macros. Here is an
|
||||
//! example :
|
||||
//!
|
||||
//! ```
|
||||
//! # #[macro_use] extern crate nix;
|
||||
//! # use nix::libc::c_int;
|
||||
//! ioctl_read! {
|
||||
//! /// Make the given terminal the controlling terminal of the calling process. The calling
|
||||
//! /// process must be a session leader and not have a controlling terminal already. If the
|
||||
//! /// terminal is already the controlling terminal of a different session group then the
|
||||
//! /// ioctl will fail with **EPERM**, unless the caller is root (more precisely: has the
|
||||
//! /// **CAP_SYS_ADMIN** capability) and arg equals 1, in which case the terminal is stolen
|
||||
//! /// and all processes that had it as controlling terminal lose it.
|
||||
//! tiocsctty, b't', 19, c_int
|
||||
//! }
|
||||
//!
|
||||
//! # fn main() {}
|
||||
//! ```
|
||||
use cfg_if::cfg_if;
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
|
||||
#[macro_use]
|
||||
mod linux;
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
|
||||
pub use self::linux::*;
|
||||
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "illumos",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"))]
|
||||
#[macro_use]
|
||||
mod bsd;
|
||||
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "illumos",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"))]
|
||||
pub use self::bsd::*;
|
||||
|
||||
/// Convert raw ioctl return value to a Nix result
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! convert_ioctl_res {
|
||||
($w:expr) => (
|
||||
{
|
||||
$crate::errno::Errno::result($w)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/// Generates a wrapper function for an ioctl that passes no data to the kernel.
|
||||
///
|
||||
/// The arguments to this macro are:
|
||||
///
|
||||
/// * The function name
|
||||
/// * The ioctl identifier
|
||||
/// * The ioctl sequence number
|
||||
///
|
||||
/// The generated function has the following signature:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int) -> Result<libc::c_int>
|
||||
/// ```
|
||||
///
|
||||
/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// The `videodev2` driver on Linux defines the `log_status` `ioctl` as:
|
||||
///
|
||||
/// ```C
|
||||
/// #define VIDIOC_LOG_STATUS _IO('V', 70)
|
||||
/// ```
|
||||
///
|
||||
/// This can be implemented in Rust like:
|
||||
///
|
||||
/// ```no_run
|
||||
/// # #[macro_use] extern crate nix;
|
||||
/// ioctl_none!(log_status, b'V', 70);
|
||||
/// fn main() {}
|
||||
/// ```
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! ioctl_none {
|
||||
($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => (
|
||||
$(#[$attr])*
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int)
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_none!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// Generates a wrapper function for a "bad" ioctl that passes no data to the kernel.
|
||||
///
|
||||
/// The arguments to this macro are:
|
||||
///
|
||||
/// * The function name
|
||||
/// * The ioctl request code
|
||||
///
|
||||
/// The generated function has the following signature:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int) -> Result<libc::c_int>
|
||||
/// ```
|
||||
///
|
||||
/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// # #[macro_use] extern crate nix;
|
||||
/// # use libc::TIOCNXCL;
|
||||
/// # use std::fs::File;
|
||||
/// # use std::os::unix::io::AsRawFd;
|
||||
/// ioctl_none_bad!(tiocnxcl, TIOCNXCL);
|
||||
/// fn main() {
|
||||
/// let file = File::open("/dev/ttyUSB0").unwrap();
|
||||
/// unsafe { tiocnxcl(file.as_raw_fd()) }.unwrap();
|
||||
/// }
|
||||
/// ```
|
||||
// TODO: add an example using request_code_*!()
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! ioctl_none_bad {
|
||||
($(#[$attr:meta])* $name:ident, $nr:expr) => (
|
||||
$(#[$attr])*
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int)
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// Generates a wrapper function for an ioctl that reads data from the kernel.
|
||||
///
|
||||
/// The arguments to this macro are:
|
||||
///
|
||||
/// * The function name
|
||||
/// * The ioctl identifier
|
||||
/// * The ioctl sequence number
|
||||
/// * The data type passed by this ioctl
|
||||
///
|
||||
/// The generated function has the following signature:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int>
|
||||
/// ```
|
||||
///
|
||||
/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate nix;
|
||||
/// const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
|
||||
/// const SPI_IOC_TYPE_MODE: u8 = 1;
|
||||
/// ioctl_read!(spi_read_mode, SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, u8);
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! ioctl_read {
|
||||
($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
|
||||
$(#[$attr])*
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int,
|
||||
data: *mut $ty)
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// Generates a wrapper function for a "bad" ioctl that reads data from the kernel.
|
||||
///
|
||||
/// The arguments to this macro are:
|
||||
///
|
||||
/// * The function name
|
||||
/// * The ioctl request code
|
||||
/// * The data type passed by this ioctl
|
||||
///
|
||||
/// The generated function has the following signature:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int>
|
||||
/// ```
|
||||
///
|
||||
/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate nix;
|
||||
/// # #[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
/// ioctl_read_bad!(tcgets, libc::TCGETS, libc::termios);
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! ioctl_read_bad {
|
||||
($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => (
|
||||
$(#[$attr])*
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int,
|
||||
data: *mut $ty)
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// Generates a wrapper function for an ioctl that writes data through a pointer to the kernel.
|
||||
///
|
||||
/// The arguments to this macro are:
|
||||
///
|
||||
/// * The function name
|
||||
/// * The ioctl identifier
|
||||
/// * The ioctl sequence number
|
||||
/// * The data type passed by this ioctl
|
||||
///
|
||||
/// The generated function has the following signature:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *const DATA_TYPE) -> Result<libc::c_int>
|
||||
/// ```
|
||||
///
|
||||
/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate nix;
|
||||
/// # pub struct v4l2_audio {}
|
||||
/// ioctl_write_ptr!(s_audio, b'V', 34, v4l2_audio);
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! ioctl_write_ptr {
|
||||
($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
|
||||
$(#[$attr])*
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int,
|
||||
data: *const $ty)
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// Generates a wrapper function for a "bad" ioctl that writes data through a pointer to the kernel.
|
||||
///
|
||||
/// The arguments to this macro are:
|
||||
///
|
||||
/// * The function name
|
||||
/// * The ioctl request code
|
||||
/// * The data type passed by this ioctl
|
||||
///
|
||||
/// The generated function has the following signature:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *const DATA_TYPE) -> Result<libc::c_int>
|
||||
/// ```
|
||||
///
|
||||
/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate nix;
|
||||
/// # #[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
/// ioctl_write_ptr_bad!(tcsets, libc::TCSETS, libc::termios);
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! ioctl_write_ptr_bad {
|
||||
($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => (
|
||||
$(#[$attr])*
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int,
|
||||
data: *const $ty)
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
cfg_if!{
|
||||
if #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] {
|
||||
/// Generates a wrapper function for a ioctl that writes an integer to the kernel.
|
||||
///
|
||||
/// The arguments to this macro are:
|
||||
///
|
||||
/// * The function name
|
||||
/// * The ioctl identifier
|
||||
/// * The ioctl sequence number
|
||||
///
|
||||
/// The generated function has the following signature:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: nix::sys::ioctl::ioctl_param_type) -> Result<libc::c_int>
|
||||
/// ```
|
||||
///
|
||||
/// `nix::sys::ioctl::ioctl_param_type` depends on the OS:
|
||||
/// * BSD - `libc::c_int`
|
||||
/// * Linux - `libc::c_ulong`
|
||||
///
|
||||
/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate nix;
|
||||
/// ioctl_write_int!(vt_activate, b'v', 4);
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! ioctl_write_int {
|
||||
($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => (
|
||||
$(#[$attr])*
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int,
|
||||
data: $crate::sys::ioctl::ioctl_param_type)
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write_int!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
/// Generates a wrapper function for a ioctl that writes an integer to the kernel.
|
||||
///
|
||||
/// The arguments to this macro are:
|
||||
///
|
||||
/// * The function name
|
||||
/// * The ioctl identifier
|
||||
/// * The ioctl sequence number
|
||||
///
|
||||
/// The generated function has the following signature:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: nix::sys::ioctl::ioctl_param_type) -> Result<libc::c_int>
|
||||
/// ```
|
||||
///
|
||||
/// `nix::sys::ioctl::ioctl_param_type` depends on the OS:
|
||||
/// * BSD - `libc::c_int`
|
||||
/// * Linux - `libc::c_ulong`
|
||||
///
|
||||
/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate nix;
|
||||
/// const HCI_IOC_MAGIC: u8 = b'k';
|
||||
/// const HCI_IOC_HCIDEVUP: u8 = 1;
|
||||
/// ioctl_write_int!(hci_dev_up, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP);
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! ioctl_write_int {
|
||||
($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => (
|
||||
$(#[$attr])*
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int,
|
||||
data: $crate::sys::ioctl::ioctl_param_type)
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$crate::libc::c_int>()) as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates a wrapper function for a "bad" ioctl that writes an integer to the kernel.
|
||||
///
|
||||
/// The arguments to this macro are:
|
||||
///
|
||||
/// * The function name
|
||||
/// * The ioctl request code
|
||||
///
|
||||
/// The generated function has the following signature:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: libc::c_int) -> Result<libc::c_int>
|
||||
/// ```
|
||||
///
|
||||
/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate nix;
|
||||
/// # #[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
/// ioctl_write_int_bad!(tcsbrk, libc::TCSBRK);
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use] extern crate nix;
|
||||
/// const KVMIO: u8 = 0xAE;
|
||||
/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03));
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! ioctl_write_int_bad {
|
||||
($(#[$attr:meta])* $name:ident, $nr:expr) => (
|
||||
$(#[$attr])*
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int,
|
||||
data: $crate::libc::c_int)
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// Generates a wrapper function for an ioctl that reads and writes data to the kernel.
|
||||
///
|
||||
/// The arguments to this macro are:
|
||||
///
|
||||
/// * The function name
|
||||
/// * The ioctl identifier
|
||||
/// * The ioctl sequence number
|
||||
/// * The data type passed by this ioctl
|
||||
///
|
||||
/// The generated function has the following signature:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int>
|
||||
/// ```
|
||||
///
|
||||
/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate nix;
|
||||
/// # pub struct v4l2_audio {}
|
||||
/// ioctl_readwrite!(enum_audio, b'V', 65, v4l2_audio);
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! ioctl_readwrite {
|
||||
($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
|
||||
$(#[$attr])*
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int,
|
||||
data: *mut $ty)
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// Generates a wrapper function for a "bad" ioctl that reads and writes data to the kernel.
|
||||
///
|
||||
/// The arguments to this macro are:
|
||||
///
|
||||
/// * The function name
|
||||
/// * The ioctl request code
|
||||
/// * The data type passed by this ioctl
|
||||
///
|
||||
/// The generated function has the following signature:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int>
|
||||
/// ```
|
||||
///
|
||||
/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
|
||||
// TODO: Find an example for ioctl_readwrite_bad
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! ioctl_readwrite_bad {
|
||||
($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => (
|
||||
$(#[$attr])*
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int,
|
||||
data: *mut $ty)
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// Generates a wrapper function for an ioctl that reads an array of elements from the kernel.
|
||||
///
|
||||
/// The arguments to this macro are:
|
||||
///
|
||||
/// * The function name
|
||||
/// * The ioctl identifier
|
||||
/// * The ioctl sequence number
|
||||
/// * The data type passed by this ioctl
|
||||
///
|
||||
/// The generated function has the following signature:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &mut [DATA_TYPE]) -> Result<libc::c_int>
|
||||
/// ```
|
||||
///
|
||||
/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
|
||||
// TODO: Find an example for ioctl_read_buf
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! ioctl_read_buf {
|
||||
($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
|
||||
$(#[$attr])*
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int,
|
||||
data: &mut [$ty])
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// Generates a wrapper function for an ioctl that writes an array of elements to the kernel.
|
||||
///
|
||||
/// The arguments to this macro are:
|
||||
///
|
||||
/// * The function name
|
||||
/// * The ioctl identifier
|
||||
/// * The ioctl sequence number
|
||||
/// * The data type passed by this ioctl
|
||||
///
|
||||
/// The generated function has the following signature:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &[DATA_TYPE]) -> Result<libc::c_int>
|
||||
/// ```
|
||||
///
|
||||
/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate nix;
|
||||
/// const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
|
||||
/// const SPI_IOC_TYPE_MESSAGE: u8 = 0;
|
||||
/// # pub struct spi_ioc_transfer(u64);
|
||||
/// ioctl_write_buf!(spi_transfer, SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, spi_ioc_transfer);
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! ioctl_write_buf {
|
||||
($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
|
||||
$(#[$attr])*
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int,
|
||||
data: &[$ty])
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// Generates a wrapper function for an ioctl that reads and writes an array of elements to the kernel.
|
||||
///
|
||||
/// The arguments to this macro are:
|
||||
///
|
||||
/// * The function name
|
||||
/// * The ioctl identifier
|
||||
/// * The ioctl sequence number
|
||||
/// * The data type passed by this ioctl
|
||||
///
|
||||
/// The generated function has the following signature:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &mut [DATA_TYPE]) -> Result<libc::c_int>
|
||||
/// ```
|
||||
///
|
||||
/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
|
||||
// TODO: Find an example for readwrite_buf
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! ioctl_readwrite_buf {
|
||||
($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
|
||||
$(#[$attr])*
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int,
|
||||
data: &mut [$ty])
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
}
|
||||
)
|
||||
}
|
19
vendor/nix-v0.23.1-patched/src/sys/memfd.rs
vendored
19
vendor/nix-v0.23.1-patched/src/sys/memfd.rs
vendored
|
@ -1,19 +0,0 @@
|
|||
use std::os::unix::io::RawFd;
|
||||
use crate::Result;
|
||||
use crate::errno::Errno;
|
||||
use std::ffi::CStr;
|
||||
|
||||
libc_bitflags!(
|
||||
pub struct MemFdCreateFlag: libc::c_uint {
|
||||
MFD_CLOEXEC;
|
||||
MFD_ALLOW_SEALING;
|
||||
}
|
||||
);
|
||||
|
||||
pub fn memfd_create(name: &CStr, flags: MemFdCreateFlag) -> Result<RawFd> {
|
||||
let res = unsafe {
|
||||
libc::syscall(libc::SYS_memfd_create, name.as_ptr(), flags.bits())
|
||||
};
|
||||
|
||||
Errno::result(res).map(|r| r as RawFd)
|
||||
}
|
464
vendor/nix-v0.23.1-patched/src/sys/mman.rs
vendored
464
vendor/nix-v0.23.1-patched/src/sys/mman.rs
vendored
|
@ -1,464 +0,0 @@
|
|||
use crate::Result;
|
||||
#[cfg(not(target_os = "android"))]
|
||||
use crate::NixPath;
|
||||
use crate::errno::Errno;
|
||||
#[cfg(not(target_os = "android"))]
|
||||
use crate::fcntl::OFlag;
|
||||
use libc::{self, c_int, c_void, size_t, off_t};
|
||||
#[cfg(not(target_os = "android"))]
|
||||
use crate::sys::stat::Mode;
|
||||
use std::os::unix::io::RawFd;
|
||||
|
||||
libc_bitflags!{
|
||||
/// Desired memory protection of a memory mapping.
|
||||
pub struct ProtFlags: c_int {
|
||||
/// Pages cannot be accessed.
|
||||
PROT_NONE;
|
||||
/// Pages can be read.
|
||||
PROT_READ;
|
||||
/// Pages can be written.
|
||||
PROT_WRITE;
|
||||
/// Pages can be executed
|
||||
PROT_EXEC;
|
||||
/// Apply protection up to the end of a mapping that grows upwards.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
PROT_GROWSDOWN;
|
||||
/// Apply protection down to the beginning of a mapping that grows downwards.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
PROT_GROWSUP;
|
||||
}
|
||||
}
|
||||
|
||||
libc_bitflags!{
|
||||
/// Additional parameters for `mmap()`.
|
||||
pub struct MapFlags: c_int {
|
||||
/// Compatibility flag. Ignored.
|
||||
MAP_FILE;
|
||||
/// Share this mapping. Mutually exclusive with `MAP_PRIVATE`.
|
||||
MAP_SHARED;
|
||||
/// Create a private copy-on-write mapping. Mutually exclusive with `MAP_SHARED`.
|
||||
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.
|
||||
MAP_ANONYMOUS;
|
||||
/// Put the mapping into the first 2GB of the process address space.
|
||||
#[cfg(any(all(any(target_os = "android", target_os = "linux"),
|
||||
any(target_arch = "x86", target_arch = "x86_64")),
|
||||
all(target_os = "linux", target_env = "musl", any(target_arch = "x86", target_arch = "x86_64")),
|
||||
all(target_os = "freebsd", target_pointer_width = "64")))]
|
||||
MAP_32BIT;
|
||||
/// Used for stacks; indicates to the kernel that the mapping should extend downward in memory.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
MAP_GROWSDOWN;
|
||||
/// Compatibility flag. Ignored.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
MAP_DENYWRITE;
|
||||
/// Compatibility flag. Ignored.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
MAP_EXECUTABLE;
|
||||
/// Mark the mmaped region to be locked in the same way as `mlock(2)`.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
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")))]
|
||||
MAP_NORESERVE;
|
||||
/// Populate page tables for a mapping.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
MAP_POPULATE;
|
||||
/// Only meaningful when used with `MAP_POPULATE`. Don't perform read-ahead.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
MAP_NONBLOCK;
|
||||
/// Allocate the mapping using "huge pages."
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
MAP_HUGETLB;
|
||||
/// Make use of 64KB huge page (must be supported by the system)
|
||||
#[cfg(target_os = "linux")]
|
||||
MAP_HUGE_64KB;
|
||||
/// Make use of 512KB huge page (must be supported by the system)
|
||||
#[cfg(target_os = "linux")]
|
||||
MAP_HUGE_512KB;
|
||||
/// Make use of 1MB huge page (must be supported by the system)
|
||||
#[cfg(target_os = "linux")]
|
||||
MAP_HUGE_1MB;
|
||||
/// Make use of 2MB huge page (must be supported by the system)
|
||||
#[cfg(target_os = "linux")]
|
||||
MAP_HUGE_2MB;
|
||||
/// Make use of 8MB huge page (must be supported by the system)
|
||||
#[cfg(target_os = "linux")]
|
||||
MAP_HUGE_8MB;
|
||||
/// Make use of 16MB huge page (must be supported by the system)
|
||||
#[cfg(target_os = "linux")]
|
||||
MAP_HUGE_16MB;
|
||||
/// Make use of 32MB huge page (must be supported by the system)
|
||||
#[cfg(target_os = "linux")]
|
||||
MAP_HUGE_32MB;
|
||||
/// Make use of 256MB huge page (must be supported by the system)
|
||||
#[cfg(target_os = "linux")]
|
||||
MAP_HUGE_256MB;
|
||||
/// Make use of 512MB huge page (must be supported by the system)
|
||||
#[cfg(target_os = "linux")]
|
||||
MAP_HUGE_512MB;
|
||||
/// Make use of 1GB huge page (must be supported by the system)
|
||||
#[cfg(target_os = "linux")]
|
||||
MAP_HUGE_1GB;
|
||||
/// Make use of 2GB huge page (must be supported by the system)
|
||||
#[cfg(target_os = "linux")]
|
||||
MAP_HUGE_2GB;
|
||||
/// Make use of 16GB huge page (must be supported by the system)
|
||||
#[cfg(target_os = "linux")]
|
||||
MAP_HUGE_16GB;
|
||||
|
||||
/// Lock the mapped region into memory as with `mlock(2)`.
|
||||
#[cfg(target_os = "netbsd")]
|
||||
MAP_WIRED;
|
||||
/// Causes dirtied data in the specified range to be flushed to disk only when necessary.
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
|
||||
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"))]
|
||||
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"))]
|
||||
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 = "freesd")]
|
||||
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"))]
|
||||
libc_bitflags!{
|
||||
/// 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`](./fn.madvise.html).
|
||||
#[repr(i32)]
|
||||
#[non_exhaustive]
|
||||
pub enum MmapAdvise {
|
||||
/// No further special treatment. This is the default.
|
||||
MADV_NORMAL,
|
||||
/// Expect random page references.
|
||||
MADV_RANDOM,
|
||||
/// Expect sequential page references.
|
||||
MADV_SEQUENTIAL,
|
||||
/// Expect access in the near future.
|
||||
MADV_WILLNEED,
|
||||
/// Do not expect access in the near future.
|
||||
MADV_DONTNEED,
|
||||
/// Free up a given range of pages and its associated backing store.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
MADV_REMOVE,
|
||||
/// Do not make pages in this range available to the child after a `fork(2)`.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
MADV_DONTFORK,
|
||||
/// Undo the effect of `MADV_DONTFORK`.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
MADV_DOFORK,
|
||||
/// Poison the given pages.
|
||||
///
|
||||
/// Subsequent references to those pages are treated like hardware memory corruption.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
MADV_HWPOISON,
|
||||
/// Enable Kernel Samepage Merging (KSM) for the given pages.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
MADV_MERGEABLE,
|
||||
/// Undo the effect of `MADV_MERGEABLE`
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
MADV_UNMERGEABLE,
|
||||
/// Preserve the memory of each page but offline the original page.
|
||||
#[cfg(any(target_os = "android",
|
||||
all(target_os = "linux", any(
|
||||
target_arch = "aarch64",
|
||||
target_arch = "arm",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64",
|
||||
target_arch = "s390x",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64",
|
||||
target_arch = "sparc64"))))]
|
||||
MADV_SOFT_OFFLINE,
|
||||
/// Enable Transparent Huge Pages (THP) for pages in the given range.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
MADV_HUGEPAGE,
|
||||
/// Undo the effect of `MADV_HUGEPAGE`.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
MADV_NOHUGEPAGE,
|
||||
/// Exclude the given range from a core dump.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
MADV_DONTDUMP,
|
||||
/// Undo the effect of an earlier `MADV_DONTDUMP`.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
MADV_DODUMP,
|
||||
/// Specify that the application no longer needs the pages in the given range.
|
||||
MADV_FREE,
|
||||
/// Request that the system not flush the current range to disk unless it needs to.
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
|
||||
MADV_NOSYNC,
|
||||
/// Undoes the effects of `MADV_NOSYNC` for any future pages dirtied within the given range.
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
|
||||
MADV_AUTOSYNC,
|
||||
/// Region is not included in a core file.
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
|
||||
MADV_NOCORE,
|
||||
/// Include region in a core file
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
|
||||
MADV_CORE,
|
||||
#[cfg(any(target_os = "freebsd"))]
|
||||
MADV_PROTECT,
|
||||
/// Invalidate the hardware page table for the given region.
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
MADV_INVAL,
|
||||
/// Set the offset of the page directory page to `value` for the virtual page table.
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
MADV_SETMAP,
|
||||
/// Indicates that the application will not need the data in the given range.
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
MADV_ZERO_WIRED_PAGES,
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
MADV_FREE_REUSABLE,
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
MADV_FREE_REUSE,
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
MADV_CAN_REUSE,
|
||||
}
|
||||
}
|
||||
|
||||
libc_bitflags!{
|
||||
/// Configuration flags for `msync`.
|
||||
pub struct MsFlags: c_int {
|
||||
/// Schedule an update but return immediately.
|
||||
MS_ASYNC;
|
||||
/// Invalidate all cached data.
|
||||
MS_INVALIDATE;
|
||||
/// Invalidate pages, but leave them mapped.
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
MS_KILLPAGES;
|
||||
/// Deactivate pages, but leave them mapped.
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
MS_DEACTIVATE;
|
||||
/// Perform an update and wait for it to complete.
|
||||
MS_SYNC;
|
||||
}
|
||||
}
|
||||
|
||||
libc_bitflags!{
|
||||
/// Flags for `mlockall`.
|
||||
pub struct MlockAllFlags: c_int {
|
||||
/// Lock pages that are currently mapped into the address space of the process.
|
||||
MCL_CURRENT;
|
||||
/// Lock pages which will become mapped into the address space of the process in the future.
|
||||
MCL_FUTURE;
|
||||
}
|
||||
}
|
||||
|
||||
/// Locks all memory pages that contain part of the address range with `length`
|
||||
/// bytes starting at `addr`.
|
||||
///
|
||||
/// Locked pages never move to the swap area.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `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)
|
||||
}
|
||||
|
||||
/// Unlocks all memory pages that contain part of the address range with
|
||||
/// `length` bytes starting at `addr`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `addr` must meet all the requirements described in the `munlock(2)` man
|
||||
/// page.
|
||||
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.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `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.
|
||||
pub fn munlockall() -> Result<()> {
|
||||
unsafe { Errno::result(libc::munlockall()) }.map(drop)
|
||||
}
|
||||
|
||||
/// allocate memory, or map files or devices into memory
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// 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())
|
||||
} else {
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
||||
|
||||
/// Expands (or shrinks) an existing memory mapping, potentially moving it at
|
||||
/// the same time.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// See the `mremap(2)` [man page](https://man7.org/linux/man-pages/man2/mremap.2.html) for
|
||||
/// detailed requirements.
|
||||
#[cfg(any(target_os = "linux", target_os = "netbsd"))]
|
||||
pub unsafe fn mremap(
|
||||
addr: *mut c_void,
|
||||
old_size: size_t,
|
||||
new_size: size_t,
|
||||
flags: MRemapFlags,
|
||||
new_address: Option<* mut c_void>,
|
||||
) -> Result<*mut c_void> {
|
||||
#[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())
|
||||
} else {
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
||||
|
||||
/// remove a mapping
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `addr` must meet all the requirements described in the `munmap(2)` man
|
||||
/// page.
|
||||
pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> {
|
||||
Errno::result(libc::munmap(addr, len)).map(drop)
|
||||
}
|
||||
|
||||
/// give advice about use of memory
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// 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
|
||||
/// details.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Calls to `mprotect` are inherently unsafe, as changes to memory protections can lead to
|
||||
/// SIGSEGVs.
|
||||
///
|
||||
/// ```
|
||||
/// # use nix::libc::size_t;
|
||||
/// # use nix::sys::mman::{mmap, mprotect, MapFlags, ProtFlags};
|
||||
/// # use std::ptr;
|
||||
/// const ONE_K: size_t = 1024;
|
||||
/// let mut slice: &mut [u8] = unsafe {
|
||||
/// let mem = mmap(ptr::null_mut(), ONE_K, ProtFlags::PROT_NONE,
|
||||
/// MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, -1, 0).unwrap();
|
||||
/// mprotect(mem, ONE_K, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE).unwrap();
|
||||
/// std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K)
|
||||
/// };
|
||||
/// assert_eq!(slice[0], 0x00);
|
||||
/// slice[0] = 0xFF;
|
||||
/// assert_eq!(slice[0], 0xFF);
|
||||
/// ```
|
||||
pub unsafe fn mprotect(addr: *mut c_void, length: size_t, prot: ProtFlags) -> Result<()> {
|
||||
Errno::result(libc::mprotect(addr, length, prot.bits())).map(drop)
|
||||
}
|
||||
|
||||
/// synchronize a mapped region
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `addr` must meet all the requirements described in the `msync(2)` man
|
||||
/// page.
|
||||
pub unsafe fn msync(addr: *mut c_void, length: size_t, flags: MsFlags) -> Result<()> {
|
||||
Errno::result(libc::msync(addr, length, flags.bits())).map(drop)
|
||||
}
|
||||
|
||||
#[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| {
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
unsafe {
|
||||
libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::c_uint)
|
||||
}
|
||||
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
|
||||
unsafe {
|
||||
libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::mode_t)
|
||||
}
|
||||
})?;
|
||||
|
||||
Errno::result(ret)
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
pub fn shm_unlink<P: ?Sized + NixPath>(name: &P) -> Result<()> {
|
||||
let ret = name.with_nix_path(|cstr| {
|
||||
unsafe { libc::shm_unlink(cstr.as_ptr()) }
|
||||
})?;
|
||||
|
||||
Errno::result(ret).map(drop)
|
||||
}
|
131
vendor/nix-v0.23.1-patched/src/sys/mod.rs
vendored
131
vendor/nix-v0.23.1-patched/src/sys/mod.rs
vendored
|
@ -1,131 +0,0 @@
|
|||
//! Mostly platform-specific functionality
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd"))]
|
||||
pub mod aio;
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[allow(missing_docs)]
|
||||
pub mod epoll;
|
||||
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"))]
|
||||
#[allow(missing_docs)]
|
||||
pub mod event;
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[allow(missing_docs)]
|
||||
pub mod eventfd;
|
||||
|
||||
#[cfg(any(target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "redox",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "illumos",
|
||||
target_os = "openbsd"))]
|
||||
#[macro_use]
|
||||
pub mod ioctl;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[allow(missing_docs)]
|
||||
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;
|
||||
|
||||
#[cfg(any(target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux",
|
||||
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;
|
||||
|
||||
#[cfg(any(target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
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",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
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;
|
||||
|
||||
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;
|
|
@ -1,70 +0,0 @@
|
|||
use crate::Result;
|
||||
use crate::errno::Errno;
|
||||
|
||||
use libc::{self, c_int, c_ulong};
|
||||
|
||||
libc_bitflags! {
|
||||
/// Flags used and returned by [`get()`](fn.get.html) and
|
||||
/// [`set()`](fn.set.html).
|
||||
pub struct Persona: c_int {
|
||||
ADDR_COMPAT_LAYOUT;
|
||||
ADDR_NO_RANDOMIZE;
|
||||
ADDR_LIMIT_32BIT;
|
||||
ADDR_LIMIT_3GB;
|
||||
#[cfg(not(target_env = "musl"))]
|
||||
FDPIC_FUNCPTRS;
|
||||
MMAP_PAGE_ZERO;
|
||||
READ_IMPLIES_EXEC;
|
||||
SHORT_INODE;
|
||||
STICKY_TIMEOUTS;
|
||||
#[cfg(not(target_env = "musl"))]
|
||||
UNAME26;
|
||||
WHOLE_SECONDS;
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieve the current process personality.
|
||||
///
|
||||
/// Returns a Result containing a Persona instance.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```
|
||||
/// # use nix::sys::personality::{self, Persona};
|
||||
/// let pers = personality::get().unwrap();
|
||||
/// assert!(!pers.contains(Persona::WHOLE_SECONDS));
|
||||
/// ```
|
||||
pub fn get() -> Result<Persona> {
|
||||
let res = unsafe {
|
||||
libc::personality(0xFFFFFFFF)
|
||||
};
|
||||
|
||||
Errno::result(res).map(Persona::from_bits_truncate)
|
||||
}
|
||||
|
||||
/// Set the current process personality.
|
||||
///
|
||||
/// Returns a Result containing the *previous* personality for the
|
||||
/// process, as a Persona.
|
||||
///
|
||||
/// For more information, see [personality(2)](https://man7.org/linux/man-pages/man2/personality.2.html)
|
||||
///
|
||||
/// **NOTE**: This call **replaces** the current personality entirely.
|
||||
/// To **update** the personality, first call `get()` and then `set()`
|
||||
/// with the modified persona.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```
|
||||
/// # use nix::sys::personality::{self, Persona};
|
||||
/// let mut pers = personality::get().unwrap();
|
||||
/// assert!(!pers.contains(Persona::ADDR_NO_RANDOMIZE));
|
||||
/// personality::set(pers | Persona::ADDR_NO_RANDOMIZE);
|
||||
/// ```
|
||||
pub fn set(persona: Persona) -> Result<Persona> {
|
||||
let res = unsafe {
|
||||
libc::personality(persona.bits() as c_ulong)
|
||||
};
|
||||
|
||||
Errno::result(res).map(Persona::from_bits_truncate)
|
||||
}
|
38
vendor/nix-v0.23.1-patched/src/sys/pthread.rs
vendored
38
vendor/nix-v0.23.1-patched/src/sys/pthread.rs
vendored
|
@ -1,38 +0,0 @@
|
|||
//! 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)
|
||||
///
|
||||
/// The thread ID returned by `pthread_self()` is not the same thing as
|
||||
/// the kernel thread ID returned by a call to `gettid(2)`.
|
||||
#[inline]
|
||||
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)
|
||||
}
|
176
vendor/nix-v0.23.1-patched/src/sys/ptrace/bsd.rs
vendored
176
vendor/nix-v0.23.1-patched/src/sys/ptrace/bsd.rs
vendored
|
@ -1,176 +0,0 @@
|
|||
use cfg_if::cfg_if;
|
||||
use crate::errno::Errno;
|
||||
use libc::{self, c_int};
|
||||
use std::ptr;
|
||||
use crate::sys::signal::Signal;
|
||||
use crate::unistd::Pid;
|
||||
use crate::Result;
|
||||
|
||||
pub type RequestType = c_int;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "openbsd"))] {
|
||||
#[doc(hidden)]
|
||||
pub type AddressType = *mut ::libc::c_char;
|
||||
} else {
|
||||
#[doc(hidden)]
|
||||
pub type AddressType = *mut ::libc::c_void;
|
||||
}
|
||||
}
|
||||
|
||||
libc_enum! {
|
||||
#[repr(i32)]
|
||||
/// Ptrace Request enum defining the action to be taken.
|
||||
#[non_exhaustive]
|
||||
pub enum Request {
|
||||
PT_TRACE_ME,
|
||||
PT_READ_I,
|
||||
PT_READ_D,
|
||||
#[cfg(target_os = "macos")]
|
||||
PT_READ_U,
|
||||
PT_WRITE_I,
|
||||
PT_WRITE_D,
|
||||
#[cfg(target_os = "macos")]
|
||||
PT_WRITE_U,
|
||||
PT_CONTINUE,
|
||||
PT_KILL,
|
||||
#[cfg(any(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos"),
|
||||
all(target_os = "openbsd", target_arch = "x86_64"),
|
||||
all(target_os = "netbsd", any(target_arch = "x86_64",
|
||||
target_arch = "powerpc"))))]
|
||||
PT_STEP,
|
||||
PT_ATTACH,
|
||||
PT_DETACH,
|
||||
#[cfg(target_os = "macos")]
|
||||
PT_SIGEXC,
|
||||
#[cfg(target_os = "macos")]
|
||||
PT_THUPDATE,
|
||||
#[cfg(target_os = "macos")]
|
||||
PT_ATTACHEXC
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn ptrace_other(
|
||||
request: Request,
|
||||
pid: Pid,
|
||||
addr: AddressType,
|
||||
data: c_int,
|
||||
) -> Result<c_int> {
|
||||
Errno::result(libc::ptrace(
|
||||
request as RequestType,
|
||||
libc::pid_t::from(pid),
|
||||
addr,
|
||||
data,
|
||||
)).map(|_| 0)
|
||||
}
|
||||
|
||||
/// Sets the process as traceable, as with `ptrace(PT_TRACEME, ...)`
|
||||
///
|
||||
/// Indicates that this process is to be traced by its parent.
|
||||
/// This is the only ptrace request to be issued by the tracee.
|
||||
pub fn traceme() -> Result<()> {
|
||||
unsafe { ptrace_other(Request::PT_TRACE_ME, Pid::from_raw(0), ptr::null_mut(), 0).map(drop) }
|
||||
}
|
||||
|
||||
/// Attach to a running process, as with `ptrace(PT_ATTACH, ...)`
|
||||
///
|
||||
/// Attaches to the process specified by `pid`, making it a tracee of the calling process.
|
||||
pub fn attach(pid: Pid) -> Result<()> {
|
||||
unsafe { ptrace_other(Request::PT_ATTACH, pid, ptr::null_mut(), 0).map(drop) }
|
||||
}
|
||||
|
||||
/// Detaches the current running process, as with `ptrace(PT_DETACH, ...)`
|
||||
///
|
||||
/// Detaches from the process specified by `pid` allowing it to run freely, optionally delivering a
|
||||
/// signal specified by `sig`.
|
||||
pub fn detach<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
|
||||
let data = match sig.into() {
|
||||
Some(s) => s as c_int,
|
||||
None => 0,
|
||||
};
|
||||
unsafe {
|
||||
ptrace_other(Request::PT_DETACH, pid, ptr::null_mut(), data).map(drop)
|
||||
}
|
||||
}
|
||||
|
||||
/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)`
|
||||
///
|
||||
/// Continues the execution of the process with PID `pid`, optionally
|
||||
/// delivering a signal specified by `sig`.
|
||||
pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
|
||||
let data = match sig.into() {
|
||||
Some(s) => s as c_int,
|
||||
None => 0,
|
||||
};
|
||||
unsafe {
|
||||
// Ignore the useless return value
|
||||
ptrace_other(Request::PT_CONTINUE, pid, 1 as AddressType, data).map(drop)
|
||||
}
|
||||
}
|
||||
|
||||
/// Issues a kill request as with `ptrace(PT_KILL, ...)`
|
||||
///
|
||||
/// This request is equivalent to `ptrace(PT_CONTINUE, ..., SIGKILL);`
|
||||
pub fn kill(pid: Pid) -> Result<()> {
|
||||
unsafe {
|
||||
ptrace_other(Request::PT_KILL, pid, 0 as AddressType, 0).map(drop)
|
||||
}
|
||||
}
|
||||
|
||||
/// Move the stopped tracee process forward by a single step as with
|
||||
/// `ptrace(PT_STEP, ...)`
|
||||
///
|
||||
/// Advances the execution of the process with PID `pid` by a single step optionally delivering a
|
||||
/// signal specified by `sig`.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// use nix::sys::ptrace::step;
|
||||
/// 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);
|
||||
/// }
|
||||
/// _ => {},
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(
|
||||
any(
|
||||
any(target_os = "dragonfly", target_os = "freebsd", target_os = "macos"),
|
||||
all(target_os = "openbsd", target_arch = "x86_64"),
|
||||
all(target_os = "netbsd",
|
||||
any(target_arch = "x86_64", target_arch = "powerpc")
|
||||
)
|
||||
)
|
||||
)]
|
||||
pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
|
||||
let data = match sig.into() {
|
||||
Some(s) => s as c_int,
|
||||
None => 0,
|
||||
};
|
||||
unsafe { ptrace_other(Request::PT_STEP, pid, ptr::null_mut(), data).map(drop) }
|
||||
}
|
||||
|
||||
/// Reads a word from a processes memory at the given address
|
||||
pub fn read(pid: Pid, addr: AddressType) -> Result<c_int> {
|
||||
unsafe {
|
||||
// Traditionally there was a difference between reading data or
|
||||
// instruction memory but not in modern systems.
|
||||
ptrace_other(Request::PT_READ_D, pid, addr, 0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a word into the processes memory at the given address
|
||||
pub fn write(pid: Pid, addr: AddressType, data: c_int) -> Result<()> {
|
||||
unsafe { ptrace_other(Request::PT_WRITE_D, pid, addr, data).map(drop) }
|
||||
}
|
479
vendor/nix-v0.23.1-patched/src/sys/ptrace/linux.rs
vendored
479
vendor/nix-v0.23.1-patched/src/sys/ptrace/linux.rs
vendored
|
@ -1,479 +0,0 @@
|
|||
//! For detailed description of the ptrace requests, consult `man ptrace`.
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use std::{mem, ptr};
|
||||
use crate::Result;
|
||||
use crate::errno::Errno;
|
||||
use libc::{self, c_void, c_long, siginfo_t};
|
||||
use crate::unistd::Pid;
|
||||
use crate::sys::signal::Signal;
|
||||
|
||||
pub type AddressType = *mut ::libc::c_void;
|
||||
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
any(all(target_arch = "x86_64",
|
||||
any(target_env = "gnu", target_env = "musl")),
|
||||
all(target_arch = "x86", target_env = "gnu"))
|
||||
))]
|
||||
use libc::user_regs_struct;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(any(all(target_os = "linux", target_arch = "s390x"),
|
||||
all(target_os = "linux", target_env = "gnu")))] {
|
||||
#[doc(hidden)]
|
||||
pub type RequestType = ::libc::c_uint;
|
||||
} else {
|
||||
#[doc(hidden)]
|
||||
pub type RequestType = ::libc::c_int;
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
PTRACE_PEEKDATA,
|
||||
PTRACE_PEEKUSER,
|
||||
PTRACE_POKETEXT,
|
||||
PTRACE_POKEDATA,
|
||||
PTRACE_POKEUSER,
|
||||
PTRACE_CONT,
|
||||
PTRACE_KILL,
|
||||
PTRACE_SINGLESTEP,
|
||||
#[cfg(any(all(target_os = "android", target_pointer_width = "32"),
|
||||
all(target_os = "linux", any(target_env = "musl",
|
||||
target_arch = "mips",
|
||||
target_arch = "mips64",
|
||||
target_arch = "x86_64",
|
||||
target_pointer_width = "32"))))]
|
||||
PTRACE_GETREGS,
|
||||
#[cfg(any(all(target_os = "android", target_pointer_width = "32"),
|
||||
all(target_os = "linux", any(target_env = "musl",
|
||||
target_arch = "mips",
|
||||
target_arch = "mips64",
|
||||
target_arch = "x86_64",
|
||||
target_pointer_width = "32"))))]
|
||||
PTRACE_SETREGS,
|
||||
#[cfg(any(all(target_os = "android", target_pointer_width = "32"),
|
||||
all(target_os = "linux", any(target_env = "musl",
|
||||
target_arch = "mips",
|
||||
target_arch = "mips64",
|
||||
target_arch = "x86_64",
|
||||
target_pointer_width = "32"))))]
|
||||
PTRACE_GETFPREGS,
|
||||
#[cfg(any(all(target_os = "android", target_pointer_width = "32"),
|
||||
all(target_os = "linux", any(target_env = "musl",
|
||||
target_arch = "mips",
|
||||
target_arch = "mips64",
|
||||
target_arch = "x86_64",
|
||||
target_pointer_width = "32"))))]
|
||||
PTRACE_SETFPREGS,
|
||||
PTRACE_ATTACH,
|
||||
PTRACE_DETACH,
|
||||
#[cfg(all(target_os = "linux", any(target_env = "musl",
|
||||
target_arch = "mips",
|
||||
target_arch = "mips64",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64")))]
|
||||
PTRACE_GETFPXREGS,
|
||||
#[cfg(all(target_os = "linux", any(target_env = "musl",
|
||||
target_arch = "mips",
|
||||
target_arch = "mips64",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64")))]
|
||||
PTRACE_SETFPXREGS,
|
||||
PTRACE_SYSCALL,
|
||||
PTRACE_SETOPTIONS,
|
||||
PTRACE_GETEVENTMSG,
|
||||
PTRACE_GETSIGINFO,
|
||||
PTRACE_SETSIGINFO,
|
||||
#[cfg(all(target_os = "linux", not(any(target_arch = "mips",
|
||||
target_arch = "mips64"))))]
|
||||
PTRACE_GETREGSET,
|
||||
#[cfg(all(target_os = "linux", not(any(target_arch = "mips",
|
||||
target_arch = "mips64"))))]
|
||||
PTRACE_SETREGSET,
|
||||
#[cfg(target_os = "linux")]
|
||||
PTRACE_SEIZE,
|
||||
#[cfg(target_os = "linux")]
|
||||
PTRACE_INTERRUPT,
|
||||
#[cfg(all(target_os = "linux", not(any(target_arch = "mips",
|
||||
target_arch = "mips64"))))]
|
||||
PTRACE_LISTEN,
|
||||
#[cfg(all(target_os = "linux", not(any(target_arch = "mips",
|
||||
target_arch = "mips64"))))]
|
||||
PTRACE_PEEKSIGINFO,
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu",
|
||||
any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
PTRACE_SYSEMU,
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu",
|
||||
any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
PTRACE_SYSEMU_SINGLESTEP,
|
||||
}
|
||||
}
|
||||
|
||||
libc_enum!{
|
||||
#[repr(i32)]
|
||||
/// 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,
|
||||
/// Event that stops before a return from vfork or clone.
|
||||
PTRACE_EVENT_VFORK,
|
||||
/// Event that stops before a return from clone.
|
||||
PTRACE_EVENT_CLONE,
|
||||
/// Event that stops before a return from execve.
|
||||
PTRACE_EVENT_EXEC,
|
||||
/// Event for a return from vfork.
|
||||
PTRACE_EVENT_VFORK_DONE,
|
||||
/// 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.
|
||||
PTRACE_EVENT_SECCOMP,
|
||||
/// Stop triggered by the `INTERRUPT` syscall, or a group stop,
|
||||
/// or when a new child is attached.
|
||||
PTRACE_EVENT_STOP,
|
||||
}
|
||||
}
|
||||
|
||||
libc_bitflags! {
|
||||
/// Ptrace options used in conjunction with the PTRACE_SETOPTIONS request.
|
||||
/// See `man ptrace` for more details.
|
||||
pub struct Options: libc::c_int {
|
||||
/// When delivering system call traps set a bit to allow tracer to
|
||||
/// distinguish between normal stops or syscall stops. May not work on
|
||||
/// all systems.
|
||||
PTRACE_O_TRACESYSGOOD;
|
||||
/// Stop tracee at next fork and start tracing the forked process.
|
||||
PTRACE_O_TRACEFORK;
|
||||
/// Stop tracee at next vfork call and trace the vforked process.
|
||||
PTRACE_O_TRACEVFORK;
|
||||
/// Stop tracee at next clone call and trace the cloned process.
|
||||
PTRACE_O_TRACECLONE;
|
||||
/// Stop tracee at next execve call.
|
||||
PTRACE_O_TRACEEXEC;
|
||||
/// Stop tracee at vfork completion.
|
||||
PTRACE_O_TRACEVFORKDONE;
|
||||
/// Stop tracee at next exit call. Stops before exit commences allowing
|
||||
/// tracer to see location of exit and register states.
|
||||
PTRACE_O_TRACEEXIT;
|
||||
/// Stop tracee when a SECCOMP_RET_TRACE rule is triggered. See `man seccomp` for more
|
||||
/// details.
|
||||
PTRACE_O_TRACESECCOMP;
|
||||
/// Send a SIGKILL to the tracee if the tracer exits. This is useful
|
||||
/// for ptrace jailers to prevent tracees from escaping their control.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
PTRACE_O_EXITKILL;
|
||||
}
|
||||
}
|
||||
|
||||
fn ptrace_peek(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result<c_long> {
|
||||
let ret = unsafe {
|
||||
Errno::clear();
|
||||
libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data)
|
||||
};
|
||||
match Errno::result(ret) {
|
||||
Ok(..) | Err(Errno::UnknownErrno) => Ok(ret),
|
||||
err @ Err(..) => err,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get user registers, as with `ptrace(PTRACE_GETREGS, ...)`
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
any(all(target_arch = "x86_64",
|
||||
any(target_env = "gnu", target_env = "musl")),
|
||||
all(target_arch = "x86", target_env = "gnu"))
|
||||
))]
|
||||
pub fn getregs(pid: Pid) -> Result<user_regs_struct> {
|
||||
ptrace_get_data::<user_regs_struct>(Request::PTRACE_GETREGS, pid)
|
||||
}
|
||||
|
||||
/// Set user registers, as with `ptrace(PTRACE_SETREGS, ...)`
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
any(all(target_arch = "x86_64",
|
||||
any(target_env = "gnu", target_env = "musl")),
|
||||
all(target_arch = "x86", target_env = "gnu"))
|
||||
))]
|
||||
pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> {
|
||||
let res = unsafe {
|
||||
libc::ptrace(Request::PTRACE_SETREGS as RequestType,
|
||||
libc::pid_t::from(pid),
|
||||
ptr::null_mut::<c_void>(),
|
||||
®s as *const _ as *const c_void)
|
||||
};
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
/// Function for ptrace requests that return values from the data field.
|
||||
/// Some ptrace get requests populate structs or larger elements than `c_long`
|
||||
/// and therefore use the data field to return values. This function handles these
|
||||
/// requests.
|
||||
fn ptrace_get_data<T>(request: Request, pid: Pid) -> Result<T> {
|
||||
let mut data = mem::MaybeUninit::uninit();
|
||||
let res = unsafe {
|
||||
libc::ptrace(request as RequestType,
|
||||
libc::pid_t::from(pid),
|
||||
ptr::null_mut::<T>(),
|
||||
data.as_mut_ptr() as *const _ as *const c_void)
|
||||
};
|
||||
Errno::result(res)?;
|
||||
Ok(unsafe{ data.assume_init() })
|
||||
}
|
||||
|
||||
unsafe fn ptrace_other(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result<c_long> {
|
||||
Errno::result(libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data)).map(|_| 0)
|
||||
}
|
||||
|
||||
/// Set options, as with `ptrace(PTRACE_SETOPTIONS,...)`.
|
||||
pub fn setoptions(pid: Pid, options: Options) -> Result<()> {
|
||||
let res = unsafe {
|
||||
libc::ptrace(Request::PTRACE_SETOPTIONS as RequestType,
|
||||
libc::pid_t::from(pid),
|
||||
ptr::null_mut::<c_void>(),
|
||||
options.bits() as *mut c_void)
|
||||
};
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG,...)`
|
||||
pub fn getevent(pid: Pid) -> Result<c_long> {
|
||||
ptrace_get_data::<c_long>(Request::PTRACE_GETEVENTMSG, pid)
|
||||
}
|
||||
|
||||
/// Get siginfo as with `ptrace(PTRACE_GETSIGINFO,...)`
|
||||
pub fn getsiginfo(pid: Pid) -> Result<siginfo_t> {
|
||||
ptrace_get_data::<siginfo_t>(Request::PTRACE_GETSIGINFO, pid)
|
||||
}
|
||||
|
||||
/// Set siginfo as with `ptrace(PTRACE_SETSIGINFO,...)`
|
||||
pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> {
|
||||
let ret = unsafe{
|
||||
Errno::clear();
|
||||
libc::ptrace(Request::PTRACE_SETSIGINFO as RequestType,
|
||||
libc::pid_t::from(pid),
|
||||
ptr::null_mut::<c_void>(),
|
||||
sig as *const _ as *const c_void)
|
||||
};
|
||||
match Errno::result(ret) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the process as traceable, as with `ptrace(PTRACE_TRACEME, ...)`
|
||||
///
|
||||
/// Indicates that this process is to be traced by its parent.
|
||||
/// This is the only ptrace request to be issued by the tracee.
|
||||
pub fn traceme() -> Result<()> {
|
||||
unsafe {
|
||||
ptrace_other(
|
||||
Request::PTRACE_TRACEME,
|
||||
Pid::from_raw(0),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
).map(drop) // ignore the useless return value
|
||||
}
|
||||
}
|
||||
|
||||
/// Continue execution until the next syscall, as with `ptrace(PTRACE_SYSCALL, ...)`
|
||||
///
|
||||
/// Arranges for the tracee to be stopped at the next entry to or exit from a system call,
|
||||
/// optionally delivering a signal specified by `sig`.
|
||||
pub fn syscall<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
|
||||
let data = match sig.into() {
|
||||
Some(s) => s as i32 as *mut c_void,
|
||||
None => ptr::null_mut(),
|
||||
};
|
||||
unsafe {
|
||||
ptrace_other(
|
||||
Request::PTRACE_SYSCALL,
|
||||
pid,
|
||||
ptr::null_mut(),
|
||||
data,
|
||||
).map(drop) // ignore the useless return value
|
||||
}
|
||||
}
|
||||
|
||||
/// Continue execution until the next syscall, as with `ptrace(PTRACE_SYSEMU, ...)`
|
||||
///
|
||||
/// In contrast to the `syscall` function, the syscall stopped at will not be executed.
|
||||
/// Thus the the tracee will only be stopped once per syscall,
|
||||
/// optionally delivering a signal specified by `sig`.
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu", any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
pub fn sysemu<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
|
||||
let data = match sig.into() {
|
||||
Some(s) => s as i32 as *mut c_void,
|
||||
None => ptr::null_mut(),
|
||||
};
|
||||
unsafe {
|
||||
ptrace_other(Request::PTRACE_SYSEMU, pid, ptr::null_mut(), data).map(drop)
|
||||
// ignore the useless return value
|
||||
}
|
||||
}
|
||||
|
||||
/// Attach to a running process, as with `ptrace(PTRACE_ATTACH, ...)`
|
||||
///
|
||||
/// Attaches to the process specified by `pid`, making it a tracee of the calling process.
|
||||
pub fn attach(pid: Pid) -> Result<()> {
|
||||
unsafe {
|
||||
ptrace_other(
|
||||
Request::PTRACE_ATTACH,
|
||||
pid,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
).map(drop) // ignore the useless return value
|
||||
}
|
||||
}
|
||||
|
||||
/// 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")]
|
||||
pub fn seize(pid: Pid, options: Options) -> Result<()> {
|
||||
unsafe {
|
||||
ptrace_other(
|
||||
Request::PTRACE_SEIZE,
|
||||
pid,
|
||||
ptr::null_mut(),
|
||||
options.bits() as *mut c_void,
|
||||
).map(drop) // ignore the useless return value
|
||||
}
|
||||
}
|
||||
|
||||
/// Detaches the current running process, as with `ptrace(PTRACE_DETACH, ...)`
|
||||
///
|
||||
/// Detaches from the process specified by `pid` allowing it to run freely, optionally delivering a
|
||||
/// signal specified by `sig`.
|
||||
pub fn detach<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
|
||||
let data = match sig.into() {
|
||||
Some(s) => s as i32 as *mut c_void,
|
||||
None => ptr::null_mut(),
|
||||
};
|
||||
unsafe {
|
||||
ptrace_other(
|
||||
Request::PTRACE_DETACH,
|
||||
pid,
|
||||
ptr::null_mut(),
|
||||
data
|
||||
).map(drop)
|
||||
}
|
||||
}
|
||||
|
||||
/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)`
|
||||
///
|
||||
/// Continues the execution of the process with PID `pid`, optionally
|
||||
/// delivering a signal specified by `sig`.
|
||||
pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
|
||||
let data = match sig.into() {
|
||||
Some(s) => s as i32 as *mut c_void,
|
||||
None => ptr::null_mut(),
|
||||
};
|
||||
unsafe {
|
||||
ptrace_other(Request::PTRACE_CONT, pid, ptr::null_mut(), data).map(drop) // ignore the useless return value
|
||||
}
|
||||
}
|
||||
|
||||
/// 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);`
|
||||
pub fn kill(pid: Pid) -> Result<()> {
|
||||
unsafe {
|
||||
ptrace_other(Request::PTRACE_KILL, pid, ptr::null_mut(), ptr::null_mut()).map(drop)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// signal specified by `sig`.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// use nix::sys::ptrace::step;
|
||||
/// 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);
|
||||
/// }
|
||||
/// _ => {},
|
||||
/// }
|
||||
/// ```
|
||||
pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
|
||||
let data = match sig.into() {
|
||||
Some(s) => s as i32 as *mut c_void,
|
||||
None => ptr::null_mut(),
|
||||
};
|
||||
unsafe {
|
||||
ptrace_other(Request::PTRACE_SINGLESTEP, pid, ptr::null_mut(), data).map(drop)
|
||||
}
|
||||
}
|
||||
|
||||
/// Move the stopped tracee process forward by a single step or stop at the next syscall
|
||||
/// as with `ptrace(PTRACE_SYSEMU_SINGLESTEP, ...)`
|
||||
///
|
||||
/// Advances the execution by a single step or until the next syscall.
|
||||
/// In case the tracee is stopped at a syscall, the syscall will not be executed.
|
||||
/// Optionally, the signal specified by `sig` is delivered to the tracee upon continuation.
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu", any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
pub fn sysemu_step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
|
||||
let data = match sig.into() {
|
||||
Some(s) => s as i32 as *mut c_void,
|
||||
None => ptr::null_mut(),
|
||||
};
|
||||
unsafe {
|
||||
ptrace_other(
|
||||
Request::PTRACE_SYSEMU_SINGLESTEP,
|
||||
pid,
|
||||
ptr::null_mut(),
|
||||
data,
|
||||
)
|
||||
.map(drop) // ignore the useless return value
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads a word from a processes memory at the given address
|
||||
pub fn read(pid: Pid, addr: AddressType) -> Result<c_long> {
|
||||
ptrace_peek(Request::PTRACE_PEEKDATA, pid, addr, ptr::null_mut())
|
||||
}
|
||||
|
||||
/// Writes a word into the processes memory at the given address
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The `data` argument is passed directly to `ptrace(2)`. Read that man page
|
||||
/// for guidance.
|
||||
pub unsafe fn write(
|
||||
pid: Pid,
|
||||
addr: AddressType,
|
||||
data: *mut c_void) -> Result<()>
|
||||
{
|
||||
ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop)
|
||||
}
|
22
vendor/nix-v0.23.1-patched/src/sys/ptrace/mod.rs
vendored
22
vendor/nix-v0.23.1-patched/src/sys/ptrace/mod.rs
vendored
|
@ -1,22 +0,0 @@
|
|||
///! Provides helpers for making ptrace system calls
|
||||
|
||||
#[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::*;
|
277
vendor/nix-v0.23.1-patched/src/sys/quota.rs
vendored
277
vendor/nix-v0.23.1-patched/src/sys/quota.rs
vendored
|
@ -1,277 +0,0 @@
|
|||
//! Set and configure disk quotas for users, groups, or projects.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Enabling and setting a quota:
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! # use nix::sys::quota::{Dqblk, quotactl_on, quotactl_set, QuotaFmt, QuotaType, QuotaValidFlags};
|
||||
//! quotactl_on(QuotaType::USRQUOTA, "/dev/sda1", QuotaFmt::QFMT_VFS_V1, "aquota.user");
|
||||
//! let mut dqblk: Dqblk = Default::default();
|
||||
//! dqblk.set_blocks_hard_limit(10000);
|
||||
//! dqblk.set_blocks_soft_limit(8000);
|
||||
//! quotactl_set(QuotaType::USRQUOTA, "/dev/sda1", 50, &dqblk, QuotaValidFlags::QIF_BLIMITS);
|
||||
//! ```
|
||||
use std::default::Default;
|
||||
use std::{mem, ptr};
|
||||
use libc::{self, c_int, c_char};
|
||||
use crate::{Result, NixPath};
|
||||
use crate::errno::Errno;
|
||||
|
||||
struct QuotaCmd(QuotaSubCmd, QuotaType);
|
||||
|
||||
impl QuotaCmd {
|
||||
#[allow(unused_unsafe)]
|
||||
fn as_int(&self) -> c_int {
|
||||
unsafe { libc::QCMD(self.0 as i32, self.1 as i32) }
|
||||
}
|
||||
}
|
||||
|
||||
// linux quota version >= 2
|
||||
libc_enum!{
|
||||
#[repr(i32)]
|
||||
enum QuotaSubCmd {
|
||||
Q_SYNC,
|
||||
Q_QUOTAON,
|
||||
Q_QUOTAOFF,
|
||||
Q_GETQUOTA,
|
||||
Q_SETQUOTA,
|
||||
}
|
||||
}
|
||||
|
||||
libc_enum!{
|
||||
/// The scope of the quota.
|
||||
#[repr(i32)]
|
||||
#[non_exhaustive]
|
||||
pub enum QuotaType {
|
||||
/// Specify a user quota
|
||||
USRQUOTA,
|
||||
/// Specify a group quota
|
||||
GRPQUOTA,
|
||||
}
|
||||
}
|
||||
|
||||
libc_enum!{
|
||||
/// The type of quota format to use.
|
||||
#[repr(i32)]
|
||||
#[non_exhaustive]
|
||||
pub enum QuotaFmt {
|
||||
/// Use the original quota format.
|
||||
QFMT_VFS_OLD,
|
||||
/// Use the standard VFS v0 quota format.
|
||||
///
|
||||
/// Handles 32-bit UIDs/GIDs and quota limits up to 2<sup>32</sup> bytes/2<sup>32</sup> inodes.
|
||||
QFMT_VFS_V0,
|
||||
/// Use the VFS v1 quota format.
|
||||
///
|
||||
/// Handles 32-bit UIDs/GIDs and quota limits of 2<sup>64</sup> bytes/2<sup>64</sup> inodes.
|
||||
QFMT_VFS_V1,
|
||||
}
|
||||
}
|
||||
|
||||
libc_bitflags!(
|
||||
/// Indicates the quota fields that are valid to read from.
|
||||
#[derive(Default)]
|
||||
pub struct QuotaValidFlags: u32 {
|
||||
/// The block hard & soft limit fields.
|
||||
QIF_BLIMITS;
|
||||
/// The current space field.
|
||||
QIF_SPACE;
|
||||
/// The inode hard & soft limit fields.
|
||||
QIF_ILIMITS;
|
||||
/// The current inodes field.
|
||||
QIF_INODES;
|
||||
/// The disk use time limit field.
|
||||
QIF_BTIME;
|
||||
/// The file quote time limit field.
|
||||
QIF_ITIME;
|
||||
/// All block & inode limits.
|
||||
QIF_LIMITS;
|
||||
/// The space & inodes usage fields.
|
||||
QIF_USAGE;
|
||||
/// The time limit fields.
|
||||
QIF_TIMES;
|
||||
/// All fields.
|
||||
QIF_ALL;
|
||||
}
|
||||
);
|
||||
|
||||
/// Wrapper type for `if_dqblk`
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct Dqblk(libc::dqblk);
|
||||
|
||||
impl Default for Dqblk {
|
||||
fn default() -> Dqblk {
|
||||
Dqblk(libc::dqblk {
|
||||
dqb_bhardlimit: 0,
|
||||
dqb_bsoftlimit: 0,
|
||||
dqb_curspace: 0,
|
||||
dqb_ihardlimit: 0,
|
||||
dqb_isoftlimit: 0,
|
||||
dqb_curinodes: 0,
|
||||
dqb_btime: 0,
|
||||
dqb_itime: 0,
|
||||
dqb_valid: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Dqblk {
|
||||
/// The absolute limit on disk quota blocks allocated.
|
||||
pub fn blocks_hard_limit(&self) -> Option<u64> {
|
||||
let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
|
||||
if valid_fields.contains(QuotaValidFlags::QIF_BLIMITS) {
|
||||
Some(self.0.dqb_bhardlimit)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the absolute limit on disk quota blocks allocated.
|
||||
pub fn set_blocks_hard_limit(&mut self, limit: u64) {
|
||||
self.0.dqb_bhardlimit = limit;
|
||||
}
|
||||
|
||||
/// Preferred limit on disk quota blocks
|
||||
pub fn blocks_soft_limit(&self) -> Option<u64> {
|
||||
let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
|
||||
if valid_fields.contains(QuotaValidFlags::QIF_BLIMITS) {
|
||||
Some(self.0.dqb_bsoftlimit)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the preferred limit on disk quota blocks allocated.
|
||||
pub fn set_blocks_soft_limit(&mut self, limit: u64) {
|
||||
self.0.dqb_bsoftlimit = limit;
|
||||
}
|
||||
|
||||
/// Current occupied space (bytes).
|
||||
pub fn occupied_space(&self) -> Option<u64> {
|
||||
let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
|
||||
if valid_fields.contains(QuotaValidFlags::QIF_SPACE) {
|
||||
Some(self.0.dqb_curspace)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Maximum number of allocated inodes.
|
||||
pub fn inodes_hard_limit(&self) -> Option<u64> {
|
||||
let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
|
||||
if valid_fields.contains(QuotaValidFlags::QIF_ILIMITS) {
|
||||
Some(self.0.dqb_ihardlimit)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the maximum number of allocated inodes.
|
||||
pub fn set_inodes_hard_limit(&mut self, limit: u64) {
|
||||
self.0.dqb_ihardlimit = limit;
|
||||
}
|
||||
|
||||
/// Preferred inode limit
|
||||
pub fn inodes_soft_limit(&self) -> Option<u64> {
|
||||
let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
|
||||
if valid_fields.contains(QuotaValidFlags::QIF_ILIMITS) {
|
||||
Some(self.0.dqb_isoftlimit)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the preferred limit of allocated inodes.
|
||||
pub fn set_inodes_soft_limit(&mut self, limit: u64) {
|
||||
self.0.dqb_isoftlimit = limit;
|
||||
}
|
||||
|
||||
/// Current number of allocated inodes.
|
||||
pub fn allocated_inodes(&self) -> Option<u64> {
|
||||
let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
|
||||
if valid_fields.contains(QuotaValidFlags::QIF_INODES) {
|
||||
Some(self.0.dqb_curinodes)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Time limit for excessive disk use.
|
||||
pub fn block_time_limit(&self) -> Option<u64> {
|
||||
let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
|
||||
if valid_fields.contains(QuotaValidFlags::QIF_BTIME) {
|
||||
Some(self.0.dqb_btime)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the time limit for excessive disk use.
|
||||
pub fn set_block_time_limit(&mut self, limit: u64) {
|
||||
self.0.dqb_btime = limit;
|
||||
}
|
||||
|
||||
/// Time limit for excessive files.
|
||||
pub fn inode_time_limit(&self) -> Option<u64> {
|
||||
let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
|
||||
if valid_fields.contains(QuotaValidFlags::QIF_ITIME) {
|
||||
Some(self.0.dqb_itime)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the time limit for excessive files.
|
||||
pub fn set_inode_time_limit(&mut self, limit: u64) {
|
||||
self.0.dqb_itime = limit;
|
||||
}
|
||||
}
|
||||
|
||||
fn quotactl<P: ?Sized + NixPath>(cmd: QuotaCmd, special: Option<&P>, id: c_int, addr: *mut c_char) -> Result<()> {
|
||||
unsafe {
|
||||
Errno::clear();
|
||||
let res = match special {
|
||||
Some(dev) => dev.with_nix_path(|path| libc::quotactl(cmd.as_int(), path.as_ptr(), id, addr)),
|
||||
None => Ok(libc::quotactl(cmd.as_int(), ptr::null(), id, addr)),
|
||||
}?;
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
}
|
||||
|
||||
/// Turn on disk quotas for a block device.
|
||||
pub fn quotactl_on<P: ?Sized + NixPath>(which: QuotaType, special: &P, format: QuotaFmt, quota_file: &P) -> Result<()> {
|
||||
quota_file.with_nix_path(|path| {
|
||||
let mut path_copy = path.to_bytes_with_nul().to_owned();
|
||||
let p: *mut c_char = path_copy.as_mut_ptr() as *mut c_char;
|
||||
quotactl(QuotaCmd(QuotaSubCmd::Q_QUOTAON, which), Some(special), format as c_int, p)
|
||||
})?
|
||||
}
|
||||
|
||||
/// Disable disk quotas for a block device.
|
||||
pub fn quotactl_off<P: ?Sized + NixPath>(which: QuotaType, special: &P) -> Result<()> {
|
||||
quotactl(QuotaCmd(QuotaSubCmd::Q_QUOTAOFF, which), Some(special), 0, ptr::null_mut())
|
||||
}
|
||||
|
||||
/// Update the on-disk copy of quota usages for a filesystem.
|
||||
///
|
||||
/// If `special` is `None`, then all file systems with active quotas are sync'd.
|
||||
pub fn quotactl_sync<P: ?Sized + NixPath>(which: QuotaType, special: Option<&P>) -> Result<()> {
|
||||
quotactl(QuotaCmd(QuotaSubCmd::Q_SYNC, which), special, 0, ptr::null_mut())
|
||||
}
|
||||
|
||||
/// Get disk quota limits and current usage for the given user/group id.
|
||||
pub fn quotactl_get<P: ?Sized + NixPath>(which: QuotaType, special: &P, id: c_int) -> Result<Dqblk> {
|
||||
let mut dqblk = mem::MaybeUninit::uninit();
|
||||
quotactl(QuotaCmd(QuotaSubCmd::Q_GETQUOTA, which), Some(special), id, dqblk.as_mut_ptr() as *mut c_char)?;
|
||||
Ok(unsafe{ Dqblk(dqblk.assume_init())})
|
||||
}
|
||||
|
||||
/// Configure quota values for the specified fields for a given user/group id.
|
||||
pub fn quotactl_set<P: ?Sized + NixPath>(which: QuotaType, special: &P, id: c_int, dqblk: &Dqblk, fields: QuotaValidFlags) -> Result<()> {
|
||||
let mut dqblk_copy = *dqblk;
|
||||
dqblk_copy.0.dqb_valid = fields.bits();
|
||||
quotactl(QuotaCmd(QuotaSubCmd::Q_SETQUOTA, which), Some(special), id, &mut dqblk_copy as *mut _ as *mut c_char)
|
||||
}
|
45
vendor/nix-v0.23.1-patched/src/sys/reboot.rs
vendored
45
vendor/nix-v0.23.1-patched/src/sys/reboot.rs
vendored
|
@ -1,45 +0,0 @@
|
|||
//! Reboot/shutdown or enable/disable Ctrl-Alt-Delete.
|
||||
|
||||
use crate::Result;
|
||||
use crate::errno::Errno;
|
||||
use std::convert::Infallible;
|
||||
use std::mem::drop;
|
||||
|
||||
libc_enum! {
|
||||
/// How exactly should the system be rebooted.
|
||||
///
|
||||
/// See [`set_cad_enabled()`](fn.set_cad_enabled.html) for
|
||||
/// enabling/disabling Ctrl-Alt-Delete.
|
||||
#[repr(i32)]
|
||||
#[non_exhaustive]
|
||||
pub enum RebootMode {
|
||||
RB_HALT_SYSTEM,
|
||||
RB_KEXEC,
|
||||
RB_POWER_OFF,
|
||||
RB_AUTOBOOT,
|
||||
// we do not support Restart2,
|
||||
RB_SW_SUSPEND,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reboot(how: RebootMode) -> Result<Infallible> {
|
||||
unsafe {
|
||||
libc::reboot(how as libc::c_int)
|
||||
};
|
||||
Err(Errno::last())
|
||||
}
|
||||
|
||||
/// Enable or disable the reboot keystroke (Ctrl-Alt-Delete).
|
||||
///
|
||||
/// Corresponds to calling `reboot(RB_ENABLE_CAD)` or `reboot(RB_DISABLE_CAD)` in C.
|
||||
pub fn set_cad_enabled(enable: bool) -> Result<()> {
|
||||
let cmd = if enable {
|
||||
libc::RB_ENABLE_CAD
|
||||
} else {
|
||||
libc::RB_DISABLE_CAD
|
||||
};
|
||||
let res = unsafe {
|
||||
libc::reboot(cmd)
|
||||
};
|
||||
Errno::result(res).map(drop)
|
||||
}
|
233
vendor/nix-v0.23.1-patched/src/sys/resource.rs
vendored
233
vendor/nix-v0.23.1-patched/src/sys/resource.rs
vendored
|
@ -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)
|
||||
}
|
430
vendor/nix-v0.23.1-patched/src/sys/select.rs
vendored
430
vendor/nix-v0.23.1-patched/src/sys/select.rs
vendored
|
@ -1,430 +0,0 @@
|
|||
//! Portably monitor a group of file descriptors for readiness.
|
||||
use std::convert::TryFrom;
|
||||
use std::iter::FusedIterator;
|
||||
use std::mem;
|
||||
use std::ops::Range;
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::ptr::{null, null_mut};
|
||||
use libc::{self, c_int};
|
||||
use crate::Result;
|
||||
use crate::errno::Errno;
|
||||
use crate::sys::signal::SigSet;
|
||||
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 {
|
||||
libc::FD_ZERO(fdset.as_mut_ptr());
|
||||
FdSet(fdset.assume_init())
|
||||
}
|
||||
}
|
||||
|
||||
/// 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) }
|
||||
}
|
||||
|
||||
/// Remove all file descriptors from this `FdSet`.
|
||||
pub fn clear(&mut self) {
|
||||
unsafe { libc::FD_ZERO(&mut self.0) };
|
||||
}
|
||||
|
||||
/// Finds the highest file descriptor in the set.
|
||||
///
|
||||
/// Returns `None` if the set is empty.
|
||||
///
|
||||
/// This can be used to calculate the `nfds` parameter of the [`select`] function.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use nix::sys::select::FdSet;
|
||||
/// 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> {
|
||||
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.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use nix::sys::select::FdSet;
|
||||
/// # use std::os::unix::io::RawFd;
|
||||
/// let mut set = FdSet::new();
|
||||
/// set.insert(4);
|
||||
/// set.insert(9);
|
||||
/// let fds: Vec<RawFd> = set.fds(None).collect();
|
||||
/// assert_eq!(fds, vec![4, 9]);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn fds(&self, highest: Option<RawFd>) -> Fds {
|
||||
Fds {
|
||||
set: self,
|
||||
range: 0..highest.map(|h| h as usize + 1).unwrap_or(FD_SETSIZE),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FdSet {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator over `FdSet`.
|
||||
#[derive(Debug)]
|
||||
pub struct Fds<'a> {
|
||||
set: &'a FdSet,
|
||||
range: Range<usize>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Fds<'a> {
|
||||
type Item = RawFd;
|
||||
|
||||
fn next(&mut self) -> Option<RawFd> {
|
||||
for i in &mut self.range {
|
||||
if self.set.contains(i as RawFd) {
|
||||
return Some(i as RawFd);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let (_, upper) = self.range.size_hint();
|
||||
(0, upper)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DoubleEndedIterator for Fds<'a> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<RawFd> {
|
||||
while let Some(i) = self.range.next_back() {
|
||||
if self.set.contains(i as RawFd) {
|
||||
return Some(i as RawFd);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FusedIterator for Fds<'a> {}
|
||||
|
||||
/// Monitors file descriptors for readiness
|
||||
///
|
||||
/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all
|
||||
/// file descriptors that are ready for the given operation are set.
|
||||
///
|
||||
/// When this function returns, `timeout` has an implementation-defined value.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this
|
||||
/// is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1
|
||||
/// to the maximum of that.
|
||||
/// * `readfds`: File descriptors to check for being ready to read.
|
||||
/// * `writefds`: File descriptors to check for being ready to write.
|
||||
/// * `errorfds`: File descriptors to check for pending error conditions.
|
||||
/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block
|
||||
/// indefinitely).
|
||||
///
|
||||
/// # References
|
||||
///
|
||||
/// [select(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html)
|
||||
///
|
||||
/// [`FdSet::highest`]: struct.FdSet.html#method.highest
|
||||
pub fn select<'a, N, R, W, E, T>(nfds: N,
|
||||
readfds: R,
|
||||
writefds: W,
|
||||
errorfds: E,
|
||||
timeout: T) -> Result<c_int>
|
||||
where
|
||||
N: Into<Option<c_int>>,
|
||||
R: Into<Option<&'a mut FdSet>>,
|
||||
W: Into<Option<&'a mut FdSet>>,
|
||||
E: Into<Option<&'a mut FdSet>>,
|
||||
T: Into<Option<&'a mut TimeVal>>,
|
||||
{
|
||||
let mut readfds = readfds.into();
|
||||
let mut writefds = writefds.into();
|
||||
let mut errorfds = errorfds.into();
|
||||
let timeout = timeout.into();
|
||||
|
||||
let nfds = nfds.into().unwrap_or_else(|| {
|
||||
readfds.iter_mut()
|
||||
.chain(writefds.iter_mut())
|
||||
.chain(errorfds.iter_mut())
|
||||
.map(|set| set.highest().unwrap_or(-1))
|
||||
.max()
|
||||
.unwrap_or(-1) + 1
|
||||
});
|
||||
|
||||
let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
|
||||
let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
|
||||
let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
|
||||
let timeout = timeout.map(|tv| tv as *mut _ as *mut libc::timeval)
|
||||
.unwrap_or(null_mut());
|
||||
|
||||
let res = unsafe {
|
||||
libc::select(nfds, readfds, writefds, errorfds, timeout)
|
||||
};
|
||||
|
||||
Errno::result(res)
|
||||
}
|
||||
|
||||
/// Monitors file descriptors for readiness with an altered signal mask.
|
||||
///
|
||||
/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all
|
||||
/// file descriptors that are ready for the given operation are set.
|
||||
///
|
||||
/// When this function returns, the original signal mask is restored.
|
||||
///
|
||||
/// Unlike [`select`](#fn.select), `pselect` does not mutate the `timeout` value.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this
|
||||
/// is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1
|
||||
/// to the maximum of that.
|
||||
/// * `readfds`: File descriptors to check for read readiness
|
||||
/// * `writefds`: File descriptors to check for write readiness
|
||||
/// * `errorfds`: File descriptors to check for pending error conditions.
|
||||
/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block
|
||||
/// indefinitely).
|
||||
/// * `sigmask`: Signal mask to activate while waiting for file descriptors to turn
|
||||
/// ready (`None` to set no alternative signal mask).
|
||||
///
|
||||
/// # References
|
||||
///
|
||||
/// [pselect(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pselect.html)
|
||||
///
|
||||
/// [The new pselect() system call](https://lwn.net/Articles/176911/)
|
||||
///
|
||||
/// [`FdSet::highest`]: struct.FdSet.html#method.highest
|
||||
pub fn pselect<'a, N, R, W, E, T, S>(nfds: N,
|
||||
readfds: R,
|
||||
writefds: W,
|
||||
errorfds: E,
|
||||
timeout: T,
|
||||
sigmask: S) -> Result<c_int>
|
||||
where
|
||||
N: Into<Option<c_int>>,
|
||||
R: Into<Option<&'a mut FdSet>>,
|
||||
W: Into<Option<&'a mut FdSet>>,
|
||||
E: Into<Option<&'a mut FdSet>>,
|
||||
T: Into<Option<&'a TimeSpec>>,
|
||||
S: Into<Option<&'a SigSet>>,
|
||||
{
|
||||
let mut readfds = readfds.into();
|
||||
let mut writefds = writefds.into();
|
||||
let mut errorfds = errorfds.into();
|
||||
let sigmask = sigmask.into();
|
||||
let timeout = timeout.into();
|
||||
|
||||
let nfds = nfds.into().unwrap_or_else(|| {
|
||||
readfds.iter_mut()
|
||||
.chain(writefds.iter_mut())
|
||||
.chain(errorfds.iter_mut())
|
||||
.map(|set| set.highest().unwrap_or(-1))
|
||||
.max()
|
||||
.unwrap_or(-1) + 1
|
||||
});
|
||||
|
||||
let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
|
||||
let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
|
||||
let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
|
||||
let timeout = timeout.map(|ts| ts.as_ref() as *const libc::timespec).unwrap_or(null());
|
||||
let sigmask = sigmask.map(|sm| sm.as_ref() as *const libc::sigset_t).unwrap_or(null());
|
||||
|
||||
let res = unsafe {
|
||||
libc::pselect(nfds, readfds, writefds, errorfds, timeout, sigmask)
|
||||
};
|
||||
|
||||
Errno::result(res)
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::os::unix::io::RawFd;
|
||||
use crate::sys::time::{TimeVal, TimeValLike};
|
||||
use crate::unistd::{write, pipe};
|
||||
|
||||
#[test]
|
||||
fn fdset_insert() {
|
||||
let mut fd_set = FdSet::new();
|
||||
|
||||
for i in 0..FD_SETSIZE {
|
||||
assert!(!fd_set.contains(i as RawFd));
|
||||
}
|
||||
|
||||
fd_set.insert(7);
|
||||
|
||||
assert!(fd_set.contains(7));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fdset_remove() {
|
||||
let mut fd_set = FdSet::new();
|
||||
|
||||
for i in 0..FD_SETSIZE {
|
||||
assert!(!fd_set.contains(i as RawFd));
|
||||
}
|
||||
|
||||
fd_set.insert(7);
|
||||
fd_set.remove(7);
|
||||
|
||||
for i in 0..FD_SETSIZE {
|
||||
assert!(!fd_set.contains(i as RawFd));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fdset_clear() {
|
||||
let mut fd_set = FdSet::new();
|
||||
fd_set.insert(1);
|
||||
fd_set.insert((FD_SETSIZE / 2) as RawFd);
|
||||
fd_set.insert((FD_SETSIZE - 1) as RawFd);
|
||||
|
||||
fd_set.clear();
|
||||
|
||||
for i in 0..FD_SETSIZE {
|
||||
assert!(!fd_set.contains(i as RawFd));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fdset_highest() {
|
||||
let mut set = FdSet::new();
|
||||
assert_eq!(set.highest(), None);
|
||||
set.insert(0);
|
||||
assert_eq!(set.highest(), Some(0));
|
||||
set.insert(90);
|
||||
assert_eq!(set.highest(), Some(90));
|
||||
set.remove(0);
|
||||
assert_eq!(set.highest(), Some(90));
|
||||
set.remove(90);
|
||||
assert_eq!(set.highest(), None);
|
||||
|
||||
set.insert(4);
|
||||
set.insert(5);
|
||||
set.insert(7);
|
||||
assert_eq!(set.highest(), Some(7));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fdset_fds() {
|
||||
let mut set = FdSet::new();
|
||||
assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![]);
|
||||
set.insert(0);
|
||||
assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![0]);
|
||||
set.insert(90);
|
||||
assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![0, 90]);
|
||||
|
||||
// highest limit
|
||||
assert_eq!(set.fds(Some(89)).collect::<Vec<_>>(), vec![0]);
|
||||
assert_eq!(set.fds(Some(90)).collect::<Vec<_>>(), vec![0, 90]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_select() {
|
||||
let (r1, w1) = pipe().unwrap();
|
||||
write(w1, b"hi!").unwrap();
|
||||
let (r2, _w2) = pipe().unwrap();
|
||||
|
||||
let mut fd_set = FdSet::new();
|
||||
fd_set.insert(r1);
|
||||
fd_set.insert(r2);
|
||||
|
||||
let mut timeout = TimeVal::seconds(10);
|
||||
assert_eq!(1, select(None,
|
||||
&mut fd_set,
|
||||
None,
|
||||
None,
|
||||
&mut timeout).unwrap());
|
||||
assert!(fd_set.contains(r1));
|
||||
assert!(!fd_set.contains(r2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_select_nfds() {
|
||||
let (r1, w1) = pipe().unwrap();
|
||||
write(w1, b"hi!").unwrap();
|
||||
let (r2, _w2) = pipe().unwrap();
|
||||
|
||||
let mut fd_set = FdSet::new();
|
||||
fd_set.insert(r1);
|
||||
fd_set.insert(r2);
|
||||
|
||||
let mut timeout = TimeVal::seconds(10);
|
||||
assert_eq!(1, select(Some(fd_set.highest().unwrap() + 1),
|
||||
&mut fd_set,
|
||||
None,
|
||||
None,
|
||||
&mut timeout).unwrap());
|
||||
assert!(fd_set.contains(r1));
|
||||
assert!(!fd_set.contains(r2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_select_nfds2() {
|
||||
let (r1, w1) = pipe().unwrap();
|
||||
write(w1, b"hi!").unwrap();
|
||||
let (r2, _w2) = pipe().unwrap();
|
||||
|
||||
let mut fd_set = FdSet::new();
|
||||
fd_set.insert(r1);
|
||||
fd_set.insert(r2);
|
||||
|
||||
let mut timeout = TimeVal::seconds(10);
|
||||
assert_eq!(1, select(::std::cmp::max(r1, r2) + 1,
|
||||
&mut fd_set,
|
||||
None,
|
||||
None,
|
||||
&mut timeout).unwrap());
|
||||
assert!(fd_set.contains(r1));
|
||||
assert!(!fd_set.contains(r2));
|
||||
}
|
||||
}
|
231
vendor/nix-v0.23.1-patched/src/sys/sendfile.rs
vendored
231
vendor/nix-v0.23.1-patched/src/sys/sendfile.rs
vendored
|
@ -1,231 +0,0 @@
|
|||
//! Send data from a file to a socket, bypassing userland.
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::ptr;
|
||||
|
||||
use libc::{self, off_t};
|
||||
|
||||
use crate::Result;
|
||||
use crate::errno::Errno;
|
||||
|
||||
/// 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(any(target_os = "android", target_os = "linux"))]
|
||||
pub fn sendfile(
|
||||
out_fd: RawFd,
|
||||
in_fd: RawFd,
|
||||
offset: Option<&mut off_t>,
|
||||
count: usize,
|
||||
) -> Result<usize> {
|
||||
let offset = offset
|
||||
.map(|offset| offset as *mut _)
|
||||
.unwrap_or(ptr::null_mut());
|
||||
let ret = unsafe { libc::sendfile(out_fd, in_fd, offset, count) };
|
||||
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",
|
||||
target_os = "macos"))] {
|
||||
use crate::sys::uio::IoVec;
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
struct SendfileHeaderTrailer<'a>(
|
||||
libc::sf_hdtr,
|
||||
Option<Vec<IoVec<&'a [u8]>>>,
|
||||
Option<Vec<IoVec<&'a [u8]>>>,
|
||||
);
|
||||
|
||||
impl<'a> SendfileHeaderTrailer<'a> {
|
||||
fn new(
|
||||
headers: Option<&'a [&'a [u8]]>,
|
||||
trailers: Option<&'a [&'a [u8]]>
|
||||
) -> SendfileHeaderTrailer<'a> {
|
||||
let header_iovecs: Option<Vec<IoVec<&[u8]>>> =
|
||||
headers.map(|s| s.iter().map(|b| IoVec::from_slice(b)).collect());
|
||||
let trailer_iovecs: Option<Vec<IoVec<&[u8]>>> =
|
||||
trailers.map(|s| s.iter().map(|b| IoVec::from_slice(b)).collect());
|
||||
SendfileHeaderTrailer(
|
||||
libc::sf_hdtr {
|
||||
headers: {
|
||||
header_iovecs
|
||||
.as_ref()
|
||||
.map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec
|
||||
},
|
||||
hdr_cnt: header_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32,
|
||||
trailers: {
|
||||
trailer_iovecs
|
||||
.as_ref()
|
||||
.map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec
|
||||
},
|
||||
trl_cnt: trailer_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32
|
||||
},
|
||||
header_iovecs,
|
||||
trailer_iovecs,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(target_os = "freebsd")] {
|
||||
use libc::c_int;
|
||||
|
||||
libc_bitflags!{
|
||||
/// Configuration options for [`sendfile`.](fn.sendfile.html)
|
||||
pub struct SfFlags: c_int {
|
||||
/// Causes `sendfile` to return EBUSY instead of blocking when attempting to read a
|
||||
/// busy page.
|
||||
SF_NODISKIO;
|
||||
/// Causes `sendfile` to sleep until the network stack releases its reference to the
|
||||
/// VM pages read. When `sendfile` returns, the data is not guaranteed to have been
|
||||
/// sent, but it is safe to modify the file.
|
||||
SF_SYNC;
|
||||
/// Causes `sendfile` to cache exactly the number of pages specified in the
|
||||
/// `readahead` parameter, disabling caching heuristics.
|
||||
SF_USER_READAHEAD;
|
||||
/// Causes `sendfile` not to cache the data read.
|
||||
SF_NOCACHE;
|
||||
}
|
||||
}
|
||||
|
||||
/// Read up to `count` bytes from `in_fd` starting at `offset` and write to `out_sock`.
|
||||
///
|
||||
/// Returns a `Result` and a count of bytes written. Bytes written may be non-zero even if
|
||||
/// an error occurs.
|
||||
///
|
||||
/// `in_fd` must describe a regular file or shared memory object. `out_sock` must describe a
|
||||
/// stream socket.
|
||||
///
|
||||
/// If `offset` falls past the end of the file, the function returns success and zero bytes
|
||||
/// written.
|
||||
///
|
||||
/// If `count` is `None` or 0, bytes will be read from `in_fd` until reaching the end of
|
||||
/// file (EOF).
|
||||
///
|
||||
/// `headers` and `trailers` specify optional slices of byte slices to be sent before and
|
||||
/// after the data read from `in_fd`, respectively. The length of headers and trailers sent
|
||||
/// is included in the returned count of bytes written. The values of `offset` and `count`
|
||||
/// do not apply to headers or trailers.
|
||||
///
|
||||
/// `readahead` specifies the minimum number of pages to cache in memory ahead of the page
|
||||
/// currently being sent.
|
||||
///
|
||||
/// For more information, see
|
||||
/// [the sendfile(2) man page.](https://www.freebsd.org/cgi/man.cgi?query=sendfile&sektion=2)
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn sendfile(
|
||||
in_fd: RawFd,
|
||||
out_sock: RawFd,
|
||||
offset: off_t,
|
||||
count: Option<usize>,
|
||||
headers: Option<&[&[u8]]>,
|
||||
trailers: Option<&[&[u8]]>,
|
||||
flags: SfFlags,
|
||||
readahead: u16
|
||||
) -> (Result<()>, off_t) {
|
||||
// Readahead goes in upper 16 bits
|
||||
// Flags goes in lower 16 bits
|
||||
// see `man 2 sendfile`
|
||||
let ra32 = u32::from(readahead);
|
||||
let flags: u32 = (ra32 << 16) | (flags.bits() as u32);
|
||||
let mut bytes_sent: off_t = 0;
|
||||
let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers));
|
||||
let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr);
|
||||
let return_code = unsafe {
|
||||
libc::sendfile(in_fd,
|
||||
out_sock,
|
||||
offset,
|
||||
count.unwrap_or(0),
|
||||
hdtr_ptr as *mut libc::sf_hdtr,
|
||||
&mut bytes_sent as *mut off_t,
|
||||
flags as c_int)
|
||||
};
|
||||
(Errno::result(return_code).and(Ok(())), bytes_sent)
|
||||
}
|
||||
} else if #[cfg(any(target_os = "ios", target_os = "macos"))] {
|
||||
/// Read bytes from `in_fd` starting at `offset` and write up to `count` bytes to
|
||||
/// `out_sock`.
|
||||
///
|
||||
/// Returns a `Result` and a count of bytes written. Bytes written may be non-zero even if
|
||||
/// an error occurs.
|
||||
///
|
||||
/// `in_fd` must describe a regular file. `out_sock` must describe a stream socket.
|
||||
///
|
||||
/// If `offset` falls past the end of the file, the function returns success and zero bytes
|
||||
/// written.
|
||||
///
|
||||
/// If `count` is `None` or 0, bytes will be read from `in_fd` until reaching the end of
|
||||
/// file (EOF).
|
||||
///
|
||||
/// `hdtr` specifies an optional list of headers and trailers to be sent before and after
|
||||
/// the data read from `in_fd`, respectively. The length of headers and trailers sent is
|
||||
/// included in the returned count of bytes written. If any headers are specified and
|
||||
/// `count` is non-zero, the length of the headers will be counted in the limit of total
|
||||
/// bytes sent. Trailers do not count toward the limit of bytes sent and will always be sent
|
||||
/// regardless. The value of `offset` does not affect headers or trailers.
|
||||
///
|
||||
/// For more information, see
|
||||
/// [the sendfile(2) man page.](https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man2/sendfile.2.html)
|
||||
pub fn sendfile(
|
||||
in_fd: RawFd,
|
||||
out_sock: RawFd,
|
||||
offset: off_t,
|
||||
count: Option<off_t>,
|
||||
headers: Option<&[&[u8]]>,
|
||||
trailers: Option<&[&[u8]]>
|
||||
) -> (Result<()>, off_t) {
|
||||
let mut len = count.unwrap_or(0);
|
||||
let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers));
|
||||
let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr);
|
||||
let return_code = unsafe {
|
||||
libc::sendfile(in_fd,
|
||||
out_sock,
|
||||
offset,
|
||||
&mut len as *mut off_t,
|
||||
hdtr_ptr as *mut libc::sf_hdtr,
|
||||
0)
|
||||
};
|
||||
(Errno::result(return_code).and(Ok(())), len)
|
||||
}
|
||||
}
|
||||
}
|
1234
vendor/nix-v0.23.1-patched/src/sys/signal.rs
vendored
1234
vendor/nix-v0.23.1-patched/src/sys/signal.rs
vendored
File diff suppressed because it is too large
Load diff
169
vendor/nix-v0.23.1-patched/src/sys/signalfd.rs
vendored
169
vendor/nix-v0.23.1-patched/src/sys/signalfd.rs
vendored
|
@ -1,169 +0,0 @@
|
|||
//! Interface for the `signalfd` syscall.
|
||||
//!
|
||||
//! # Signal discarding
|
||||
//! When a signal can't be delivered to a process (or thread), it will become a pending signal.
|
||||
//! Failure to deliver could happen if the signal is blocked by every thread in the process or if
|
||||
//! the signal handler is still handling a previous signal.
|
||||
//!
|
||||
//! If a signal is sent to a process (or thread) that already has a pending signal of the same
|
||||
//! type, it will be discarded. This means that if signals of the same type are received faster than
|
||||
//! they are processed, some of those signals will be dropped. Because of this limitation,
|
||||
//! `signalfd` in itself cannot be used for reliable communication between processes or threads.
|
||||
//!
|
||||
//! Once the signal is unblocked, or the signal handler is finished, and a signal is still pending
|
||||
//! (ie. not consumed from a signalfd) it will be delivered to the signal handler.
|
||||
//!
|
||||
//! Please note that signal discarding is not specific to `signalfd`, but also happens with regular
|
||||
//! signal handlers.
|
||||
use crate::unistd;
|
||||
use crate::Result;
|
||||
use crate::errno::Errno;
|
||||
pub use crate::sys::signal::{self, SigSet};
|
||||
pub use libc::signalfd_siginfo as siginfo;
|
||||
|
||||
use std::os::unix::io::{RawFd, AsRawFd};
|
||||
use std::mem;
|
||||
|
||||
|
||||
libc_bitflags!{
|
||||
pub struct SfdFlags: libc::c_int {
|
||||
SFD_NONBLOCK;
|
||||
SFD_CLOEXEC;
|
||||
}
|
||||
}
|
||||
|
||||
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>();
|
||||
|
||||
/// Creates a new file descriptor for reading signals.
|
||||
///
|
||||
/// **Important:** please read the module level documentation about signal discarding before using
|
||||
/// this function!
|
||||
///
|
||||
/// The `mask` parameter specifies the set of signals that can be accepted via this file descriptor.
|
||||
///
|
||||
/// 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)
|
||||
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()))
|
||||
}
|
||||
}
|
||||
|
||||
/// A helper struct for creating, reading and closing a `signalfd` instance.
|
||||
///
|
||||
/// **Important:** please read the module level documentation about signal discarding before using
|
||||
/// this struct!
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use nix::sys::signalfd::*;
|
||||
/// // Set the thread to block the SIGUSR1 signal, otherwise the default handler will be used
|
||||
/// let mut mask = SigSet::empty();
|
||||
/// mask.add(signal::SIGUSR1);
|
||||
/// mask.thread_block().unwrap();
|
||||
///
|
||||
/// // Signals are queued up on the file descriptor
|
||||
/// let mut sfd = SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap();
|
||||
///
|
||||
/// match sfd.read_signal() {
|
||||
/// // we caught a signal
|
||||
/// Ok(Some(sig)) => (),
|
||||
/// // there were no signals waiting (only happens when the SFD_NONBLOCK flag is set,
|
||||
/// // otherwise the read_signal call blocks)
|
||||
/// Ok(None) => (),
|
||||
/// Err(err) => (), // some error happend
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug, Eq, Hash, PartialEq)]
|
||||
pub struct SignalFd(RawFd);
|
||||
|
||||
impl SignalFd {
|
||||
pub fn new(mask: &SigSet) -> Result<SignalFd> {
|
||||
Self::with_flags(mask, SfdFlags::empty())
|
||||
}
|
||||
|
||||
pub fn with_flags(mask: &SigSet, flags: SfdFlags) -> Result<SignalFd> {
|
||||
let fd = signalfd(SIGNALFD_NEW, mask, flags)?;
|
||||
|
||||
Ok(SignalFd(fd))
|
||||
}
|
||||
|
||||
pub fn set_mask(&mut self, mask: &SigSet) -> Result<()> {
|
||||
signalfd(self.0, mask, SfdFlags::empty()).map(drop)
|
||||
}
|
||||
|
||||
pub fn read_signal(&mut self) -> Result<Option<siginfo>> {
|
||||
let mut buffer = mem::MaybeUninit::<siginfo>::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)
|
||||
}).map(|r| r as usize);
|
||||
match res {
|
||||
Ok(x) if x == size => Ok(Some(unsafe { buffer.assume_init() })),
|
||||
Ok(_) => unreachable!("partial read on signalfd"),
|
||||
Err(Errno::EAGAIN) => Ok(None),
|
||||
Err(error) => Err(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SignalFd {
|
||||
fn drop(&mut self) {
|
||||
let e = unistd::close(self.0);
|
||||
if !std::thread::panicking() && e == Err(Errno::EBADF) {
|
||||
panic!("Closing an invalid file descriptor!");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for SignalFd {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for SignalFd {
|
||||
type Item = siginfo;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.read_signal() {
|
||||
Ok(Some(sig)) => Some(sig),
|
||||
Ok(None) | Err(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn create_signalfd() {
|
||||
let mask = SigSet::empty();
|
||||
let fd = SignalFd::new(&mask);
|
||||
assert!(fd.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_signalfd_with_opts() {
|
||||
let mask = SigSet::empty();
|
||||
let fd = SignalFd::with_flags(&mask, SfdFlags::SFD_CLOEXEC | SfdFlags::SFD_NONBLOCK);
|
||||
assert!(fd.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_empty_signalfd() {
|
||||
let mask = SigSet::empty();
|
||||
let mut fd = SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap();
|
||||
|
||||
let res = fd.read_signal();
|
||||
assert!(res.unwrap().is_none());
|
||||
}
|
||||
}
|
1447
vendor/nix-v0.23.1-patched/src/sys/socket/addr.rs
vendored
1447
vendor/nix-v0.23.1-patched/src/sys/socket/addr.rs
vendored
File diff suppressed because it is too large
Load diff
1916
vendor/nix-v0.23.1-patched/src/sys/socket/mod.rs
vendored
1916
vendor/nix-v0.23.1-patched/src/sys/socket/mod.rs
vendored
File diff suppressed because it is too large
Load diff
930
vendor/nix-v0.23.1-patched/src/sys/socket/sockopt.rs
vendored
930
vendor/nix-v0.23.1-patched/src/sys/socket/sockopt.rs
vendored
|
@ -1,930 +0,0 @@
|
|||
//! Socket options as used by `setsockopt` and `getsockopt`.
|
||||
use cfg_if::cfg_if;
|
||||
use super::{GetSockOpt, SetSockOpt};
|
||||
use crate::Result;
|
||||
use crate::errno::Errno;
|
||||
use crate::sys::time::TimeVal;
|
||||
use libc::{self, c_int, c_void, socklen_t};
|
||||
use std::mem::{
|
||||
self,
|
||||
MaybeUninit
|
||||
};
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
#[cfg(target_family = "unix")]
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
||||
// Constants
|
||||
// TCP_CA_NAME_MAX isn't defined in user space include files
|
||||
#[cfg(any(target_os = "freebsd", target_os = "linux"))]
|
||||
const TCP_CA_NAME_MAX: usize = 16;
|
||||
|
||||
/// Helper for implementing `SetSockOpt` for a given socket option. See
|
||||
/// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html).
|
||||
///
|
||||
/// This macro aims to help implementing `SetSockOpt` for different socket options that accept
|
||||
/// different kinds of data to be used with `setsockopt`.
|
||||
///
|
||||
/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option
|
||||
/// you are implementing represents a simple type.
|
||||
///
|
||||
/// # 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*
|
||||
/// (`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.
|
||||
/// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
|
||||
/// `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`)
|
||||
/// to the `setsockopt` call.
|
||||
/// * Type of the value that you are going to set.
|
||||
/// * 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) => {
|
||||
impl SetSockOpt for $name {
|
||||
type Val = $ty;
|
||||
|
||||
fn set(&self, fd: RawFd, val: &$ty) -> Result<()> {
|
||||
unsafe {
|
||||
let setter: $setter = Set::new(val);
|
||||
|
||||
let res = libc::setsockopt(fd, $level, $flag,
|
||||
setter.ffi_ptr(),
|
||||
setter.ffi_len());
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper for implementing `GetSockOpt` for a given socket option. See
|
||||
/// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html).
|
||||
///
|
||||
/// This macro aims to help implementing `GetSockOpt` for different socket options that accept
|
||||
/// different kinds of data to be use with `getsockopt`.
|
||||
///
|
||||
/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option
|
||||
/// you are implementing represents a simple type.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * Name of the type you want to implement `GetSockOpt` for.
|
||||
/// * 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` call.
|
||||
/// * A flag to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
|
||||
/// `libc::SO_ORIGINAL_DST` and others. Will be passed as the third argument (`option_name`) to
|
||||
/// the `getsockopt` call.
|
||||
/// * Type of the value that you are going to get.
|
||||
/// * 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) => {
|
||||
impl GetSockOpt for $name {
|
||||
type Val = $ty;
|
||||
|
||||
fn get(&self, fd: RawFd) -> Result<$ty> {
|
||||
unsafe {
|
||||
let mut getter: $getter = Get::uninit();
|
||||
|
||||
let res = libc::getsockopt(fd, $level, $flag,
|
||||
getter.ffi_ptr(),
|
||||
getter.ffi_len());
|
||||
Errno::result(res)?;
|
||||
|
||||
Ok(getter.assume_init())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper to generate the sockopt accessors. See
|
||||
/// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html) and
|
||||
/// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html).
|
||||
///
|
||||
/// This macro aims to help implementing `GetSockOpt` and `SetSockOpt` for different socket options
|
||||
/// that accept different kinds of data to be use with `getsockopt` and `setsockopt` respectively.
|
||||
///
|
||||
/// Basically this macro wraps up the [`getsockopt_impl!`](macro.getsockopt_impl.html) and
|
||||
/// [`setsockopt_impl!`](macro.setsockopt_impl.html) macros.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `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*
|
||||
/// (`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.
|
||||
/// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
|
||||
/// `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`)
|
||||
/// to the `setsockopt`/`getsockopt` call.
|
||||
/// * `$ty:ty`: type of the value that will be get/set.
|
||||
/// * `$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);
|
||||
};
|
||||
|
||||
($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, u8) => {
|
||||
sockopt_impl!($(#[$attr])* $name, GetOnly, $level, $flag, u8, GetU8);
|
||||
};
|
||||
|
||||
($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, usize) =>
|
||||
{
|
||||
sockopt_impl!($(#[$attr])*
|
||||
$name, GetOnly, $level, $flag, usize, GetUsize);
|
||||
};
|
||||
|
||||
($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, bool) => {
|
||||
sockopt_impl!($(#[$attr])*
|
||||
$name, SetOnly, $level, $flag, bool, SetBool);
|
||||
};
|
||||
|
||||
($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, u8) => {
|
||||
sockopt_impl!($(#[$attr])* $name, SetOnly, $level, $flag, u8, SetU8);
|
||||
};
|
||||
|
||||
($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, usize) =>
|
||||
{
|
||||
sockopt_impl!($(#[$attr])*
|
||||
$name, SetOnly, $level, $flag, usize, SetUsize);
|
||||
};
|
||||
|
||||
($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, bool) => {
|
||||
sockopt_impl!($(#[$attr])*
|
||||
$name, Both, $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);
|
||||
};
|
||||
|
||||
($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, usize) => {
|
||||
sockopt_impl!($(#[$attr])*
|
||||
$name, Both, $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);
|
||||
};
|
||||
|
||||
/*
|
||||
* 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>);
|
||||
};
|
||||
|
||||
($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty,
|
||||
$getter:ty) =>
|
||||
{
|
||||
$(#[$attr])*
|
||||
#[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>);
|
||||
};
|
||||
|
||||
($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty,
|
||||
$setter:ty) =>
|
||||
{
|
||||
$(#[$attr])*
|
||||
#[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])*
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct $name;
|
||||
|
||||
setsockopt_impl!($name, $level, $flag, $ty, $setter);
|
||||
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>);
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== Define sockopts =====
|
||||
*
|
||||
*/
|
||||
|
||||
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);
|
||||
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);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
#[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);
|
||||
#[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);
|
||||
#[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);
|
||||
}
|
||||
}
|
||||
#[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);
|
||||
#[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);
|
||||
#[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);
|
||||
#[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]>);
|
||||
#[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);
|
||||
#[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);
|
||||
#[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);
|
||||
#[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);
|
||||
#[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);
|
||||
#[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);
|
||||
#[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);
|
||||
#[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]>);
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
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);
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
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);
|
||||
#[cfg(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
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);
|
||||
#[cfg(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
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);
|
||||
#[cfg(target_os = "linux")]
|
||||
sockopt_impl!(
|
||||
#[allow(missing_docs)]
|
||||
// Not documented by Linux!
|
||||
UdpGsoSegment, Both, 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!
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct AlgSetAeadAuthSize;
|
||||
|
||||
// ALG_SET_AEAD_AUTH_SIZE read the length from passed `option_len`
|
||||
// See https://elixir.bootlin.com/linux/v4.4/source/crypto/af_alg.c#L222
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
impl SetSockOpt for AlgSetAeadAuthSize {
|
||||
type Val = usize;
|
||||
|
||||
fn set(&self, fd: RawFd, val: &usize) -> Result<()> {
|
||||
unsafe {
|
||||
let res = libc::setsockopt(fd,
|
||||
libc::SOL_ALG,
|
||||
libc::ALG_SET_AEAD_AUTHSIZE,
|
||||
::std::ptr::null(),
|
||||
*val as libc::socklen_t);
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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>);
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
impl<T> Default for AlgSetKey<T> {
|
||||
fn default() -> Self {
|
||||
AlgSetKey(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
impl<T> SetSockOpt for AlgSetKey<T> where T: AsRef<[u8]> + Clone {
|
||||
type Val = T;
|
||||
|
||||
fn set(&self, fd: RawFd, val: &T) -> Result<()> {
|
||||
unsafe {
|
||||
let res = libc::setsockopt(fd,
|
||||
libc::SOL_ALG,
|
||||
libc::ALG_SET_KEY,
|
||||
val.as_ref().as_ptr() as *const _,
|
||||
val.as_ref().len() as libc::socklen_t);
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== Accessor helpers =====
|
||||
*
|
||||
*/
|
||||
|
||||
/// Helper trait that describes what is expected from a `GetSockOpt` getter.
|
||||
trait Get<T> {
|
||||
/// Returns an uninitialized value.
|
||||
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;
|
||||
/// Returns length of the stored value. This pointer will be passed to the system's
|
||||
/// `getsockopt` call (`man 3p getsockopt`, argument `option_len`).
|
||||
fn ffi_len(&mut self) -> *mut socklen_t;
|
||||
/// Returns the hopefully initialized inner value.
|
||||
unsafe fn assume_init(self) -> T;
|
||||
}
|
||||
|
||||
/// Helper trait that describes what is expected from a `SetSockOpt` setter.
|
||||
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
|
||||
/// `setsockopt` call (`man 3p setsockopt`, argument `option_value`).
|
||||
fn ffi_ptr(&self) -> *const c_void;
|
||||
/// Returns length of the stored value. This pointer will be passed to the system's
|
||||
/// `setsockopt` call (`man 3p setsockopt`, argument `option_len`).
|
||||
fn ffi_len(&self) -> socklen_t;
|
||||
}
|
||||
|
||||
/// Getter for an arbitrary `struct`.
|
||||
struct GetStruct<T> {
|
||||
len: socklen_t,
|
||||
val: MaybeUninit<T>,
|
||||
}
|
||||
|
||||
impl<T> Get<T> for GetStruct<T> {
|
||||
fn uninit() -> Self {
|
||||
GetStruct {
|
||||
len: mem::size_of::<T>() as socklen_t,
|
||||
val: MaybeUninit::uninit(),
|
||||
}
|
||||
}
|
||||
|
||||
fn ffi_ptr(&mut self) -> *mut c_void {
|
||||
self.val.as_mut_ptr() as *mut c_void
|
||||
}
|
||||
|
||||
fn ffi_len(&mut self) -> *mut socklen_t {
|
||||
&mut self.len
|
||||
}
|
||||
|
||||
unsafe fn assume_init(self) -> T {
|
||||
assert_eq!(self.len as usize, mem::size_of::<T>(), "invalid getsockopt implementation");
|
||||
self.val.assume_init()
|
||||
}
|
||||
}
|
||||
|
||||
/// Setter for an arbitrary `struct`.
|
||||
struct SetStruct<'a, T: 'static> {
|
||||
ptr: &'a T,
|
||||
}
|
||||
|
||||
impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
|
||||
fn new(ptr: &'a T) -> SetStruct<'a, T> {
|
||||
SetStruct { ptr }
|
||||
}
|
||||
|
||||
fn ffi_ptr(&self) -> *const c_void {
|
||||
self.ptr as *const T as *const c_void
|
||||
}
|
||||
|
||||
fn ffi_len(&self) -> socklen_t {
|
||||
mem::size_of::<T>() as socklen_t
|
||||
}
|
||||
}
|
||||
|
||||
/// Getter for a boolean value.
|
||||
struct GetBool {
|
||||
len: socklen_t,
|
||||
val: MaybeUninit<c_int>,
|
||||
}
|
||||
|
||||
impl Get<bool> for GetBool {
|
||||
fn uninit() -> Self {
|
||||
GetBool {
|
||||
len: mem::size_of::<c_int>() as socklen_t,
|
||||
val: MaybeUninit::uninit(),
|
||||
}
|
||||
}
|
||||
|
||||
fn ffi_ptr(&mut self) -> *mut c_void {
|
||||
self.val.as_mut_ptr() as *mut c_void
|
||||
}
|
||||
|
||||
fn ffi_len(&mut self) -> *mut socklen_t {
|
||||
&mut self.len
|
||||
}
|
||||
|
||||
unsafe fn assume_init(self) -> bool {
|
||||
assert_eq!(self.len as usize, mem::size_of::<c_int>(), "invalid getsockopt implementation");
|
||||
self.val.assume_init() != 0
|
||||
}
|
||||
}
|
||||
|
||||
/// Setter for a boolean value.
|
||||
struct SetBool {
|
||||
val: c_int,
|
||||
}
|
||||
|
||||
impl<'a> Set<'a, bool> for SetBool {
|
||||
fn new(val: &'a bool) -> SetBool {
|
||||
SetBool { val: if *val { 1 } else { 0 } }
|
||||
}
|
||||
|
||||
fn ffi_ptr(&self) -> *const c_void {
|
||||
&self.val as *const c_int as *const c_void
|
||||
}
|
||||
|
||||
fn ffi_len(&self) -> socklen_t {
|
||||
mem::size_of::<c_int>() as socklen_t
|
||||
}
|
||||
}
|
||||
|
||||
/// Getter for an `u8` value.
|
||||
struct GetU8 {
|
||||
len: socklen_t,
|
||||
val: MaybeUninit<u8>,
|
||||
}
|
||||
|
||||
impl Get<u8> for GetU8 {
|
||||
fn uninit() -> Self {
|
||||
GetU8 {
|
||||
len: mem::size_of::<u8>() as socklen_t,
|
||||
val: MaybeUninit::uninit(),
|
||||
}
|
||||
}
|
||||
|
||||
fn ffi_ptr(&mut self) -> *mut c_void {
|
||||
self.val.as_mut_ptr() as *mut c_void
|
||||
}
|
||||
|
||||
fn ffi_len(&mut self) -> *mut socklen_t {
|
||||
&mut self.len
|
||||
}
|
||||
|
||||
unsafe fn assume_init(self) -> u8 {
|
||||
assert_eq!(self.len as usize, mem::size_of::<u8>(), "invalid getsockopt implementation");
|
||||
self.val.assume_init()
|
||||
}
|
||||
}
|
||||
|
||||
/// Setter for an `u8` value.
|
||||
struct SetU8 {
|
||||
val: u8,
|
||||
}
|
||||
|
||||
impl<'a> Set<'a, u8> for SetU8 {
|
||||
fn new(val: &'a u8) -> SetU8 {
|
||||
SetU8 { val: *val as u8 }
|
||||
}
|
||||
|
||||
fn ffi_ptr(&self) -> *const c_void {
|
||||
&self.val as *const u8 as *const c_void
|
||||
}
|
||||
|
||||
fn ffi_len(&self) -> socklen_t {
|
||||
mem::size_of::<c_int>() as socklen_t
|
||||
}
|
||||
}
|
||||
|
||||
/// Getter for an `usize` value.
|
||||
struct GetUsize {
|
||||
len: socklen_t,
|
||||
val: MaybeUninit<c_int>,
|
||||
}
|
||||
|
||||
impl Get<usize> for GetUsize {
|
||||
fn uninit() -> Self {
|
||||
GetUsize {
|
||||
len: mem::size_of::<c_int>() as socklen_t,
|
||||
val: MaybeUninit::uninit(),
|
||||
}
|
||||
}
|
||||
|
||||
fn ffi_ptr(&mut self) -> *mut c_void {
|
||||
self.val.as_mut_ptr() as *mut c_void
|
||||
}
|
||||
|
||||
fn ffi_len(&mut self) -> *mut socklen_t {
|
||||
&mut self.len
|
||||
}
|
||||
|
||||
unsafe fn assume_init(self) -> usize {
|
||||
assert_eq!(self.len as usize, mem::size_of::<c_int>(), "invalid getsockopt implementation");
|
||||
self.val.assume_init() as usize
|
||||
}
|
||||
}
|
||||
|
||||
/// Setter for an `usize` value.
|
||||
struct SetUsize {
|
||||
val: c_int,
|
||||
}
|
||||
|
||||
impl<'a> Set<'a, usize> for SetUsize {
|
||||
fn new(val: &'a usize) -> SetUsize {
|
||||
SetUsize { val: *val as c_int }
|
||||
}
|
||||
|
||||
fn ffi_ptr(&self) -> *const c_void {
|
||||
&self.val as *const c_int as *const c_void
|
||||
}
|
||||
|
||||
fn ffi_len(&self) -> socklen_t {
|
||||
mem::size_of::<c_int>() as socklen_t
|
||||
}
|
||||
}
|
||||
|
||||
/// Getter for a `OsString` value.
|
||||
struct GetOsString<T: AsMut<[u8]>> {
|
||||
len: socklen_t,
|
||||
val: MaybeUninit<T>,
|
||||
}
|
||||
|
||||
impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
|
||||
fn uninit() -> Self {
|
||||
GetOsString {
|
||||
len: mem::size_of::<T>() as socklen_t,
|
||||
val: MaybeUninit::uninit(),
|
||||
}
|
||||
}
|
||||
|
||||
fn ffi_ptr(&mut self) -> *mut c_void {
|
||||
self.val.as_mut_ptr() as *mut c_void
|
||||
}
|
||||
|
||||
fn ffi_len(&mut self) -> *mut socklen_t {
|
||||
&mut self.len
|
||||
}
|
||||
|
||||
unsafe fn assume_init(self) -> OsString {
|
||||
let len = self.len as usize;
|
||||
let mut v = self.val.assume_init();
|
||||
OsStr::from_bytes(&v.as_mut()[0..len]).to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
/// Setter for a `OsString` value.
|
||||
struct SetOsString<'a> {
|
||||
val: &'a OsStr,
|
||||
}
|
||||
|
||||
impl<'a> Set<'a, OsString> for SetOsString<'a> {
|
||||
fn new(val: &'a OsString) -> SetOsString {
|
||||
SetOsString { val: val.as_os_str() }
|
||||
}
|
||||
|
||||
fn ffi_ptr(&self) -> *const c_void {
|
||||
self.val.as_bytes().as_ptr() as *const c_void
|
||||
}
|
||||
|
||||
fn ffi_len(&self) -> socklen_t {
|
||||
self.val.len() as socklen_t
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[test]
|
||||
fn can_get_peercred_on_unix_socket() {
|
||||
use super::super::*;
|
||||
|
||||
let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
|
||||
let a_cred = getsockopt(a, super::PeerCredentials).unwrap();
|
||||
let b_cred = getsockopt(b, super::PeerCredentials).unwrap();
|
||||
assert_eq!(a_cred, b_cred);
|
||||
assert!(a_cred.pid() != 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_socket_type_unix() {
|
||||
use super::super::*;
|
||||
use crate::unistd::close;
|
||||
|
||||
let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
|
||||
let a_type = getsockopt(a, super::SockType).unwrap();
|
||||
assert_eq!(a_type, SockType::Stream);
|
||||
close(a).unwrap();
|
||||
close(b).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_socket_type_dgram() {
|
||||
use super::super::*;
|
||||
use crate::unistd::close;
|
||||
|
||||
let s = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap();
|
||||
let s_type = getsockopt(s, super::SockType).unwrap();
|
||||
assert_eq!(s_type, SockType::Datagram);
|
||||
close(s).unwrap();
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "freebsd",
|
||||
target_os = "linux",
|
||||
target_os = "nacl"))]
|
||||
#[test]
|
||||
fn can_get_listen_on_tcp_socket() {
|
||||
use super::super::*;
|
||||
use crate::unistd::close;
|
||||
|
||||
let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
|
||||
let s_listening = getsockopt(s, super::AcceptConn).unwrap();
|
||||
assert!(!s_listening);
|
||||
listen(s, 10).unwrap();
|
||||
let s_listening2 = getsockopt(s, super::AcceptConn).unwrap();
|
||||
assert!(s_listening2);
|
||||
close(s).unwrap();
|
||||
}
|
||||
|
||||
}
|
315
vendor/nix-v0.23.1-patched/src/sys/stat.rs
vendored
315
vendor/nix-v0.23.1-patched/src/sys/stat.rs
vendored
|
@ -1,315 +0,0 @@
|
|||
pub use libc::{dev_t, mode_t};
|
||||
pub use libc::stat as FileStat;
|
||||
|
||||
use crate::{Result, NixPath, errno::Errno};
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use crate::fcntl::{AtFlags, at_rawfd};
|
||||
use std::mem;
|
||||
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;
|
||||
S_IFDIR;
|
||||
S_IFBLK;
|
||||
S_IFREG;
|
||||
S_IFLNK;
|
||||
S_IFSOCK;
|
||||
S_IFMT;
|
||||
}
|
||||
);
|
||||
|
||||
libc_bitflags! {
|
||||
/// "File mode / permissions" flags.
|
||||
pub struct Mode: mode_t {
|
||||
S_IRWXU;
|
||||
S_IRUSR;
|
||||
S_IWUSR;
|
||||
S_IXUSR;
|
||||
S_IRWXG;
|
||||
S_IRGRP;
|
||||
S_IWGRP;
|
||||
S_IXGRP;
|
||||
S_IRWXO;
|
||||
S_IROTH;
|
||||
S_IWOTH;
|
||||
S_IXOTH;
|
||||
S_ISUID as mode_t;
|
||||
S_ISGID as mode_t;
|
||||
S_ISVTX as mode_t;
|
||||
}
|
||||
}
|
||||
|
||||
/// 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)
|
||||
})?;
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub const 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 {
|
||||
((dev >> 12) & 0xffff_ff00) |
|
||||
((dev ) & 0x0000_00ff)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub const fn makedev(major: u64, minor: u64) -> dev_t {
|
||||
((major & 0xffff_f000) << 32) |
|
||||
((major & 0x0000_0fff) << 8) |
|
||||
((minor & 0xffff_ff00) << 12) |
|
||||
(minor & 0x0000_00ff)
|
||||
}
|
||||
|
||||
pub fn umask(mode: Mode) -> Mode {
|
||||
let prev = unsafe { libc::umask(mode.bits() as mode_t) };
|
||||
Mode::from_bits(prev).expect("[BUG] umask returned invalid Mode")
|
||||
}
|
||||
|
||||
pub fn stat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
|
||||
let mut dst = mem::MaybeUninit::uninit();
|
||||
let res = path.with_nix_path(|cstr| {
|
||||
unsafe {
|
||||
libc::stat(cstr.as_ptr(), dst.as_mut_ptr())
|
||||
}
|
||||
})?;
|
||||
|
||||
Errno::result(res)?;
|
||||
|
||||
Ok(unsafe{dst.assume_init()})
|
||||
}
|
||||
|
||||
pub fn lstat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
|
||||
let mut dst = mem::MaybeUninit::uninit();
|
||||
let res = path.with_nix_path(|cstr| {
|
||||
unsafe {
|
||||
libc::lstat(cstr.as_ptr(), dst.as_mut_ptr())
|
||||
}
|
||||
})?;
|
||||
|
||||
Errno::result(res)?;
|
||||
|
||||
Ok(unsafe{dst.assume_init()})
|
||||
}
|
||||
|
||||
pub fn fstat(fd: RawFd) -> Result<FileStat> {
|
||||
let mut dst = mem::MaybeUninit::uninit();
|
||||
let res = unsafe { libc::fstat(fd, dst.as_mut_ptr()) };
|
||||
|
||||
Errno::result(res)?;
|
||||
|
||||
Ok(unsafe{dst.assume_init()})
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
pub fn fstatat<P: ?Sized + NixPath>(dirfd: RawFd, pathname: &P, f: AtFlags) -> Result<FileStat> {
|
||||
let mut dst = mem::MaybeUninit::uninit();
|
||||
let res = pathname.with_nix_path(|cstr| {
|
||||
unsafe { libc::fstatat(dirfd, cstr.as_ptr(), dst.as_mut_ptr(), f.bits() as libc::c_int) }
|
||||
})?;
|
||||
|
||||
Errno::result(res)?;
|
||||
|
||||
Ok(unsafe{dst.assume_init()})
|
||||
}
|
||||
|
||||
/// Change the file permission bits of the file specified by a file descriptor.
|
||||
///
|
||||
/// # References
|
||||
///
|
||||
/// [fchmod(2)](https://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) };
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
/// Flags for `fchmodat` function.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum FchmodatFlags {
|
||||
FollowSymlink,
|
||||
NoFollowSymlink,
|
||||
}
|
||||
|
||||
/// Change the file permission bits.
|
||||
///
|
||||
/// The file to be changed is determined relative to the directory associated
|
||||
/// with the file descriptor `dirfd` or the current working directory
|
||||
/// if `dirfd` is `None`.
|
||||
///
|
||||
/// If `flag` is `FchmodatFlags::NoFollowSymlink` and `path` names a symbolic link,
|
||||
/// then the mode of the symbolic link is changed.
|
||||
///
|
||||
/// `fchmodat(None, path, mode, FchmodatFlags::FollowSymlink)` is identical to
|
||||
/// a call `libc::chmod(path, mode)`. That's why `chmod` is unimplemented
|
||||
/// in the `nix` crate.
|
||||
///
|
||||
/// # References
|
||||
///
|
||||
/// [fchmodat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html).
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
pub fn fchmodat<P: ?Sized + NixPath>(
|
||||
dirfd: Option<RawFd>,
|
||||
path: &P,
|
||||
mode: Mode,
|
||||
flag: FchmodatFlags,
|
||||
) -> Result<()> {
|
||||
let atflag =
|
||||
match flag {
|
||||
FchmodatFlags::FollowSymlink => AtFlags::empty(),
|
||||
FchmodatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
|
||||
};
|
||||
let res = path.with_nix_path(|cstr| unsafe {
|
||||
libc::fchmodat(
|
||||
at_rawfd(dirfd),
|
||||
cstr.as_ptr(),
|
||||
mode.bits() as mode_t,
|
||||
atflag.bits() as libc::c_int,
|
||||
)
|
||||
})?;
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
/// Change the access and modification times of a file.
|
||||
///
|
||||
/// `utimes(path, times)` is identical to
|
||||
/// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)`. The former
|
||||
/// is a deprecated API so prefer using the latter if the platforms you care
|
||||
/// about support it.
|
||||
///
|
||||
/// # References
|
||||
///
|
||||
/// [utimes(2)](https://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 {
|
||||
libc::utimes(cstr.as_ptr(), ×[0])
|
||||
})?;
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
/// Change the access and modification times of a file without following symlinks.
|
||||
///
|
||||
/// `lutimes(path, times)` is identical to
|
||||
/// `utimensat(None, path, times, UtimensatFlags::NoFollowSymlink)`. The former
|
||||
/// is a deprecated API so prefer using the latter if the platforms you care
|
||||
/// about support it.
|
||||
///
|
||||
/// # References
|
||||
///
|
||||
/// [lutimes(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/lutimes.html).
|
||||
#[cfg(any(target_os = "linux",
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd"))]
|
||||
pub fn lutimes<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 {
|
||||
libc::lutimes(cstr.as_ptr(), ×[0])
|
||||
})?;
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
/// Change the access and modification times of the file specified by a file descriptor.
|
||||
///
|
||||
/// # References
|
||||
///
|
||||
/// [futimens(2)](https://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()];
|
||||
let res = unsafe { libc::futimens(fd, ×[0]) };
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
/// Flags for `utimensat` function.
|
||||
// TODO: replace with fcntl::AtFlags
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum UtimensatFlags {
|
||||
FollowSymlink,
|
||||
NoFollowSymlink,
|
||||
}
|
||||
|
||||
/// Change the access and modification times of a file.
|
||||
///
|
||||
/// The file to be changed is determined relative to the directory associated
|
||||
/// with the file descriptor `dirfd` or the current working directory
|
||||
/// if `dirfd` is `None`.
|
||||
///
|
||||
/// If `flag` is `UtimensatFlags::NoFollowSymlink` and `path` names a symbolic link,
|
||||
/// then the mode of the symbolic link is changed.
|
||||
///
|
||||
/// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)` is identical to
|
||||
/// `utimes(path, times)`. The latter is a deprecated API so prefer using the
|
||||
/// former if the platforms you care about support it.
|
||||
///
|
||||
/// # References
|
||||
///
|
||||
/// [utimensat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimens.html).
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
pub fn utimensat<P: ?Sized + NixPath>(
|
||||
dirfd: Option<RawFd>,
|
||||
path: &P,
|
||||
atime: &TimeSpec,
|
||||
mtime: &TimeSpec,
|
||||
flag: UtimensatFlags
|
||||
) -> Result<()> {
|
||||
let atflag =
|
||||
match flag {
|
||||
UtimensatFlags::FollowSymlink => AtFlags::empty(),
|
||||
UtimensatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
|
||||
};
|
||||
let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
|
||||
let res = path.with_nix_path(|cstr| unsafe {
|
||||
libc::utimensat(
|
||||
at_rawfd(dirfd),
|
||||
cstr.as_ptr(),
|
||||
×[0],
|
||||
atflag.bits() as libc::c_int,
|
||||
)
|
||||
})?;
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
pub fn mkdirat<P: ?Sized + NixPath>(fd: RawFd, path: &P, mode: Mode) -> Result<()> {
|
||||
let res = path.with_nix_path(|cstr| {
|
||||
unsafe { libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t) }
|
||||
})?;
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
622
vendor/nix-v0.23.1-patched/src/sys/statfs.rs
vendored
622
vendor/nix-v0.23.1-patched/src/sys/statfs.rs
vendored
|
@ -1,622 +0,0 @@
|
|||
//! 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;
|
||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||
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);
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
type fs_type_t = u32;
|
||||
#[cfg(target_os = "android")]
|
||||
type fs_type_t = libc::c_ulong;
|
||||
#[cfg(all(target_os = "linux", target_arch = "s390x"))]
|
||||
type fs_type_t = libc::c_uint;
|
||||
#[cfg(all(target_os = "linux", target_env = "musl"))]
|
||||
type fs_type_t = libc::c_ulong;
|
||||
#[cfg(all(target_os = "linux", 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",
|
||||
all(target_os = "linux", target_arch = "s390x"),
|
||||
all(target_os = "linux", target_env = "musl"),
|
||||
all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))),
|
||||
))]
|
||||
#[derive(Eq, Copy, Clone, PartialEq, Debug)]
|
||||
pub struct FsType(pub 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);
|
||||
|
||||
|
||||
impl Statfs {
|
||||
/// Magic code defining system type
|
||||
#[cfg(not(any(
|
||||
target_os = "openbsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "ios",
|
||||
target_os = "macos"
|
||||
)))]
|
||||
pub fn filesystem_type(&self) -> FsType {
|
||||
FsType(self.0.f_type)
|
||||
}
|
||||
|
||||
/// Magic code defining system type
|
||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||
pub fn filesystem_type_name(&self) -> &str {
|
||||
let c_str = unsafe { CStr::from_ptr(self.0.f_fstypename.as_ptr()) };
|
||||
c_str.to_str().unwrap()
|
||||
}
|
||||
|
||||
/// Optimal transfer block size
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
pub fn optimal_transfer_size(&self) -> i32 {
|
||||
self.0.f_iosize
|
||||
}
|
||||
|
||||
/// Optimal transfer block size
|
||||
#[cfg(target_os = "openbsd")]
|
||||
pub fn optimal_transfer_size(&self) -> u32 {
|
||||
self.0.f_iosize
|
||||
}
|
||||
|
||||
/// Optimal transfer block size
|
||||
#[cfg(all(target_os = "linux", target_arch = "s390x"))]
|
||||
pub fn optimal_transfer_size(&self) -> u32 {
|
||||
self.0.f_bsize
|
||||
}
|
||||
|
||||
/// Optimal transfer block size
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
all(target_os = "linux", target_env = "musl")
|
||||
))]
|
||||
pub fn optimal_transfer_size(&self) -> libc::c_ulong {
|
||||
self.0.f_bsize
|
||||
}
|
||||
|
||||
/// Optimal transfer block size
|
||||
#[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
|
||||
pub fn optimal_transfer_size(&self) -> libc::__fsword_t {
|
||||
self.0.f_bsize
|
||||
}
|
||||
|
||||
/// Optimal transfer block size
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
pub fn optimal_transfer_size(&self) -> libc::c_long {
|
||||
self.0.f_iosize
|
||||
}
|
||||
|
||||
/// Optimal transfer block size
|
||||
#[cfg(target_os = "freebsd")]
|
||||
pub fn optimal_transfer_size(&self) -> u64 {
|
||||
self.0.f_iosize
|
||||
}
|
||||
|
||||
/// Size of a block
|
||||
#[cfg(any(target_os = "ios", target_os = "macos", target_os = "openbsd"))]
|
||||
pub fn block_size(&self) -> u32 {
|
||||
self.0.f_bsize
|
||||
}
|
||||
|
||||
/// Size of a block
|
||||
// f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
|
||||
#[cfg(all(target_os = "linux", target_arch = "s390x"))]
|
||||
pub fn block_size(&self) -> u32 {
|
||||
self.0.f_bsize
|
||||
}
|
||||
|
||||
/// Size of a block
|
||||
// f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
|
||||
#[cfg(all(target_os = "linux", target_env = "musl"))]
|
||||
pub fn block_size(&self) -> libc::c_ulong {
|
||||
self.0.f_bsize
|
||||
}
|
||||
|
||||
/// Size of a block
|
||||
// f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
|
||||
#[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
|
||||
pub fn block_size(&self) -> libc::__fsword_t {
|
||||
self.0.f_bsize
|
||||
}
|
||||
|
||||
/// Size of a block
|
||||
#[cfg(target_os = "freebsd")]
|
||||
pub fn block_size(&self) -> u64 {
|
||||
self.0.f_bsize
|
||||
}
|
||||
|
||||
/// Size of a block
|
||||
#[cfg(target_os = "android")]
|
||||
pub fn block_size(&self) -> libc::c_ulong {
|
||||
self.0.f_bsize
|
||||
}
|
||||
|
||||
/// Size of a block
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
pub fn block_size(&self) -> libc::c_long {
|
||||
self.0.f_bsize
|
||||
}
|
||||
|
||||
/// Maximum length of filenames
|
||||
#[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
|
||||
pub fn maximum_name_length(&self) -> u32 {
|
||||
self.0.f_namemax
|
||||
}
|
||||
|
||||
/// Maximum length of filenames
|
||||
#[cfg(all(target_os = "linux", target_arch = "s390x"))]
|
||||
pub fn maximum_name_length(&self) -> u32 {
|
||||
self.0.f_namelen
|
||||
}
|
||||
|
||||
/// Maximum length of filenames
|
||||
#[cfg(all(target_os = "linux", target_env = "musl"))]
|
||||
pub fn maximum_name_length(&self) -> libc::c_ulong {
|
||||
self.0.f_namelen
|
||||
}
|
||||
|
||||
/// Maximum length of filenames
|
||||
#[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
|
||||
pub fn maximum_name_length(&self) -> libc::__fsword_t {
|
||||
self.0.f_namelen
|
||||
}
|
||||
|
||||
/// Maximum length of filenames
|
||||
#[cfg(target_os = "android")]
|
||||
pub fn maximum_name_length(&self) -> libc::c_ulong {
|
||||
self.0.f_namelen
|
||||
}
|
||||
|
||||
/// Total data blocks in filesystem
|
||||
#[cfg(any(
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "openbsd",
|
||||
))]
|
||||
pub fn blocks(&self) -> u64 {
|
||||
self.0.f_blocks
|
||||
}
|
||||
|
||||
/// Total data blocks in filesystem
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
pub fn blocks(&self) -> libc::c_long {
|
||||
self.0.f_blocks
|
||||
}
|
||||
|
||||
/// Total data blocks in filesystem
|
||||
#[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
|
||||
pub fn blocks(&self) -> u64 {
|
||||
self.0.f_blocks
|
||||
}
|
||||
|
||||
/// Total data blocks in filesystem
|
||||
#[cfg(not(any(
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "dragonfly",
|
||||
all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32")))
|
||||
)))]
|
||||
pub fn blocks(&self) -> libc::c_ulong {
|
||||
self.0.f_blocks
|
||||
}
|
||||
|
||||
/// Free blocks in filesystem
|
||||
#[cfg(any(
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "openbsd",
|
||||
))]
|
||||
pub fn blocks_free(&self) -> u64 {
|
||||
self.0.f_bfree
|
||||
}
|
||||
|
||||
/// Free blocks in filesystem
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
pub fn blocks_free(&self) -> libc::c_long {
|
||||
self.0.f_bfree
|
||||
}
|
||||
|
||||
/// Free blocks in filesystem
|
||||
#[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
|
||||
pub fn blocks_free(&self) -> u64 {
|
||||
self.0.f_bfree
|
||||
}
|
||||
|
||||
/// Free blocks in filesystem
|
||||
#[cfg(not(any(
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "dragonfly",
|
||||
all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32")))
|
||||
)))]
|
||||
pub fn blocks_free(&self) -> libc::c_ulong {
|
||||
self.0.f_bfree
|
||||
}
|
||||
|
||||
/// Free blocks available to unprivileged user
|
||||
#[cfg(any(target_os = "ios", target_os = "macos", target_os = "android"))]
|
||||
pub fn blocks_available(&self) -> u64 {
|
||||
self.0.f_bavail
|
||||
}
|
||||
|
||||
/// Free blocks available to unprivileged user
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
pub fn blocks_available(&self) -> libc::c_long {
|
||||
self.0.f_bavail
|
||||
}
|
||||
|
||||
/// Free blocks available to unprivileged user
|
||||
#[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
|
||||
pub fn blocks_available(&self) -> i64 {
|
||||
self.0.f_bavail
|
||||
}
|
||||
|
||||
/// Free blocks available to unprivileged user
|
||||
#[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
|
||||
pub fn blocks_available(&self) -> u64 {
|
||||
self.0.f_bavail
|
||||
}
|
||||
|
||||
/// Free blocks available to unprivileged user
|
||||
#[cfg(not(any(
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "dragonfly",
|
||||
all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32")))
|
||||
)))]
|
||||
pub fn blocks_available(&self) -> libc::c_ulong {
|
||||
self.0.f_bavail
|
||||
}
|
||||
|
||||
/// Total file nodes in filesystem
|
||||
#[cfg(any(
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "openbsd",
|
||||
))]
|
||||
pub fn files(&self) -> u64 {
|
||||
self.0.f_files
|
||||
}
|
||||
|
||||
/// Total file nodes in filesystem
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
pub fn files(&self) -> libc::c_long {
|
||||
self.0.f_files
|
||||
}
|
||||
|
||||
/// Total file nodes in filesystem
|
||||
#[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
|
||||
pub fn files(&self) -> libc::fsfilcnt_t {
|
||||
self.0.f_files
|
||||
}
|
||||
|
||||
/// Total file nodes in filesystem
|
||||
#[cfg(not(any(
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "dragonfly",
|
||||
all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32")))
|
||||
)))]
|
||||
pub fn files(&self) -> libc::c_ulong {
|
||||
self.0.f_files
|
||||
}
|
||||
|
||||
/// Free file nodes in filesystem
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
pub fn files_free(&self) -> u64 {
|
||||
self.0.f_ffree
|
||||
}
|
||||
|
||||
/// Free file nodes in filesystem
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
pub fn files_free(&self) -> libc::c_long {
|
||||
self.0.f_ffree
|
||||
}
|
||||
|
||||
/// Free file nodes in filesystem
|
||||
#[cfg(target_os = "freebsd")]
|
||||
pub fn files_free(&self) -> i64 {
|
||||
self.0.f_ffree
|
||||
}
|
||||
|
||||
/// Free file nodes in filesystem
|
||||
#[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
|
||||
pub fn files_free(&self) -> libc::fsfilcnt_t {
|
||||
self.0.f_ffree
|
||||
}
|
||||
|
||||
/// Free file nodes in filesystem
|
||||
#[cfg(not(any(
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "dragonfly",
|
||||
all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32")))
|
||||
)))]
|
||||
pub fn files_free(&self) -> libc::c_ulong {
|
||||
self.0.f_ffree
|
||||
}
|
||||
|
||||
/// Filesystem ID
|
||||
pub fn filesystem_id(&self) -> fsid_t {
|
||||
self.0.f_fsid
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Statfs {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("Statfs")
|
||||
.field("optimal_transfer_size", &self.optimal_transfer_size())
|
||||
.field("block_size", &self.block_size())
|
||||
.field("blocks", &self.blocks())
|
||||
.field("blocks_free", &self.blocks_free())
|
||||
.field("blocks_available", &self.blocks_available())
|
||||
.field("files", &self.files())
|
||||
.field("files_free", &self.files_free())
|
||||
.field("filesystem_id", &self.filesystem_id())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// 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();
|
||||
let res = path.with_nix_path(|path| libc::statfs(path.as_ptr(), stat.as_mut_ptr()))?;
|
||||
Errno::result(res).map(|_| Statfs(stat.assume_init()))
|
||||
}
|
||||
}
|
||||
|
||||
/// 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();
|
||||
Errno::result(libc::fstatfs(fd.as_raw_fd(), stat.as_mut_ptr()))
|
||||
.map(|_| Statfs(stat.assume_init()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::fs::File;
|
||||
|
||||
use crate::sys::statfs::*;
|
||||
use crate::sys::statvfs::*;
|
||||
use std::path::Path;
|
||||
|
||||
#[test]
|
||||
fn statfs_call() {
|
||||
check_statfs("/tmp");
|
||||
check_statfs("/dev");
|
||||
check_statfs("/run");
|
||||
check_statfs("/");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fstatfs_call() {
|
||||
check_fstatfs("/tmp");
|
||||
check_fstatfs("/dev");
|
||||
check_fstatfs("/run");
|
||||
check_fstatfs("/");
|
||||
}
|
||||
|
||||
fn check_fstatfs(path: &str) {
|
||||
if !Path::new(path).exists() {
|
||||
return;
|
||||
}
|
||||
let vfs = statvfs(path.as_bytes()).unwrap();
|
||||
let file = File::open(path).unwrap();
|
||||
let fs = fstatfs(&file).unwrap();
|
||||
assert_fs_equals(fs, vfs);
|
||||
}
|
||||
|
||||
fn check_statfs(path: &str) {
|
||||
if !Path::new(path).exists() {
|
||||
return;
|
||||
}
|
||||
let vfs = statvfs(path.as_bytes()).unwrap();
|
||||
let fs = statfs(path.as_bytes()).unwrap();
|
||||
assert_fs_equals(fs, vfs);
|
||||
}
|
||||
|
||||
fn assert_fs_equals(fs: Statfs, vfs: Statvfs) {
|
||||
assert_eq!(fs.files() as u64, vfs.files() as u64);
|
||||
assert_eq!(fs.blocks() as u64, vfs.blocks() as u64);
|
||||
assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64);
|
||||
}
|
||||
|
||||
// This test is ignored because files_free/blocks_free can change after statvfs call and before
|
||||
// statfs call.
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn statfs_call_strict() {
|
||||
check_statfs_strict("/tmp");
|
||||
check_statfs_strict("/dev");
|
||||
check_statfs_strict("/run");
|
||||
check_statfs_strict("/");
|
||||
}
|
||||
|
||||
// This test is ignored because files_free/blocks_free can change after statvfs call and before
|
||||
// fstatfs call.
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn fstatfs_call_strict() {
|
||||
check_fstatfs_strict("/tmp");
|
||||
check_fstatfs_strict("/dev");
|
||||
check_fstatfs_strict("/run");
|
||||
check_fstatfs_strict("/");
|
||||
}
|
||||
|
||||
fn check_fstatfs_strict(path: &str) {
|
||||
if !Path::new(path).exists() {
|
||||
return;
|
||||
}
|
||||
let vfs = statvfs(path.as_bytes());
|
||||
let file = File::open(path).unwrap();
|
||||
let fs = fstatfs(&file);
|
||||
assert_fs_equals_strict(fs.unwrap(), vfs.unwrap())
|
||||
}
|
||||
|
||||
fn check_statfs_strict(path: &str) {
|
||||
if !Path::new(path).exists() {
|
||||
return;
|
||||
}
|
||||
let vfs = statvfs(path.as_bytes());
|
||||
let fs = statfs(path.as_bytes());
|
||||
assert_fs_equals_strict(fs.unwrap(), vfs.unwrap())
|
||||
}
|
||||
|
||||
fn assert_fs_equals_strict(fs: Statfs, vfs: Statvfs) {
|
||||
assert_eq!(fs.files_free() as u64, vfs.files_free() as u64);
|
||||
assert_eq!(fs.blocks_free() as u64, vfs.blocks_free() as u64);
|
||||
assert_eq!(fs.blocks_available() as u64, vfs.blocks_available() as u64);
|
||||
assert_eq!(fs.files() as u64, vfs.files() as u64);
|
||||
assert_eq!(fs.blocks() as u64, vfs.blocks() as u64);
|
||||
assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64);
|
||||
}
|
||||
}
|
161
vendor/nix-v0.23.1-patched/src/sys/statvfs.rs
vendored
161
vendor/nix-v0.23.1-patched/src/sys/statvfs.rs
vendored
|
@ -1,161 +0,0 @@
|
|||
//! Get filesystem statistics
|
||||
//!
|
||||
//! See [the man pages](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatvfs.html)
|
||||
//! for more details.
|
||||
use std::mem;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
use libc::{self, c_ulong};
|
||||
|
||||
use crate::{Result, NixPath, errno::Errno};
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
libc_bitflags!(
|
||||
/// File system mount Flags
|
||||
#[repr(C)]
|
||||
#[derive(Default)]
|
||||
pub struct FsFlags: c_ulong {
|
||||
/// Read Only
|
||||
ST_RDONLY;
|
||||
/// Do not allow the set-uid bits to have an effect
|
||||
ST_NOSUID;
|
||||
/// Do not interpret character or block-special devices
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
ST_NODEV;
|
||||
/// Do not allow execution of binaries on the filesystem
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
ST_NOEXEC;
|
||||
/// All IO should be done synchronously
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
ST_SYNCHRONOUS;
|
||||
/// Allow mandatory locks on the filesystem
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
ST_MANDLOCK;
|
||||
/// Write on file/directory/symlink
|
||||
#[cfg(target_os = "linux")]
|
||||
ST_WRITE;
|
||||
/// Append-only file
|
||||
#[cfg(target_os = "linux")]
|
||||
ST_APPEND;
|
||||
/// Immutable file
|
||||
#[cfg(target_os = "linux")]
|
||||
ST_IMMUTABLE;
|
||||
/// Do not update access times on files
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
ST_NOATIME;
|
||||
/// Do not update access times on files
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
ST_NODIRATIME;
|
||||
/// Update access time relative to modify/change time
|
||||
#[cfg(any(target_os = "android", all(target_os = "linux", not(target_env = "musl"))))]
|
||||
ST_RELATIME;
|
||||
}
|
||||
);
|
||||
|
||||
/// 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).
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct Statvfs(libc::statvfs);
|
||||
|
||||
impl Statvfs {
|
||||
/// get the file system block size
|
||||
pub fn block_size(&self) -> c_ulong {
|
||||
self.0.f_bsize
|
||||
}
|
||||
|
||||
/// Get the fundamental file system block size
|
||||
pub fn fragment_size(&self) -> c_ulong {
|
||||
self.0.f_frsize
|
||||
}
|
||||
|
||||
/// Get the number of blocks.
|
||||
///
|
||||
/// Units are in units of `fragment_size()`
|
||||
pub fn blocks(&self) -> libc::fsblkcnt_t {
|
||||
self.0.f_blocks
|
||||
}
|
||||
|
||||
/// Get the number of free blocks in the file system
|
||||
pub fn blocks_free(&self) -> libc::fsblkcnt_t {
|
||||
self.0.f_bfree
|
||||
}
|
||||
|
||||
/// Get the number of free blocks for unprivileged users
|
||||
pub fn blocks_available(&self) -> libc::fsblkcnt_t {
|
||||
self.0.f_bavail
|
||||
}
|
||||
|
||||
/// Get the total number of file inodes
|
||||
pub fn files(&self) -> libc::fsfilcnt_t {
|
||||
self.0.f_files
|
||||
}
|
||||
|
||||
/// Get the number of free file inodes
|
||||
pub fn files_free(&self) -> libc::fsfilcnt_t {
|
||||
self.0.f_ffree
|
||||
}
|
||||
|
||||
/// Get the number of free file inodes for unprivileged users
|
||||
pub fn files_available(&self) -> libc::fsfilcnt_t {
|
||||
self.0.f_favail
|
||||
}
|
||||
|
||||
/// Get the file system id
|
||||
pub fn filesystem_id(&self) -> c_ulong {
|
||||
self.0.f_fsid
|
||||
}
|
||||
|
||||
/// Get the mount flags
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
pub fn flags(&self) -> FsFlags {
|
||||
FsFlags::from_bits_truncate(self.0.f_flag)
|
||||
}
|
||||
|
||||
/// Get the maximum filename length
|
||||
pub fn name_max(&self) -> c_ulong {
|
||||
self.0.f_namemax
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Return a `Statvfs` object with information about the `path`
|
||||
pub fn statvfs<P: ?Sized + NixPath>(path: &P) -> Result<Statvfs> {
|
||||
unsafe {
|
||||
Errno::clear();
|
||||
let mut stat = mem::MaybeUninit::<libc::statvfs>::uninit();
|
||||
let res = path.with_nix_path(|path|
|
||||
libc::statvfs(path.as_ptr(), stat.as_mut_ptr())
|
||||
)?;
|
||||
|
||||
Errno::result(res).map(|_| Statvfs(stat.assume_init()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a `Statvfs` object with information about `fd`
|
||||
pub fn fstatvfs<T: AsRawFd>(fd: &T) -> Result<Statvfs> {
|
||||
unsafe {
|
||||
Errno::clear();
|
||||
let mut stat = mem::MaybeUninit::<libc::statvfs>::uninit();
|
||||
Errno::result(libc::fstatvfs(fd.as_raw_fd(), stat.as_mut_ptr()))
|
||||
.map(|_| Statvfs(stat.assume_init()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::fs::File;
|
||||
use crate::sys::statvfs::*;
|
||||
|
||||
#[test]
|
||||
fn statvfs_call() {
|
||||
statvfs(&b"/"[..]).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fstatvfs_call() {
|
||||
let root = File::open("/").unwrap();
|
||||
fstatvfs(&root).unwrap();
|
||||
}
|
||||
}
|
79
vendor/nix-v0.23.1-patched/src/sys/sysinfo.rs
vendored
79
vendor/nix-v0.23.1-patched/src/sys/sysinfo.rs
vendored
|
@ -1,79 +0,0 @@
|
|||
use libc::{self, SI_LOAD_SHIFT};
|
||||
use std::{cmp, mem};
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::Result;
|
||||
use crate::errno::Errno;
|
||||
|
||||
/// System info structure returned by `sysinfo`.
|
||||
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
|
||||
#[repr(transparent)]
|
||||
pub struct SysInfo(libc::sysinfo);
|
||||
|
||||
// The fields are c_ulong on 32-bit linux, u64 on 64-bit linux; x32's ulong is u32
|
||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
|
||||
type mem_blocks_t = u64;
|
||||
#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))]
|
||||
type mem_blocks_t = libc::c_ulong;
|
||||
|
||||
impl SysInfo {
|
||||
/// Returns the load average tuple.
|
||||
///
|
||||
/// The returned values represent the load average over time intervals of
|
||||
/// 1, 5, and 15 minutes, respectively.
|
||||
pub fn load_average(&self) -> (f64, f64, f64) {
|
||||
(
|
||||
self.0.loads[0] as f64 / (1 << SI_LOAD_SHIFT) as f64,
|
||||
self.0.loads[1] as f64 / (1 << SI_LOAD_SHIFT) as f64,
|
||||
self.0.loads[2] as f64 / (1 << SI_LOAD_SHIFT) as f64,
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the time since system boot.
|
||||
pub fn uptime(&self) -> Duration {
|
||||
// Truncate negative values to 0
|
||||
Duration::from_secs(cmp::max(self.0.uptime, 0) as u64)
|
||||
}
|
||||
|
||||
/// Current number of processes.
|
||||
pub fn process_count(&self) -> u16 {
|
||||
self.0.procs
|
||||
}
|
||||
|
||||
/// Returns the amount of swap memory in Bytes.
|
||||
pub fn swap_total(&self) -> u64 {
|
||||
self.scale_mem(self.0.totalswap)
|
||||
}
|
||||
|
||||
/// Returns the amount of unused swap memory in Bytes.
|
||||
pub fn swap_free(&self) -> u64 {
|
||||
self.scale_mem(self.0.freeswap)
|
||||
}
|
||||
|
||||
/// Returns the total amount of installed RAM in Bytes.
|
||||
pub fn ram_total(&self) -> u64 {
|
||||
self.scale_mem(self.0.totalram)
|
||||
}
|
||||
|
||||
/// Returns the amount of completely unused RAM in Bytes.
|
||||
///
|
||||
/// "Unused" in this context means that the RAM in neither actively used by
|
||||
/// programs, nor by the operating system as disk cache or buffer. It is
|
||||
/// "wasted" RAM since it currently serves no purpose.
|
||||
pub fn ram_unused(&self) -> u64 {
|
||||
self.scale_mem(self.0.freeram)
|
||||
}
|
||||
|
||||
fn scale_mem(&self, units: mem_blocks_t) -> u64 {
|
||||
units as u64 * self.0.mem_unit as u64
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns system information.
|
||||
///
|
||||
/// [See `sysinfo(2)`](https://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()) };
|
||||
Errno::result(res).map(|_| unsafe{ SysInfo(info.assume_init()) })
|
||||
}
|
1016
vendor/nix-v0.23.1-patched/src/sys/termios.rs
vendored
1016
vendor/nix-v0.23.1-patched/src/sys/termios.rs
vendored
File diff suppressed because it is too large
Load diff
609
vendor/nix-v0.23.1-patched/src/sys/time.rs
vendored
609
vendor/nix-v0.23.1-patched/src/sys/time.rs
vendored
|
@ -1,609 +0,0 @@
|
|||
use std::{cmp, fmt, ops};
|
||||
use std::time::Duration;
|
||||
use std::convert::From;
|
||||
use libc::{timespec, timeval};
|
||||
#[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
|
||||
pub use libc::{time_t, suseconds_t};
|
||||
|
||||
pub trait TimeValLike: Sized {
|
||||
#[inline]
|
||||
fn zero() -> Self {
|
||||
Self::seconds(0)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn hours(hours: i64) -> Self {
|
||||
let secs = hours.checked_mul(SECS_PER_HOUR)
|
||||
.expect("TimeValLike::hours ouf of bounds");
|
||||
Self::seconds(secs)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn minutes(minutes: i64) -> Self {
|
||||
let secs = minutes.checked_mul(SECS_PER_MINUTE)
|
||||
.expect("TimeValLike::minutes out of bounds");
|
||||
Self::seconds(secs)
|
||||
}
|
||||
|
||||
fn seconds(seconds: i64) -> Self;
|
||||
fn milliseconds(milliseconds: i64) -> Self;
|
||||
fn microseconds(microseconds: i64) -> Self;
|
||||
fn nanoseconds(nanoseconds: i64) -> Self;
|
||||
|
||||
#[inline]
|
||||
fn num_hours(&self) -> i64 {
|
||||
self.num_seconds() / 3600
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn num_minutes(&self) -> i64 {
|
||||
self.num_seconds() / 60
|
||||
}
|
||||
|
||||
fn num_seconds(&self) -> i64;
|
||||
fn num_milliseconds(&self) -> i64;
|
||||
fn num_microseconds(&self) -> i64;
|
||||
fn num_nanoseconds(&self) -> i64;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct TimeSpec(timespec);
|
||||
|
||||
const NANOS_PER_SEC: i64 = 1_000_000_000;
|
||||
const SECS_PER_MINUTE: i64 = 60;
|
||||
const SECS_PER_HOUR: i64 = 3600;
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
const TS_MAX_SECONDS: i64 = (::std::i64::MAX / NANOS_PER_SEC) - 1;
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
const TS_MAX_SECONDS: i64 = ::std::isize::MAX as i64;
|
||||
|
||||
const TS_MIN_SECONDS: i64 = -TS_MAX_SECONDS;
|
||||
|
||||
// x32 compatibility
|
||||
// See https://sourceware.org/bugzilla/show_bug.cgi?id=16437
|
||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
|
||||
type timespec_tv_nsec_t = i64;
|
||||
#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))]
|
||||
type timespec_tv_nsec_t = libc::c_long;
|
||||
|
||||
impl From<timespec> for TimeSpec {
|
||||
fn from(ts: timespec) -> Self {
|
||||
Self(ts)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Duration> for TimeSpec {
|
||||
fn from(duration: Duration) -> Self {
|
||||
Self::from_duration(duration)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TimeSpec> for Duration {
|
||||
fn from(timespec: TimeSpec) -> Self {
|
||||
Duration::new(timespec.0.tv_sec as u64, timespec.0.tv_nsec as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<timespec> for TimeSpec {
|
||||
fn as_ref(&self) -> ×pec {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<timespec> for TimeSpec {
|
||||
fn as_mut(&mut self) -> &mut timespec {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for TimeSpec {
|
||||
// The implementation of cmp is simplified by assuming that the struct is
|
||||
// normalized. That is, tv_nsec must always be within [0, 1_000_000_000)
|
||||
fn cmp(&self, other: &TimeSpec) -> cmp::Ordering {
|
||||
if self.tv_sec() == other.tv_sec() {
|
||||
self.tv_nsec().cmp(&other.tv_nsec())
|
||||
} else {
|
||||
self.tv_sec().cmp(&other.tv_sec())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for TimeSpec {
|
||||
fn partial_cmp(&self, other: &TimeSpec) -> Option<cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl TimeValLike for TimeSpec {
|
||||
#[inline]
|
||||
fn seconds(seconds: i64) -> TimeSpec {
|
||||
assert!(seconds >= TS_MIN_SECONDS && seconds <= TS_MAX_SECONDS,
|
||||
"TimeSpec out of bounds; seconds={}", seconds);
|
||||
#[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
|
||||
TimeSpec(timespec {tv_sec: seconds as time_t, tv_nsec: 0 })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn milliseconds(milliseconds: i64) -> TimeSpec {
|
||||
let nanoseconds = milliseconds.checked_mul(1_000_000)
|
||||
.expect("TimeSpec::milliseconds out of bounds");
|
||||
|
||||
TimeSpec::nanoseconds(nanoseconds)
|
||||
}
|
||||
|
||||
/// Makes a new `TimeSpec` with given number of microseconds.
|
||||
#[inline]
|
||||
fn microseconds(microseconds: i64) -> TimeSpec {
|
||||
let nanoseconds = microseconds.checked_mul(1_000)
|
||||
.expect("TimeSpec::milliseconds out of bounds");
|
||||
|
||||
TimeSpec::nanoseconds(nanoseconds)
|
||||
}
|
||||
|
||||
/// Makes a new `TimeSpec` with given number of nanoseconds.
|
||||
#[inline]
|
||||
fn nanoseconds(nanoseconds: i64) -> TimeSpec {
|
||||
let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC);
|
||||
assert!(secs >= TS_MIN_SECONDS && secs <= TS_MAX_SECONDS,
|
||||
"TimeSpec out of bounds");
|
||||
#[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
|
||||
TimeSpec(timespec {tv_sec: secs as time_t,
|
||||
tv_nsec: nanos as timespec_tv_nsec_t })
|
||||
}
|
||||
|
||||
fn num_seconds(&self) -> i64 {
|
||||
if self.tv_sec() < 0 && self.tv_nsec() > 0 {
|
||||
(self.tv_sec() + 1) as i64
|
||||
} else {
|
||||
self.tv_sec() as i64
|
||||
}
|
||||
}
|
||||
|
||||
fn num_milliseconds(&self) -> i64 {
|
||||
self.num_nanoseconds() / 1_000_000
|
||||
}
|
||||
|
||||
fn num_microseconds(&self) -> i64 {
|
||||
self.num_nanoseconds() / 1_000_000_000
|
||||
}
|
||||
|
||||
fn num_nanoseconds(&self) -> i64 {
|
||||
let secs = self.num_seconds() * 1_000_000_000;
|
||||
let nsec = self.nanos_mod_sec();
|
||||
secs + nsec as i64
|
||||
}
|
||||
}
|
||||
|
||||
impl TimeSpec {
|
||||
fn nanos_mod_sec(&self) -> timespec_tv_nsec_t {
|
||||
if self.tv_sec() < 0 && self.tv_nsec() > 0 {
|
||||
self.tv_nsec() - NANOS_PER_SEC as timespec_tv_nsec_t
|
||||
} else {
|
||||
self.tv_nsec()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
|
||||
pub const fn tv_sec(&self) -> time_t {
|
||||
self.0.tv_sec
|
||||
}
|
||||
|
||||
pub const 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 {
|
||||
type Output = TimeSpec;
|
||||
|
||||
fn neg(self) -> TimeSpec {
|
||||
TimeSpec::nanoseconds(-self.num_nanoseconds())
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Add for TimeSpec {
|
||||
type Output = TimeSpec;
|
||||
|
||||
fn add(self, rhs: TimeSpec) -> TimeSpec {
|
||||
TimeSpec::nanoseconds(
|
||||
self.num_nanoseconds() + rhs.num_nanoseconds())
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Sub for TimeSpec {
|
||||
type Output = TimeSpec;
|
||||
|
||||
fn sub(self, rhs: TimeSpec) -> TimeSpec {
|
||||
TimeSpec::nanoseconds(
|
||||
self.num_nanoseconds() - rhs.num_nanoseconds())
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Mul<i32> for TimeSpec {
|
||||
type Output = TimeSpec;
|
||||
|
||||
fn mul(self, rhs: i32) -> TimeSpec {
|
||||
let usec = self.num_nanoseconds().checked_mul(i64::from(rhs))
|
||||
.expect("TimeSpec multiply out of bounds");
|
||||
|
||||
TimeSpec::nanoseconds(usec)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Div<i32> for TimeSpec {
|
||||
type Output = TimeSpec;
|
||||
|
||||
fn div(self, rhs: i32) -> TimeSpec {
|
||||
let usec = self.num_nanoseconds() / i64::from(rhs);
|
||||
TimeSpec::nanoseconds(usec)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for TimeSpec {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let (abs, sign) = if self.tv_sec() < 0 {
|
||||
(-*self, "-")
|
||||
} else {
|
||||
(*self, "")
|
||||
};
|
||||
|
||||
let sec = abs.tv_sec();
|
||||
|
||||
write!(f, "{}", sign)?;
|
||||
|
||||
if abs.tv_nsec() == 0 {
|
||||
if abs.tv_sec() == 1 {
|
||||
write!(f, "{} second", sec)?;
|
||||
} else {
|
||||
write!(f, "{} seconds", sec)?;
|
||||
}
|
||||
} else if abs.tv_nsec() % 1_000_000 == 0 {
|
||||
write!(f, "{}.{:03} seconds", sec, abs.tv_nsec() / 1_000_000)?;
|
||||
} else if abs.tv_nsec() % 1_000 == 0 {
|
||||
write!(f, "{}.{:06} seconds", sec, abs.tv_nsec() / 1_000)?;
|
||||
} else {
|
||||
write!(f, "{}.{:09} seconds", sec, abs.tv_nsec())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct TimeVal(timeval);
|
||||
|
||||
const MICROS_PER_SEC: i64 = 1_000_000;
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
const TV_MAX_SECONDS: i64 = (::std::i64::MAX / MICROS_PER_SEC) - 1;
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
const TV_MAX_SECONDS: i64 = ::std::isize::MAX as i64;
|
||||
|
||||
const TV_MIN_SECONDS: i64 = -TV_MAX_SECONDS;
|
||||
|
||||
impl AsRef<timeval> for TimeVal {
|
||||
fn as_ref(&self) -> &timeval {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<timeval> for TimeVal {
|
||||
fn as_mut(&mut self) -> &mut timeval {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for TimeVal {
|
||||
// The implementation of cmp is simplified by assuming that the struct is
|
||||
// normalized. That is, tv_usec must always be within [0, 1_000_000)
|
||||
fn cmp(&self, other: &TimeVal) -> cmp::Ordering {
|
||||
if self.tv_sec() == other.tv_sec() {
|
||||
self.tv_usec().cmp(&other.tv_usec())
|
||||
} else {
|
||||
self.tv_sec().cmp(&other.tv_sec())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for TimeVal {
|
||||
fn partial_cmp(&self, other: &TimeVal) -> Option<cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl TimeValLike for TimeVal {
|
||||
#[inline]
|
||||
fn seconds(seconds: i64) -> TimeVal {
|
||||
assert!(seconds >= TV_MIN_SECONDS && seconds <= TV_MAX_SECONDS,
|
||||
"TimeVal out of bounds; seconds={}", seconds);
|
||||
#[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
|
||||
TimeVal(timeval {tv_sec: seconds as time_t, tv_usec: 0 })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn milliseconds(milliseconds: i64) -> TimeVal {
|
||||
let microseconds = milliseconds.checked_mul(1_000)
|
||||
.expect("TimeVal::milliseconds out of bounds");
|
||||
|
||||
TimeVal::microseconds(microseconds)
|
||||
}
|
||||
|
||||
/// Makes a new `TimeVal` with given number of microseconds.
|
||||
#[inline]
|
||||
fn microseconds(microseconds: i64) -> TimeVal {
|
||||
let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
|
||||
assert!(secs >= TV_MIN_SECONDS && secs <= TV_MAX_SECONDS,
|
||||
"TimeVal out of bounds");
|
||||
#[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
|
||||
TimeVal(timeval {tv_sec: secs as time_t,
|
||||
tv_usec: micros as suseconds_t })
|
||||
}
|
||||
|
||||
/// Makes a new `TimeVal` with given number of nanoseconds. Some precision
|
||||
/// will be lost
|
||||
#[inline]
|
||||
fn nanoseconds(nanoseconds: i64) -> TimeVal {
|
||||
let microseconds = nanoseconds / 1000;
|
||||
let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
|
||||
assert!(secs >= TV_MIN_SECONDS && secs <= TV_MAX_SECONDS,
|
||||
"TimeVal out of bounds");
|
||||
#[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
|
||||
TimeVal(timeval {tv_sec: secs as time_t,
|
||||
tv_usec: micros as suseconds_t })
|
||||
}
|
||||
|
||||
fn num_seconds(&self) -> i64 {
|
||||
if self.tv_sec() < 0 && self.tv_usec() > 0 {
|
||||
(self.tv_sec() + 1) as i64
|
||||
} else {
|
||||
self.tv_sec() as i64
|
||||
}
|
||||
}
|
||||
|
||||
fn num_milliseconds(&self) -> i64 {
|
||||
self.num_microseconds() / 1_000
|
||||
}
|
||||
|
||||
fn num_microseconds(&self) -> i64 {
|
||||
let secs = self.num_seconds() * 1_000_000;
|
||||
let usec = self.micros_mod_sec();
|
||||
secs + usec as i64
|
||||
}
|
||||
|
||||
fn num_nanoseconds(&self) -> i64 {
|
||||
self.num_microseconds() * 1_000
|
||||
}
|
||||
}
|
||||
|
||||
impl TimeVal {
|
||||
fn micros_mod_sec(&self) -> suseconds_t {
|
||||
if self.tv_sec() < 0 && self.tv_usec() > 0 {
|
||||
self.tv_usec() - MICROS_PER_SEC as suseconds_t
|
||||
} else {
|
||||
self.tv_usec()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
|
||||
pub const fn tv_sec(&self) -> time_t {
|
||||
self.0.tv_sec
|
||||
}
|
||||
|
||||
pub const fn tv_usec(&self) -> suseconds_t {
|
||||
self.0.tv_usec
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Neg for TimeVal {
|
||||
type Output = TimeVal;
|
||||
|
||||
fn neg(self) -> TimeVal {
|
||||
TimeVal::microseconds(-self.num_microseconds())
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Add for TimeVal {
|
||||
type Output = TimeVal;
|
||||
|
||||
fn add(self, rhs: TimeVal) -> TimeVal {
|
||||
TimeVal::microseconds(
|
||||
self.num_microseconds() + rhs.num_microseconds())
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Sub for TimeVal {
|
||||
type Output = TimeVal;
|
||||
|
||||
fn sub(self, rhs: TimeVal) -> TimeVal {
|
||||
TimeVal::microseconds(
|
||||
self.num_microseconds() - rhs.num_microseconds())
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Mul<i32> for TimeVal {
|
||||
type Output = TimeVal;
|
||||
|
||||
fn mul(self, rhs: i32) -> TimeVal {
|
||||
let usec = self.num_microseconds().checked_mul(i64::from(rhs))
|
||||
.expect("TimeVal multiply out of bounds");
|
||||
|
||||
TimeVal::microseconds(usec)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Div<i32> for TimeVal {
|
||||
type Output = TimeVal;
|
||||
|
||||
fn div(self, rhs: i32) -> TimeVal {
|
||||
let usec = self.num_microseconds() / i64::from(rhs);
|
||||
TimeVal::microseconds(usec)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for TimeVal {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let (abs, sign) = if self.tv_sec() < 0 {
|
||||
(-*self, "-")
|
||||
} else {
|
||||
(*self, "")
|
||||
};
|
||||
|
||||
let sec = abs.tv_sec();
|
||||
|
||||
write!(f, "{}", sign)?;
|
||||
|
||||
if abs.tv_usec() == 0 {
|
||||
if abs.tv_sec() == 1 {
|
||||
write!(f, "{} second", sec)?;
|
||||
} else {
|
||||
write!(f, "{} seconds", sec)?;
|
||||
}
|
||||
} else if abs.tv_usec() % 1000 == 0 {
|
||||
write!(f, "{}.{:03} seconds", sec, abs.tv_usec() / 1000)?;
|
||||
} else {
|
||||
write!(f, "{}.{:06} seconds", sec, abs.tv_usec())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<timeval> for TimeVal {
|
||||
fn from(tv: timeval) -> Self {
|
||||
TimeVal(tv)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
|
||||
(div_floor_64(this, other), mod_floor_64(this, other))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn div_floor_64(this: i64, other: i64) -> i64 {
|
||||
match div_rem_64(this, other) {
|
||||
(d, r) if (r > 0 && other < 0)
|
||||
|| (r < 0 && other > 0) => d - 1,
|
||||
(d, _) => d,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn mod_floor_64(this: i64, other: i64) -> i64 {
|
||||
match this % other {
|
||||
r if (r > 0 && other < 0)
|
||||
|| (r < 0 && other > 0) => r + other,
|
||||
r => r,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
|
||||
(this / other, this % other)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{TimeSpec, TimeVal, TimeValLike};
|
||||
use std::time::Duration;
|
||||
|
||||
#[test]
|
||||
pub fn test_timespec() {
|
||||
assert!(TimeSpec::seconds(1) != TimeSpec::zero());
|
||||
assert_eq!(TimeSpec::seconds(1) + TimeSpec::seconds(2),
|
||||
TimeSpec::seconds(3));
|
||||
assert_eq!(TimeSpec::minutes(3) + TimeSpec::seconds(2),
|
||||
TimeSpec::seconds(182));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_timespec_from() {
|
||||
let duration = Duration::new(123, 123_456_789);
|
||||
let timespec = TimeSpec::nanoseconds(123_123_456_789);
|
||||
|
||||
assert_eq!(TimeSpec::from(duration), timespec);
|
||||
assert_eq!(Duration::from(timespec), duration);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_timespec_neg() {
|
||||
let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123);
|
||||
let b = TimeSpec::seconds(-1) + TimeSpec::nanoseconds(-123);
|
||||
|
||||
assert_eq!(a, -b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_timespec_ord() {
|
||||
assert!(TimeSpec::seconds(1) == TimeSpec::nanoseconds(1_000_000_000));
|
||||
assert!(TimeSpec::seconds(1) < TimeSpec::nanoseconds(1_000_000_001));
|
||||
assert!(TimeSpec::seconds(1) > TimeSpec::nanoseconds(999_999_999));
|
||||
assert!(TimeSpec::seconds(-1) < TimeSpec::nanoseconds(-999_999_999));
|
||||
assert!(TimeSpec::seconds(-1) > TimeSpec::nanoseconds(-1_000_000_001));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_timespec_fmt() {
|
||||
assert_eq!(TimeSpec::zero().to_string(), "0 seconds");
|
||||
assert_eq!(TimeSpec::seconds(42).to_string(), "42 seconds");
|
||||
assert_eq!(TimeSpec::milliseconds(42).to_string(), "0.042 seconds");
|
||||
assert_eq!(TimeSpec::microseconds(42).to_string(), "0.000042 seconds");
|
||||
assert_eq!(TimeSpec::nanoseconds(42).to_string(), "0.000000042 seconds");
|
||||
assert_eq!(TimeSpec::seconds(-86401).to_string(), "-86401 seconds");
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_timeval() {
|
||||
assert!(TimeVal::seconds(1) != TimeVal::zero());
|
||||
assert_eq!(TimeVal::seconds(1) + TimeVal::seconds(2),
|
||||
TimeVal::seconds(3));
|
||||
assert_eq!(TimeVal::minutes(3) + TimeVal::seconds(2),
|
||||
TimeVal::seconds(182));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_timeval_ord() {
|
||||
assert!(TimeVal::seconds(1) == TimeVal::microseconds(1_000_000));
|
||||
assert!(TimeVal::seconds(1) < TimeVal::microseconds(1_000_001));
|
||||
assert!(TimeVal::seconds(1) > TimeVal::microseconds(999_999));
|
||||
assert!(TimeVal::seconds(-1) < TimeVal::microseconds(-999_999));
|
||||
assert!(TimeVal::seconds(-1) > TimeVal::microseconds(-1_000_001));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_timeval_neg() {
|
||||
let a = TimeVal::seconds(1) + TimeVal::microseconds(123);
|
||||
let b = TimeVal::seconds(-1) + TimeVal::microseconds(-123);
|
||||
|
||||
assert_eq!(a, -b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_timeval_fmt() {
|
||||
assert_eq!(TimeVal::zero().to_string(), "0 seconds");
|
||||
assert_eq!(TimeVal::seconds(42).to_string(), "42 seconds");
|
||||
assert_eq!(TimeVal::milliseconds(42).to_string(), "0.042 seconds");
|
||||
assert_eq!(TimeVal::microseconds(42).to_string(), "0.000042 seconds");
|
||||
assert_eq!(TimeVal::nanoseconds(1402).to_string(), "0.000001 seconds");
|
||||
assert_eq!(TimeVal::seconds(-86401).to_string(), "-86401 seconds");
|
||||
}
|
||||
}
|
281
vendor/nix-v0.23.1-patched/src/sys/timerfd.rs
vendored
281
vendor/nix-v0.23.1-patched/src/sys/timerfd.rs
vendored
|
@ -1,281 +0,0 @@
|
|||
//! Timer API via file descriptors.
|
||||
//!
|
||||
//! 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).
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Create a new one-shot timer that expires after 1 second.
|
||||
//! ```
|
||||
//! # use std::os::unix::io::AsRawFd;
|
||||
//! # use nix::sys::timerfd::{TimerFd, ClockId, TimerFlags, TimerSetTimeFlags,
|
||||
//! # Expiration};
|
||||
//! # use nix::sys::time::{TimeSpec, TimeValLike};
|
||||
//! # use nix::unistd::read;
|
||||
//! #
|
||||
//! // We create a new monotonic timer.
|
||||
//! let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty())
|
||||
//! .unwrap();
|
||||
//!
|
||||
//! // We set a new one-shot timer in 1 seconds.
|
||||
//! timer.set(
|
||||
//! Expiration::OneShot(TimeSpec::seconds(1)),
|
||||
//! TimerSetTimeFlags::empty()
|
||||
//! ).unwrap();
|
||||
//!
|
||||
//! // We wait for the timer to expire.
|
||||
//! timer.wait().unwrap();
|
||||
//! ```
|
||||
use crate::sys::time::TimeSpec;
|
||||
use crate::unistd::read;
|
||||
use crate::{errno::Errno, Result};
|
||||
use bitflags::bitflags;
|
||||
use libc::c_int;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||
|
||||
/// A timerfd instance. This is also a file descriptor, you can feed it to
|
||||
/// other interfaces consuming file descriptors, epoll for example.
|
||||
#[derive(Debug)]
|
||||
pub struct TimerFd {
|
||||
fd: RawFd,
|
||||
}
|
||||
|
||||
impl AsRawFd for TimerFd {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.fd
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for TimerFd {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||
TimerFd { fd }
|
||||
}
|
||||
}
|
||||
|
||||
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).
|
||||
#[repr(i32)]
|
||||
#[non_exhaustive]
|
||||
pub enum ClockId {
|
||||
CLOCK_REALTIME,
|
||||
CLOCK_MONOTONIC,
|
||||
CLOCK_BOOTTIME,
|
||||
CLOCK_REALTIME_ALARM,
|
||||
CLOCK_BOOTTIME_ALARM,
|
||||
}
|
||||
}
|
||||
|
||||
libc_bitflags! {
|
||||
/// Additional flags to change the behaviour of the file descriptor at the
|
||||
/// time of creation.
|
||||
pub struct TimerFlags: c_int {
|
||||
TFD_NONBLOCK;
|
||||
TFD_CLOEXEC;
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Flags that are used for arming the timer.
|
||||
pub struct TimerSetTimeFlags: libc::c_int {
|
||||
const TFD_TIMER_ABSTIME = libc::TFD_TIMER_ABSTIME;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct TimerSpec(libc::itimerspec);
|
||||
|
||||
impl TimerSpec {
|
||||
pub const fn none() -> Self {
|
||||
Self(libc::itimerspec {
|
||||
it_interval: libc::timespec {
|
||||
tv_sec: 0,
|
||||
tv_nsec: 0,
|
||||
},
|
||||
it_value: libc::timespec {
|
||||
tv_sec: 0,
|
||||
tv_nsec: 0,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<libc::itimerspec> for TimerSpec {
|
||||
fn as_ref(&self) -> &libc::itimerspec {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Expiration> for TimerSpec {
|
||||
fn from(expiration: Expiration) -> TimerSpec {
|
||||
match expiration {
|
||||
Expiration::OneShot(t) => TimerSpec(libc::itimerspec {
|
||||
it_interval: libc::timespec {
|
||||
tv_sec: 0,
|
||||
tv_nsec: 0,
|
||||
},
|
||||
it_value: *t.as_ref(),
|
||||
}),
|
||||
Expiration::IntervalDelayed(start, interval) => TimerSpec(libc::itimerspec {
|
||||
it_interval: *interval.as_ref(),
|
||||
it_value: *start.as_ref(),
|
||||
}),
|
||||
Expiration::Interval(t) => TimerSpec(libc::itimerspec {
|
||||
it_interval: *t.as_ref(),
|
||||
it_value: *t.as_ref(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TimerSpec> for Expiration {
|
||||
fn from(timerspec: TimerSpec) -> Expiration {
|
||||
match timerspec {
|
||||
TimerSpec(libc::itimerspec {
|
||||
it_interval:
|
||||
libc::timespec {
|
||||
tv_sec: 0,
|
||||
tv_nsec: 0,
|
||||
},
|
||||
it_value: ts,
|
||||
}) => Expiration::OneShot(ts.into()),
|
||||
TimerSpec(libc::itimerspec {
|
||||
it_interval: int_ts,
|
||||
it_value: val_ts,
|
||||
}) => {
|
||||
if (int_ts.tv_sec == val_ts.tv_sec) && (int_ts.tv_nsec == val_ts.tv_nsec) {
|
||||
Expiration::Interval(int_ts.into())
|
||||
} else {
|
||||
Expiration::IntervalDelayed(val_ts.into(), int_ts.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An enumeration allowing the definition of the expiration time of an alarm,
|
||||
/// recurring or not.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum Expiration {
|
||||
OneShot(TimeSpec),
|
||||
IntervalDelayed(TimeSpec, TimeSpec),
|
||||
Interval(TimeSpec),
|
||||
}
|
||||
|
||||
impl TimerFd {
|
||||
/// Creates a new timer based on the clock defined by `clockid`. The
|
||||
/// underlying fd can be assigned specific flags with `flags` (CLOEXEC,
|
||||
/// NONBLOCK). The underlying fd will be closed on drop.
|
||||
pub fn new(clockid: ClockId, flags: TimerFlags) -> Result<Self> {
|
||||
Errno::result(unsafe { libc::timerfd_create(clockid as i32, flags.bits()) })
|
||||
.map(|fd| Self { fd })
|
||||
}
|
||||
|
||||
/// Sets a new alarm on the timer.
|
||||
///
|
||||
/// # Types of alarm
|
||||
///
|
||||
/// There are 3 types of alarms you can set:
|
||||
///
|
||||
/// - one shot: the alarm will trigger once after the specified amount of
|
||||
/// time.
|
||||
/// Example: I want an alarm to go off in 60s and then disables itself.
|
||||
///
|
||||
/// - interval: the alarm will trigger every specified interval of time.
|
||||
/// Example: I want an alarm to go off every 60s. The alarm will first
|
||||
/// go off 60s after I set it and every 60s after that. The alarm will
|
||||
/// not disable itself.
|
||||
///
|
||||
/// - interval delayed: the alarm will trigger after a certain amount of
|
||||
/// time and then trigger at a specified interval.
|
||||
/// Example: I want an alarm to go off every 60s but only start in 1h.
|
||||
/// The alarm will first trigger 1h after I set it and then every 60s
|
||||
/// after that. The alarm will not disable itself.
|
||||
///
|
||||
/// # Relative vs absolute alarm
|
||||
///
|
||||
/// If you do not set any `TimerSetTimeFlags`, then the `TimeSpec` you pass
|
||||
/// to the `Expiration` you want is relative. If however you want an alarm
|
||||
/// to go off at a certain point in time, you can set `TFD_TIMER_ABSTIME`.
|
||||
/// Then the one shot TimeSpec and the delay TimeSpec of the delayed
|
||||
/// interval are going to be interpreted as absolute.
|
||||
///
|
||||
/// # Disabling alarms
|
||||
///
|
||||
/// Note: Only one alarm can be set for any given timer. Setting a new alarm
|
||||
/// actually removes the previous one.
|
||||
///
|
||||
/// Note: Setting a one shot alarm with a 0s TimeSpec disables the alarm
|
||||
/// altogether.
|
||||
pub fn set(&self, expiration: Expiration, flags: TimerSetTimeFlags) -> Result<()> {
|
||||
let timerspec: TimerSpec = expiration.into();
|
||||
Errno::result(unsafe {
|
||||
libc::timerfd_settime(
|
||||
self.fd,
|
||||
flags.bits(),
|
||||
timerspec.as_ref(),
|
||||
std::ptr::null_mut(),
|
||||
)
|
||||
})
|
||||
.map(drop)
|
||||
}
|
||||
|
||||
/// Get the parameters for the alarm currently set, if any.
|
||||
pub fn get(&self) -> Result<Option<Expiration>> {
|
||||
let mut timerspec = TimerSpec::none();
|
||||
let timerspec_ptr: *mut libc::itimerspec = &mut timerspec.0;
|
||||
|
||||
Errno::result(unsafe { libc::timerfd_gettime(self.fd, timerspec_ptr) }).map(|_| {
|
||||
if timerspec.0.it_interval.tv_sec == 0
|
||||
&& timerspec.0.it_interval.tv_nsec == 0
|
||||
&& timerspec.0.it_value.tv_sec == 0
|
||||
&& timerspec.0.it_value.tv_nsec == 0
|
||||
{
|
||||
None
|
||||
} else {
|
||||
Some(timerspec.into())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Remove the alarm if any is set.
|
||||
pub fn unset(&self) -> Result<()> {
|
||||
Errno::result(unsafe {
|
||||
libc::timerfd_settime(
|
||||
self.fd,
|
||||
TimerSetTimeFlags::empty().bits(),
|
||||
TimerSpec::none().as_ref(),
|
||||
std::ptr::null_mut(),
|
||||
)
|
||||
})
|
||||
.map(drop)
|
||||
}
|
||||
|
||||
/// Wait for the configured alarm to expire.
|
||||
///
|
||||
/// 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)
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TimerFd {
|
||||
fn drop(&mut self) {
|
||||
if !std::thread::panicking() {
|
||||
let result = Errno::result(unsafe {
|
||||
libc::close(self.fd)
|
||||
});
|
||||
if let Err(Errno::EBADF) = result {
|
||||
panic!("close of TimerFd encountered EBADF");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
223
vendor/nix-v0.23.1-patched/src/sys/uio.rs
vendored
223
vendor/nix-v0.23.1-patched/src/sys/uio.rs
vendored
|
@ -1,223 +0,0 @@
|
|||
//! Vectored I/O
|
||||
|
||||
use crate::Result;
|
||||
use crate::errno::Errno;
|
||||
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) };
|
||||
|
||||
Errno::result(res).map(|r| r as usize)
|
||||
}
|
||||
|
||||
/// Write to `fd` at `offset` from buffers in `iov`.
|
||||
///
|
||||
/// Buffers in `iov` will be written in order until all buffers have been written
|
||||
/// or an error occurs. The file offset is not changed.
|
||||
///
|
||||
/// See also: [`writev`](fn.writev.html) and [`pwrite`](fn.pwrite.html)
|
||||
#[cfg(not(any(target_os = "macos", target_os = "redox")))]
|
||||
pub fn pwritev(fd: RawFd, iov: &[IoVec<&[u8]>],
|
||||
offset: off_t) -> Result<usize> {
|
||||
let res = unsafe {
|
||||
libc::pwritev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset)
|
||||
};
|
||||
|
||||
Errno::result(res).map(|r| r as usize)
|
||||
}
|
||||
|
||||
/// Read from `fd` at `offset` filling buffers in `iov`.
|
||||
///
|
||||
/// Buffers in `iov` will be filled in order until all buffers have been filled,
|
||||
/// no more bytes are available, or an error occurs. The file offset is not
|
||||
/// changed.
|
||||
///
|
||||
/// See also: [`readv`](fn.readv.html) and [`pread`](fn.pread.html)
|
||||
#[cfg(not(any(target_os = "macos", target_os = "redox")))]
|
||||
pub fn preadv(fd: RawFd, iov: &[IoVec<&mut [u8]>],
|
||||
offset: off_t) -> Result<usize> {
|
||||
let res = unsafe {
|
||||
libc::preadv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset)
|
||||
};
|
||||
|
||||
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,
|
||||
offset)
|
||||
};
|
||||
|
||||
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,
|
||||
offset)
|
||||
};
|
||||
|
||||
Errno::result(res).map(|r| r as usize)
|
||||
}
|
||||
|
||||
/// A slice of memory in a remote process, starting at address `base`
|
||||
/// and consisting of `len` bytes.
|
||||
///
|
||||
/// This is the same underlying C structure as [`IoVec`](struct.IoVec.html),
|
||||
/// except that it refers to memory in some other process, and is
|
||||
/// therefore not represented in Rust by an actual slice as `IoVec` is. It
|
||||
/// is used with [`process_vm_readv`](fn.process_vm_readv.html)
|
||||
/// and [`process_vm_writev`](fn.process_vm_writev.html).
|
||||
#[cfg(target_os = "linux")]
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct RemoteIoVec {
|
||||
/// The starting address of this slice (`iov_base`).
|
||||
pub base: usize,
|
||||
/// The number of bytes in this slice (`iov_len`).
|
||||
pub len: usize,
|
||||
}
|
||||
|
||||
/// Write data directly to another process's virtual memory
|
||||
/// (see [`process_vm_writev`(2)]).
|
||||
///
|
||||
/// `local_iov` is a list of [`IoVec`]s containing the data to be written,
|
||||
/// and `remote_iov` is a list of [`RemoteIoVec`]s identifying where the
|
||||
/// data should be written in the target process. On success, returns the
|
||||
/// number of bytes written, which will always be a whole
|
||||
/// number of `remote_iov` chunks.
|
||||
///
|
||||
/// This requires the same permissions as debugging the process using
|
||||
/// [ptrace]: you must either be a privileged process (with
|
||||
/// `CAP_SYS_PTRACE`), or you must be running as the same user as the
|
||||
/// target process and the OS must have unprivileged debugging enabled.
|
||||
///
|
||||
/// This function is only available on Linux.
|
||||
///
|
||||
/// [`process_vm_writev`(2)]: https://man7.org/linux/man-pages/man2/process_vm_writev.2.html
|
||||
/// [ptrace]: ../ptrace/index.html
|
||||
/// [`IoVec`]: struct.IoVec.html
|
||||
/// [`RemoteIoVec`]: struct.RemoteIoVec.html
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn process_vm_writev(
|
||||
pid: crate::unistd::Pid,
|
||||
local_iov: &[IoVec<&[u8]>],
|
||||
remote_iov: &[RemoteIoVec]) -> Result<usize>
|
||||
{
|
||||
let res = unsafe {
|
||||
libc::process_vm_writev(pid.into(),
|
||||
local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong,
|
||||
remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0)
|
||||
};
|
||||
|
||||
Errno::result(res).map(|r| r as usize)
|
||||
}
|
||||
|
||||
/// Read data directly from another process's virtual memory
|
||||
/// (see [`process_vm_readv`(2)]).
|
||||
///
|
||||
/// `local_iov` is a list of [`IoVec`]s containing the buffer to copy
|
||||
/// data into, and `remote_iov` is a list of [`RemoteIoVec`]s identifying
|
||||
/// where the source data is in the target process. On success,
|
||||
/// returns the number of bytes written, which will always be a whole
|
||||
/// number of `remote_iov` chunks.
|
||||
///
|
||||
/// This requires the same permissions as debugging the process using
|
||||
/// [`ptrace`]: you must either be a privileged process (with
|
||||
/// `CAP_SYS_PTRACE`), or you must be running as the same user as the
|
||||
/// target process and the OS must have unprivileged debugging enabled.
|
||||
///
|
||||
/// This function is only available on Linux.
|
||||
///
|
||||
/// [`process_vm_readv`(2)]: https://man7.org/linux/man-pages/man2/process_vm_readv.2.html
|
||||
/// [`ptrace`]: ../ptrace/index.html
|
||||
/// [`IoVec`]: struct.IoVec.html
|
||||
/// [`RemoteIoVec`]: struct.RemoteIoVec.html
|
||||
#[cfg(any(target_os = "linux"))]
|
||||
pub fn process_vm_readv(
|
||||
pid: crate::unistd::Pid,
|
||||
local_iov: &[IoVec<&mut [u8]>],
|
||||
remote_iov: &[RemoteIoVec]) -> Result<usize>
|
||||
{
|
||||
let res = unsafe {
|
||||
libc::process_vm_readv(pid.into(),
|
||||
local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong,
|
||||
remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0)
|
||||
};
|
||||
|
||||
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>);
|
||||
|
||||
impl<T> IoVec<T> {
|
||||
/// View the `IoVec` as a Rust slice.
|
||||
#[inline]
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
use std::slice;
|
||||
|
||||
unsafe {
|
||||
slice::from_raw_parts(
|
||||
self.0.iov_base as *const u8,
|
||||
self.0.iov_len as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
iov_len: buf.len() as size_t,
|
||||
}, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
iov_len: buf.len() as size_t,
|
||||
}, PhantomData)
|
||||
}
|
||||
}
|
75
vendor/nix-v0.23.1-patched/src/sys/utsname.rs
vendored
75
vendor/nix-v0.23.1-patched/src/sys/utsname.rs
vendored
|
@ -1,75 +0,0 @@
|
|||
//! 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();
|
||||
libc::uname(ret.as_mut_ptr());
|
||||
UtsName(ret.assume_init())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn to_str<'a>(s: *const *const c_char) -> &'a str {
|
||||
unsafe {
|
||||
let res = CStr::from_ptr(*s).to_bytes();
|
||||
from_utf8_unchecked(res)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[cfg(target_os = "linux")]
|
||||
#[test]
|
||||
pub fn test_uname_linux() {
|
||||
assert_eq!(super::uname().sysname(), "Linux");
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
#[test]
|
||||
pub fn test_uname_darwin() {
|
||||
assert_eq!(super::uname().sysname(), "Darwin");
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[test]
|
||||
pub fn test_uname_freebsd() {
|
||||
assert_eq!(super::uname().sysname(), "FreeBSD");
|
||||
}
|
||||
}
|
262
vendor/nix-v0.23.1-patched/src/sys/wait.rs
vendored
262
vendor/nix-v0.23.1-patched/src/sys/wait.rs
vendored
|
@ -1,262 +0,0 @@
|
|||
//! Wait for a process to change status
|
||||
use crate::errno::Errno;
|
||||
use crate::sys::signal::Signal;
|
||||
use crate::unistd::Pid;
|
||||
use crate::Result;
|
||||
use cfg_if::cfg_if;
|
||||
use libc::{self, c_int};
|
||||
use std::convert::TryFrom;
|
||||
|
||||
libc_bitflags!(
|
||||
/// 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",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "redox",
|
||||
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",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "redox",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd"))]
|
||||
WSTOPPED;
|
||||
/// Don't reap, just poll status.
|
||||
#[cfg(any(target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "redox",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd"))]
|
||||
WNOWAIT;
|
||||
/// Don't wait on children of other threads in this group
|
||||
#[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
|
||||
__WNOTHREAD;
|
||||
/// 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;
|
||||
}
|
||||
);
|
||||
|
||||
/// Possible return values from `wait()` or `waitpid()`.
|
||||
///
|
||||
/// Each status (other than `StillAlive`) describes a state transition
|
||||
/// in a child process `Pid`, such as the process exiting or stopping,
|
||||
/// plus additional data about the transition if any.
|
||||
///
|
||||
/// Note that there are two Linux-specific enum variants, `PtraceEvent`
|
||||
/// and `PtraceSyscall`. Portable code should avoid exhaustively
|
||||
/// matching on `WaitStatus`.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum WaitStatus {
|
||||
/// The process exited normally (as with `exit()` or returning from
|
||||
/// `main`) with the given exit code. This case matches the C macro
|
||||
/// `WIFEXITED(status)`; the second field is `WEXITSTATUS(status)`.
|
||||
Exited(Pid, i32),
|
||||
/// The process was killed by the given signal. The third field
|
||||
/// indicates whether the signal generated a core dump. This case
|
||||
/// matches the C macro `WIFSIGNALED(status)`; the last two fields
|
||||
/// correspond to `WTERMSIG(status)` and `WCOREDUMP(status)`.
|
||||
Signaled(Pid, Signal, bool),
|
||||
/// The process is alive, but was stopped by the given signal. This
|
||||
/// is only reported if `WaitPidFlag::WUNTRACED` was passed. This
|
||||
/// case matches the C macro `WIFSTOPPED(status)`; the second field
|
||||
/// is `WSTOPSIG(status)`.
|
||||
Stopped(Pid, Signal),
|
||||
/// The traced process was stopped by a `PTRACE_EVENT_*` event. See
|
||||
/// [`nix::sys::ptrace`] and [`ptrace`(2)] for more information. All
|
||||
/// currently-defined events use `SIGTRAP` as the signal; the third
|
||||
/// 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
|
||||
#[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
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
PtraceSyscall(Pid),
|
||||
/// The process was previously stopped but has resumed execution
|
||||
/// after receiving a `SIGCONT` signal. This is only reported if
|
||||
/// `WaitPidFlag::WCONTINUED` was passed. This case matches the C
|
||||
/// macro `WIFCONTINUED(status)`.
|
||||
Continued(Pid),
|
||||
/// There are currently no state changes to report in any awaited
|
||||
/// child process. This is only returned if `WaitPidFlag::WNOHANG`
|
||||
/// was used (otherwise `wait()` or `waitpid()` would block until
|
||||
/// there was something to report).
|
||||
StillAlive,
|
||||
}
|
||||
|
||||
impl WaitStatus {
|
||||
/// Extracts the PID from the WaitStatus unless it equals StillAlive.
|
||||
pub fn pid(&self) -> Option<Pid> {
|
||||
use self::WaitStatus::*;
|
||||
match *self {
|
||||
Exited(p, _) | Signaled(p, _, _) | Stopped(p, _) | Continued(p) => Some(p),
|
||||
StillAlive => None,
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
PtraceEvent(p, _, _) | PtraceSyscall(p) => Some(p),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn exited(status: i32) -> bool {
|
||||
libc::WIFEXITED(status)
|
||||
}
|
||||
|
||||
fn exit_status(status: i32) -> i32 {
|
||||
libc::WEXITSTATUS(status)
|
||||
}
|
||||
|
||||
fn signaled(status: i32) -> bool {
|
||||
libc::WIFSIGNALED(status)
|
||||
}
|
||||
|
||||
fn term_signal(status: i32) -> Result<Signal> {
|
||||
Signal::try_from(libc::WTERMSIG(status))
|
||||
}
|
||||
|
||||
fn dumped_core(status: i32) -> bool {
|
||||
libc::WCOREDUMP(status)
|
||||
}
|
||||
|
||||
fn stopped(status: i32) -> bool {
|
||||
libc::WIFSTOPPED(status)
|
||||
}
|
||||
|
||||
fn stop_signal(status: i32) -> Result<Signal> {
|
||||
Signal::try_from(libc::WSTOPSIG(status))
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
fn syscall_stop(status: i32) -> bool {
|
||||
// From ptrace(2), setting PTRACE_O_TRACESYSGOOD has the effect
|
||||
// of delivering SIGTRAP | 0x80 as the signal number for syscall
|
||||
// stops. This allows easily distinguishing syscall stops from
|
||||
// genuine SIGTRAP signals.
|
||||
libc::WSTOPSIG(status) == libc::SIGTRAP | 0x80
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
fn stop_additional(status: i32) -> c_int {
|
||||
(status >> 16) as c_int
|
||||
}
|
||||
|
||||
fn continued(status: i32) -> bool {
|
||||
libc::WIFCONTINUED(status)
|
||||
}
|
||||
|
||||
impl WaitStatus {
|
||||
/// Convert a raw `wstatus` as returned by `waitpid`/`wait` into a `WaitStatus`
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an `Error` corresponding to `EINVAL` for invalid status values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Convert a `wstatus` obtained from `libc::waitpid` into a `WaitStatus`:
|
||||
///
|
||||
/// ```
|
||||
/// use nix::sys::wait::WaitStatus;
|
||||
/// use nix::sys::signal::Signal;
|
||||
/// let pid = nix::unistd::Pid::from_raw(1);
|
||||
/// let status = WaitStatus::from_raw(pid, 0x0002);
|
||||
/// assert_eq!(status, Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false)));
|
||||
/// ```
|
||||
pub fn from_raw(pid: Pid, status: i32) -> Result<WaitStatus> {
|
||||
Ok(if exited(status) {
|
||||
WaitStatus::Exited(pid, exit_status(status))
|
||||
} else if signaled(status) {
|
||||
WaitStatus::Signaled(pid, term_signal(status)?, dumped_core(status))
|
||||
} else if stopped(status) {
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "android", target_os = "linux"))] {
|
||||
fn decode_stopped(pid: Pid, status: i32) -> Result<WaitStatus> {
|
||||
let status_additional = stop_additional(status);
|
||||
Ok(if syscall_stop(status) {
|
||||
WaitStatus::PtraceSyscall(pid)
|
||||
} else if status_additional == 0 {
|
||||
WaitStatus::Stopped(pid, stop_signal(status)?)
|
||||
} else {
|
||||
WaitStatus::PtraceEvent(pid, stop_signal(status)?,
|
||||
stop_additional(status))
|
||||
})
|
||||
}
|
||||
} else {
|
||||
fn decode_stopped(pid: Pid, status: i32) -> Result<WaitStatus> {
|
||||
Ok(WaitStatus::Stopped(pid, stop_signal(status)?))
|
||||
}
|
||||
}
|
||||
}
|
||||
return decode_stopped(pid, status);
|
||||
} else {
|
||||
assert!(continued(status));
|
||||
WaitStatus::Continued(pid)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// 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::*;
|
||||
|
||||
let mut status: i32 = 0;
|
||||
|
||||
let option_bits = match options {
|
||||
Some(bits) => bits.bits(),
|
||||
None => 0,
|
||||
};
|
||||
|
||||
let res = unsafe {
|
||||
libc::waitpid(
|
||||
pid.into().unwrap_or_else(|| Pid::from_raw(-1)).into(),
|
||||
&mut status as *mut c_int,
|
||||
option_bits,
|
||||
)
|
||||
};
|
||||
|
||||
match Errno::result(res)? {
|
||||
0 => Ok(StillAlive),
|
||||
res => WaitStatus::from_raw(Pid::from_raw(res), status),
|
||||
}
|
||||
}
|
||||
|
||||
/// 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)
|
||||
}
|
260
vendor/nix-v0.23.1-patched/src/time.rs
vendored
260
vendor/nix-v0.23.1-patched/src/time.rs
vendored
|
@ -1,260 +0,0 @@
|
|||
use crate::sys::time::TimeSpec;
|
||||
#[cfg(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
))]
|
||||
use crate::unistd::Pid;
|
||||
use crate::{Errno, Result};
|
||||
use libc::{self, clockid_t};
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
/// Clock identifier
|
||||
///
|
||||
/// Newtype pattern around `clockid_t` (which is just alias). It pervents bugs caused by
|
||||
/// accidentally passing wrong value.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
pub struct ClockId(clockid_t);
|
||||
|
||||
impl ClockId {
|
||||
/// Creates `ClockId` from raw `clockid_t`
|
||||
pub const fn from_raw(clk_id: clockid_t) -> Self {
|
||||
ClockId(clk_id)
|
||||
}
|
||||
|
||||
/// Returns `ClockId` of a `pid` CPU-time clock
|
||||
#[cfg(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
))]
|
||||
pub fn pid_cpu_clock_id(pid: Pid) -> Result<Self> {
|
||||
clock_getcpuclockid(pid)
|
||||
}
|
||||
|
||||
/// Returns resolution of the clock id
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
pub fn res(self) -> Result<TimeSpec> {
|
||||
clock_getres(self)
|
||||
}
|
||||
|
||||
/// Returns the current time on the clock id
|
||||
pub fn now(self) -> Result<TimeSpec> {
|
||||
clock_gettime(self)
|
||||
}
|
||||
|
||||
/// Sets time to `timespec` on the clock id
|
||||
#[cfg(not(any(
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
all(
|
||||
not(any(target_env = "uclibc", target_env = "newlibc")),
|
||||
any(target_os = "redox", target_os = "hermit",),
|
||||
),
|
||||
)))]
|
||||
pub fn set_time(self, timespec: TimeSpec) -> Result<()> {
|
||||
clock_settime(self, timespec)
|
||||
}
|
||||
|
||||
/// Gets the raw `clockid_t` wrapped by `self`
|
||||
pub const fn as_raw(self) -> clockid_t {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "fuchsia",
|
||||
all(
|
||||
not(any(target_env = "uclibc", target_env = "newlib")),
|
||||
any(target_os = "linux", target_os = "android", target_os = "emscripten"),
|
||||
)
|
||||
))]
|
||||
pub const CLOCK_BOOTTIME: ClockId = ClockId(libc::CLOCK_BOOTTIME);
|
||||
#[cfg(any(
|
||||
target_os = "fuchsia",
|
||||
all(
|
||||
not(any(target_env = "uclibc", target_env = "newlib")),
|
||||
any(target_os = "linux", target_os = "android", target_os = "emscripten")
|
||||
)
|
||||
))]
|
||||
pub const CLOCK_BOOTTIME_ALARM: ClockId = ClockId(libc::CLOCK_BOOTTIME_ALARM);
|
||||
pub const CLOCK_MONOTONIC: ClockId = ClockId(libc::CLOCK_MONOTONIC);
|
||||
#[cfg(any(
|
||||
target_os = "fuchsia",
|
||||
all(
|
||||
not(any(target_env = "uclibc", target_env = "newlib")),
|
||||
any(target_os = "linux", target_os = "android", target_os = "emscripten")
|
||||
)
|
||||
))]
|
||||
pub const CLOCK_MONOTONIC_COARSE: ClockId = ClockId(libc::CLOCK_MONOTONIC_COARSE);
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
pub const CLOCK_MONOTONIC_FAST: ClockId = ClockId(libc::CLOCK_MONOTONIC_FAST);
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
pub const CLOCK_MONOTONIC_PRECISE: ClockId = ClockId(libc::CLOCK_MONOTONIC_PRECISE);
|
||||
#[cfg(any(
|
||||
target_os = "fuchsia",
|
||||
all(
|
||||
not(any(target_env = "uclibc", target_env = "newlib")),
|
||||
any(target_os = "linux", target_os = "android", target_os = "emscripten")
|
||||
)
|
||||
))]
|
||||
pub const CLOCK_MONOTONIC_RAW: ClockId = ClockId(libc::CLOCK_MONOTONIC_RAW);
|
||||
#[cfg(any(
|
||||
target_os = "fuchsia",
|
||||
target_env = "uclibc",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
all(
|
||||
not(target_env = "newlib"),
|
||||
any(target_os = "linux", target_os = "android", target_os = "emscripten")
|
||||
)
|
||||
))]
|
||||
pub const CLOCK_PROCESS_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_PROCESS_CPUTIME_ID);
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
pub const CLOCK_PROF: ClockId = ClockId(libc::CLOCK_PROF);
|
||||
pub const CLOCK_REALTIME: ClockId = ClockId(libc::CLOCK_REALTIME);
|
||||
#[cfg(any(
|
||||
target_os = "fuchsia",
|
||||
all(
|
||||
not(any(target_env = "uclibc", target_env = "newlib")),
|
||||
any(target_os = "linux", target_os = "android", target_os = "emscripten")
|
||||
)
|
||||
))]
|
||||
pub const CLOCK_REALTIME_ALARM: ClockId = ClockId(libc::CLOCK_REALTIME_ALARM);
|
||||
#[cfg(any(
|
||||
target_os = "fuchsia",
|
||||
all(
|
||||
not(any(target_env = "uclibc", target_env = "newlib")),
|
||||
any(target_os = "linux", target_os = "android", target_os = "emscripten")
|
||||
)
|
||||
))]
|
||||
pub const CLOCK_REALTIME_COARSE: ClockId = ClockId(libc::CLOCK_REALTIME_COARSE);
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
pub const CLOCK_REALTIME_FAST: ClockId = ClockId(libc::CLOCK_REALTIME_FAST);
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
pub const CLOCK_REALTIME_PRECISE: ClockId = ClockId(libc::CLOCK_REALTIME_PRECISE);
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
pub const CLOCK_SECOND: ClockId = ClockId(libc::CLOCK_SECOND);
|
||||
#[cfg(any(
|
||||
target_os = "fuchsia",
|
||||
all(
|
||||
not(any(target_env = "uclibc", target_env = "newlib")),
|
||||
any(
|
||||
target_os = "emscripten",
|
||||
all(target_os = "linux", target_env = "musl")
|
||||
)
|
||||
)
|
||||
))]
|
||||
pub const CLOCK_SGI_CYCLE: ClockId = ClockId(libc::CLOCK_SGI_CYCLE);
|
||||
#[cfg(any(
|
||||
target_os = "fuchsia",
|
||||
all(
|
||||
not(any(target_env = "uclibc", target_env = "newlib")),
|
||||
any(
|
||||
target_os = "emscripten",
|
||||
all(target_os = "linux", target_env = "musl")
|
||||
)
|
||||
)
|
||||
))]
|
||||
pub const CLOCK_TAI: ClockId = ClockId(libc::CLOCK_TAI);
|
||||
#[cfg(any(
|
||||
target_env = "uclibc",
|
||||
target_os = "fuchsia",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
all(
|
||||
not(target_env = "newlib"),
|
||||
any(target_os = "linux", target_os = "android", target_os = "emscripten",),
|
||||
),
|
||||
))]
|
||||
pub const CLOCK_THREAD_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_THREAD_CPUTIME_ID);
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
pub const CLOCK_UPTIME: ClockId = ClockId(libc::CLOCK_UPTIME);
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
pub const CLOCK_UPTIME_FAST: ClockId = ClockId(libc::CLOCK_UPTIME_FAST);
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
pub const CLOCK_UPTIME_PRECISE: ClockId = ClockId(libc::CLOCK_UPTIME_PRECISE);
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
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 From<clockid_t> for ClockId {
|
||||
fn from(clk_id: clockid_t) -> Self {
|
||||
ClockId::from_raw(clk_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ClockId {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the resolution of the specified clock, (see
|
||||
/// [clock_getres(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_getres.html)).
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
pub fn clock_getres(clock_id: ClockId) -> Result<TimeSpec> {
|
||||
let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
|
||||
let ret = unsafe { libc::clock_getres(clock_id.as_raw(), c_time.as_mut_ptr()) };
|
||||
Errno::result(ret)?;
|
||||
let res = unsafe { c_time.assume_init() };
|
||||
Ok(TimeSpec::from(res))
|
||||
}
|
||||
|
||||
/// Get the time of the specified clock, (see
|
||||
/// [clock_gettime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_gettime.html)).
|
||||
pub fn clock_gettime(clock_id: ClockId) -> Result<TimeSpec> {
|
||||
let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
|
||||
let ret = unsafe { libc::clock_gettime(clock_id.as_raw(), c_time.as_mut_ptr()) };
|
||||
Errno::result(ret)?;
|
||||
let res = unsafe { c_time.assume_init() };
|
||||
Ok(TimeSpec::from(res))
|
||||
}
|
||||
|
||||
/// Set the time of the specified clock, (see
|
||||
/// [clock_settime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_settime.html)).
|
||||
#[cfg(not(any(
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
all(
|
||||
not(any(target_env = "uclibc", target_env = "newlibc")),
|
||||
any(target_os = "redox", target_os = "hermit",),
|
||||
),
|
||||
)))]
|
||||
pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> {
|
||||
let ret = unsafe { libc::clock_settime(clock_id.as_raw(), timespec.as_ref()) };
|
||||
Errno::result(ret).map(drop)
|
||||
}
|
||||
|
||||
/// Get the clock id of the specified process id, (see
|
||||
/// [clock_getcpuclockid(3)](https://pubs.opengroup.org/onlinepubs/009695399/functions/clock_getcpuclockid.html)).
|
||||
#[cfg(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
))]
|
||||
pub fn clock_getcpuclockid(pid: Pid) -> Result<ClockId> {
|
||||
let mut clk_id: MaybeUninit<libc::clockid_t> = MaybeUninit::uninit();
|
||||
let ret = unsafe { libc::clock_getcpuclockid(pid.into(), clk_id.as_mut_ptr()) };
|
||||
if ret == 0 {
|
||||
let res = unsafe { clk_id.assume_init() };
|
||||
Ok(ClockId::from(res))
|
||||
} else {
|
||||
Err(Errno::from_i32(ret))
|
||||
}
|
||||
}
|
43
vendor/nix-v0.23.1-patched/src/ucontext.rs
vendored
43
vendor/nix-v0.23.1-patched/src/ucontext.rs
vendored
|
@ -1,43 +0,0 @@
|
|||
#[cfg(not(target_env = "musl"))]
|
||||
use crate::Result;
|
||||
#[cfg(not(target_env = "musl"))]
|
||||
use crate::errno::Errno;
|
||||
#[cfg(not(target_env = "musl"))]
|
||||
use std::mem;
|
||||
use crate::sys::signal::SigSet;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct UContext {
|
||||
context: libc::ucontext_t,
|
||||
}
|
||||
|
||||
impl UContext {
|
||||
#[cfg(not(target_env = "musl"))]
|
||||
pub fn get() -> Result<UContext> {
|
||||
let mut context = mem::MaybeUninit::<libc::ucontext_t>::uninit();
|
||||
let res = unsafe { libc::getcontext(context.as_mut_ptr()) };
|
||||
Errno::result(res).map(|_| unsafe {
|
||||
UContext { context: context.assume_init()}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(target_env = "musl"))]
|
||||
pub fn set(&self) -> Result<()> {
|
||||
let res = unsafe {
|
||||
libc::setcontext(&self.context as *const libc::ucontext_t)
|
||||
};
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
pub fn sigmask_mut(&mut self) -> &mut SigSet {
|
||||
unsafe {
|
||||
&mut *(&mut self.context.uc_sigmask as *mut libc::sigset_t as *mut SigSet)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sigmask(&self) -> &SigSet {
|
||||
unsafe {
|
||||
&*(&self.context.uc_sigmask as *const libc::sigset_t as *const SigSet)
|
||||
}
|
||||
}
|
||||
}
|
2994
vendor/nix-v0.23.1-patched/src/unistd.rs
vendored
2994
vendor/nix-v0.23.1-patched/src/unistd.rs
vendored
File diff suppressed because it is too large
Load diff
141
vendor/nix-v0.23.1-patched/test/common/mod.rs
vendored
141
vendor/nix-v0.23.1-patched/test/common/mod.rs
vendored
|
@ -1,141 +0,0 @@
|
|||
use cfg_if::cfg_if;
|
||||
|
||||
#[macro_export] macro_rules! skip {
|
||||
($($reason: expr),+) => {
|
||||
use ::std::io::{self, Write};
|
||||
|
||||
let stderr = io::stderr();
|
||||
let mut handle = stderr.lock();
|
||||
writeln!(handle, $($reason),+).unwrap();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "android", target_os = "linux"))] {
|
||||
#[macro_export] macro_rules! require_capability {
|
||||
($name:expr, $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);
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os= "android"))]
|
||||
#[macro_export] macro_rules! skip_if_cirrus {
|
||||
($reason:expr) => {
|
||||
if std::env::var_os("CIRRUS_CI").is_some() {
|
||||
skip!("{}", $reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[macro_export] macro_rules! skip_if_jailed {
|
||||
($name:expr) => {
|
||||
use ::sysctl::CtlValue;
|
||||
|
||||
if let CtlValue::Int(1) = ::sysctl::value("security.jail.jailed")
|
||||
.unwrap()
|
||||
{
|
||||
skip!("{} cannot run in a jail. Skipping test.", $name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
|
||||
#[macro_export] macro_rules! skip_if_not_root {
|
||||
($name:expr) => {
|
||||
use nix::unistd::Uid;
|
||||
|
||||
if !Uid::current().is_root() {
|
||||
skip!("{} requires root privileges. Skipping test.", $name);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "android", target_os = "linux"))] {
|
||||
#[macro_export] macro_rules! skip_if_seccomp {
|
||||
($name:expr) => {
|
||||
if let Ok(s) = std::fs::read_to_string("/proc/self/status") {
|
||||
for l in s.lines() {
|
||||
let mut fields = l.split_whitespace();
|
||||
if fields.next() == Some("Seccomp:") &&
|
||||
fields.next() != Some("0")
|
||||
{
|
||||
skip!("{} cannot be run in Seccomp mode. Skipping test.",
|
||||
stringify!($name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if #[cfg(not(target_os = "redox"))] {
|
||||
#[macro_export] macro_rules! skip_if_seccomp {
|
||||
($name:expr) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(target_os = "linux")] {
|
||||
#[macro_export] macro_rules! require_kernel_version {
|
||||
($name:expr, $version_requirement:expr) => {
|
||||
use semver::{Version, VersionReq};
|
||||
|
||||
let version_requirement = VersionReq::parse($version_requirement)
|
||||
.expect("Bad match_version provided");
|
||||
|
||||
let uname = nix::sys::utsname::uname();
|
||||
println!("{}", uname.sysname());
|
||||
println!("{}", uname.nodename());
|
||||
println!("{}", uname.release());
|
||||
println!("{}", uname.version());
|
||||
println!("{}", uname.machine());
|
||||
|
||||
// Fix stuff that the semver parser can't handle
|
||||
let fixed_release = &uname.release().to_string()
|
||||
// Fedora 33 reports version as 4.18.el8_2.x86_64 or
|
||||
// 5.18.200-fc33.x86_64. Remove the underscore.
|
||||
.replace("_", "-")
|
||||
// Cirrus-CI reports version as 4.19.112+ . Remove the +
|
||||
.replace("+", "");
|
||||
let mut version = Version::parse(fixed_release).unwrap();
|
||||
|
||||
//Keep only numeric parts
|
||||
version.pre = semver::Prerelease::EMPTY;
|
||||
version.build = semver::BuildMetadata::EMPTY;
|
||||
|
||||
if !version_requirement.matches(&version) {
|
||||
skip!("Skip {} because kernel version `{}` doesn't match the requirement `{}`",
|
||||
stringify!($name), version, version_requirement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
47
vendor/nix-v0.23.1-patched/test/sys/mod.rs
vendored
47
vendor/nix-v0.23.1-patched/test/sys/mod.rs
vendored
|
@ -1,47 +0,0 @@
|
|||
mod test_signal;
|
||||
|
||||
// NOTE: DragonFly lacks a kernel-level implementation of Posix AIO as of
|
||||
// this writing. There is an user-level implementation, but whether aio
|
||||
// works or not heavily depends on which pthread implementation is chosen
|
||||
// by the user at link time. For this reason we do not want to run aio test
|
||||
// cases on DragonFly.
|
||||
#[cfg(any(target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
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"))]
|
||||
mod test_socket;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
mod test_sockopt;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
mod test_select;
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
mod test_sysinfo;
|
||||
#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
|
||||
mod test_termios;
|
||||
#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
|
||||
mod test_ioctl;
|
||||
mod test_wait;
|
||||
mod test_uio;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
mod test_epoll;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod test_inotify;
|
||||
mod test_pthread;
|
||||
#[cfg(any(target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"))]
|
||||
mod test_ptrace;
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
mod test_timerfd;
|
620
vendor/nix-v0.23.1-patched/test/sys/test_aio.rs
vendored
620
vendor/nix-v0.23.1-patched/test/sys/test_aio.rs
vendored
|
@ -1,620 +0,0 @@
|
|||
use libc::{c_int, c_void};
|
||||
use nix::Result;
|
||||
use nix::errno::*;
|
||||
use nix::sys::aio::*;
|
||||
use nix::sys::signal::{SaFlags, SigAction, sigaction, SigevNotify, SigHandler, Signal, SigSet};
|
||||
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<()> {
|
||||
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; };
|
||||
thread::sleep(time::Duration::from_millis(10));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_accessors() {
|
||||
let mut rbuf = vec![0; 4];
|
||||
let aiocb = AioCb::from_mut_slice( 1001,
|
||||
2, //offset
|
||||
&mut rbuf,
|
||||
42, //priority
|
||||
SigevNotify::SigevSignal {
|
||||
signal: Signal::SIGUSR2,
|
||||
si_value: 99
|
||||
},
|
||||
LioOpcode::LIO_NOP);
|
||||
assert_eq!(1001, aiocb.fd());
|
||||
assert_eq!(Some(LioOpcode::LIO_NOP), aiocb.lio_opcode());
|
||||
assert_eq!(4, aiocb.nbytes());
|
||||
assert_eq!(2, aiocb.offset());
|
||||
assert_eq!(42, aiocb.priority());
|
||||
let sev = aiocb.sigevent().sigevent();
|
||||
assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo);
|
||||
assert_eq!(99, sev.sigev_value.sival_ptr as i64);
|
||||
}
|
||||
|
||||
// Tests AioCb.cancel. We aren't trying to test the OS's implementation, only
|
||||
// our bindings. So it's sufficient to check that AioCb.cancel returned any
|
||||
// AioCancelStat value.
|
||||
#[test]
|
||||
#[cfg_attr(target_env = "musl", ignore)]
|
||||
fn test_cancel() {
|
||||
let wbuf: &[u8] = b"CDEF";
|
||||
|
||||
let f = tempfile().unwrap();
|
||||
let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
|
||||
0, //offset
|
||||
wbuf,
|
||||
0, //priority
|
||||
SigevNotify::SigevNone,
|
||||
LioOpcode::LIO_NOP);
|
||||
aiocb.write().unwrap();
|
||||
let err = aiocb.error();
|
||||
assert!(err == Ok(()) || err == Err(Errno::EINPROGRESS));
|
||||
|
||||
let cancelstat = aiocb.cancel();
|
||||
assert!(cancelstat.is_ok());
|
||||
|
||||
// Wait for aiocb to complete, but don't care whether it succeeded
|
||||
let _ = poll_aio(&mut aiocb);
|
||||
let _ = aiocb.aio_return();
|
||||
}
|
||||
|
||||
// Tests using aio_cancel_all for all outstanding IOs.
|
||||
#[test]
|
||||
#[cfg_attr(target_env = "musl", ignore)]
|
||||
fn test_aio_cancel_all() {
|
||||
let wbuf: &[u8] = b"CDEF";
|
||||
|
||||
let f = tempfile().unwrap();
|
||||
let mut aiocb = AioCb::from_slice(f.as_raw_fd(),
|
||||
0, //offset
|
||||
wbuf,
|
||||
0, //priority
|
||||
SigevNotify::SigevNone,
|
||||
LioOpcode::LIO_NOP);
|
||||
aiocb.write().unwrap();
|
||||
let err = aiocb.error();
|
||||
assert!(err == Ok(()) || err == Err(Errno::EINPROGRESS));
|
||||
|
||||
let cancelstat = aio_cancel_all(f.as_raw_fd());
|
||||
assert!(cancelstat.is_ok());
|
||||
|
||||
// Wait for aiocb to complete, but don't care whether it succeeded
|
||||
let _ = poll_aio(&mut aiocb);
|
||||
let _ = aiocb.aio_return();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
|
||||
fn test_fsync() {
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
let mut aiocb = AioCb::from_fd( f.as_raw_fd(),
|
||||
0, //priority
|
||||
SigevNotify::SigevNone);
|
||||
let err = aiocb.fsync(AioFsyncMode::O_SYNC);
|
||||
assert!(err.is_ok());
|
||||
poll_aio(&mut aiocb).unwrap();
|
||||
aiocb.aio_return().unwrap();
|
||||
}
|
||||
|
||||
/// `AioCb::fsync` should not modify the `AioCb` object if `libc::aio_fsync` returns
|
||||
/// an error
|
||||
// Skip on Linux, because Linux's AIO implementation can't detect errors
|
||||
// synchronously
|
||||
#[test]
|
||||
#[cfg(any(target_os = "freebsd", target_os = "macos"))]
|
||||
fn test_fsync_error() {
|
||||
use std::mem;
|
||||
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
// Create an invalid AioFsyncMode
|
||||
let mode = unsafe { mem::transmute(666) };
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
let mut aiocb = AioCb::from_fd( f.as_raw_fd(),
|
||||
0, //priority
|
||||
SigevNotify::SigevNone);
|
||||
let err = aiocb.fsync(mode);
|
||||
assert!(err.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
// On Cirrus on Linux, this test fails due to a glibc bug.
|
||||
// https://github.com/nix-rust/nix/issues/1099
|
||||
#[cfg_attr(target_os = "linux", ignore)]
|
||||
// On Cirrus, aio_suspend is failing with EINVAL
|
||||
// https://github.com/nix-rust/nix/issues/1361
|
||||
#[cfg_attr(target_os = "macos", ignore)]
|
||||
fn test_aio_suspend() {
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
const WBUF: &[u8] = b"CDEFG";
|
||||
let timeout = TimeSpec::seconds(10);
|
||||
let mut rbuf = vec![0; 4];
|
||||
let rlen = rbuf.len();
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
|
||||
let mut wcb = AioCb::from_slice( f.as_raw_fd(),
|
||||
2, //offset
|
||||
WBUF,
|
||||
0, //priority
|
||||
SigevNotify::SigevNone,
|
||||
LioOpcode::LIO_WRITE);
|
||||
|
||||
let mut rcb = AioCb::from_mut_slice( f.as_raw_fd(),
|
||||
8, //offset
|
||||
&mut rbuf,
|
||||
0, //priority
|
||||
SigevNotify::SigevNone,
|
||||
LioOpcode::LIO_READ);
|
||||
wcb.write().unwrap();
|
||||
rcb.read().unwrap();
|
||||
loop {
|
||||
{
|
||||
let cbbuf = [wcb.as_ref(), rcb.as_ref()];
|
||||
let r = aio_suspend(&cbbuf[..], Some(timeout));
|
||||
match r {
|
||||
Err(Errno::EINTR) => continue,
|
||||
Err(e) => panic!("aio_suspend returned {:?}", e),
|
||||
Ok(_) => ()
|
||||
};
|
||||
}
|
||||
if rcb.error() != Err(Errno::EINPROGRESS) &&
|
||||
wcb.error() != Err(Errno::EINPROGRESS) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(wcb.aio_return().unwrap() as usize, WBUF.len());
|
||||
assert_eq!(rcb.aio_return().unwrap() as usize, rlen);
|
||||
}
|
||||
|
||||
// Test a simple aio operation with no completion notification. We must poll
|
||||
// for completion
|
||||
#[test]
|
||||
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
|
||||
fn test_read() {
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
let mut rbuf = vec![0; 4];
|
||||
const EXPECT: &[u8] = b"cdef";
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
{
|
||||
let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(),
|
||||
2, //offset
|
||||
&mut 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());
|
||||
}
|
||||
|
||||
assert_eq!(EXPECT, rbuf.deref().deref());
|
||||
}
|
||||
|
||||
/// `AioCb::read` should not modify the `AioCb` object if `libc::aio_read`
|
||||
/// returns an error
|
||||
// Skip on Linux, because Linux's AIO implementation can't detect errors
|
||||
// synchronously
|
||||
#[test]
|
||||
#[cfg(any(target_os = "freebsd", target_os = "macos"))]
|
||||
fn test_read_error() {
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
let mut rbuf = vec![0; 4];
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(),
|
||||
-1, //an invalid offset
|
||||
&mut rbuf,
|
||||
0, //priority
|
||||
SigevNotify::SigevNone,
|
||||
LioOpcode::LIO_NOP);
|
||||
assert!(aiocb.read().is_err());
|
||||
}
|
||||
|
||||
// Tests from_mut_slice
|
||||
#[test]
|
||||
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
|
||||
fn test_read_into_mut_slice() {
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
let mut rbuf = vec![0; 4];
|
||||
const EXPECT: &[u8] = b"cdef";
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
{
|
||||
let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(),
|
||||
2, //offset
|
||||
&mut 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());
|
||||
}
|
||||
|
||||
assert_eq!(rbuf, EXPECT);
|
||||
}
|
||||
|
||||
// Tests from_ptr
|
||||
#[test]
|
||||
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
|
||||
fn test_read_into_pointer() {
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
let mut rbuf = vec![0; 4];
|
||||
const EXPECT: &[u8] = b"cdef";
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
{
|
||||
// Safety: ok because rbuf lives until after poll_aio
|
||||
let mut aiocb = unsafe {
|
||||
AioCb::from_mut_ptr( f.as_raw_fd(),
|
||||
2, //offset
|
||||
rbuf.as_mut_ptr() as *mut c_void,
|
||||
rbuf.len(),
|
||||
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());
|
||||
}
|
||||
|
||||
assert_eq!(rbuf, EXPECT);
|
||||
}
|
||||
|
||||
// Test reading into an immutable buffer. It should fail
|
||||
// FIXME: This test fails to panic on Linux/musl
|
||||
#[test]
|
||||
#[should_panic(expected = "Can't read into an immutable buffer")]
|
||||
#[cfg_attr(target_env = "musl", ignore)]
|
||||
fn test_read_immutable_buffer() {
|
||||
let rbuf: &[u8] = b"CDEF";
|
||||
let f = tempfile().unwrap();
|
||||
let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
|
||||
2, //offset
|
||||
rbuf,
|
||||
0, //priority
|
||||
SigevNotify::SigevNone,
|
||||
LioOpcode::LIO_NOP);
|
||||
aiocb.read().unwrap();
|
||||
}
|
||||
|
||||
|
||||
// Test a simple aio operation with no completion notification. We must poll
|
||||
// for completion. Unlike test_aio_read, this test uses AioCb::from_slice
|
||||
#[test]
|
||||
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
|
||||
fn test_write() {
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
let wbuf = "CDEF".to_string().into_bytes();
|
||||
let mut rbuf = Vec::new();
|
||||
const EXPECT: &[u8] = b"abCDEF123456";
|
||||
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
let mut aiocb = AioCb::from_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, wbuf.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_ptr`
|
||||
#[test]
|
||||
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
|
||||
fn test_write_from_pointer() {
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
let wbuf = "CDEF".to_string().into_bytes();
|
||||
let mut rbuf = Vec::new();
|
||||
const EXPECT: &[u8] = b"abCDEF123456";
|
||||
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
// Safety: ok because aiocb outlives poll_aio
|
||||
let mut aiocb = unsafe {
|
||||
AioCb::from_ptr( f.as_raw_fd(),
|
||||
2, //offset
|
||||
wbuf.as_ptr() as *const c_void,
|
||||
wbuf.len(),
|
||||
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, wbuf.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);
|
||||
}
|
||||
|
||||
/// `AioCb::write` should not modify the `AioCb` object if `libc::aio_write`
|
||||
/// returns an error
|
||||
// Skip on Linux, because Linux's AIO implementation can't detect errors
|
||||
// synchronously
|
||||
#[test]
|
||||
#[cfg(any(target_os = "freebsd", target_os = "macos"))]
|
||||
fn test_write_error() {
|
||||
let wbuf = "CDEF".to_string().into_bytes();
|
||||
let mut aiocb = AioCb::from_slice( 666, // An invalid file descriptor
|
||||
0, //offset
|
||||
&wbuf,
|
||||
0, //priority
|
||||
SigevNotify::SigevNone,
|
||||
LioOpcode::LIO_NOP);
|
||||
assert!(aiocb.write().is_err());
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref SIGNALED: AtomicBool = AtomicBool::new(false);
|
||||
}
|
||||
|
||||
extern fn sigfunc(_: c_int) {
|
||||
SIGNALED.store(true, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
// Test an aio operation with completion delivered by a signal
|
||||
// FIXME: This test is ignored on mips because of failures in qemu in CI
|
||||
#[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().expect("Mutex got poisoned by another test");
|
||||
let sa = SigAction::new(SigHandler::Handler(sigfunc),
|
||||
SaFlags::SA_RESETHAND,
|
||||
SigSet::empty());
|
||||
SIGNALED.store(false, Ordering::Relaxed);
|
||||
unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap();
|
||||
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
const WBUF: &[u8] = b"CDEF";
|
||||
let mut rbuf = Vec::new();
|
||||
const EXPECT: &[u8] = b"abCDEF123456";
|
||||
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
|
||||
2, //offset
|
||||
WBUF,
|
||||
0, //priority
|
||||
SigevNotify::SigevSignal {
|
||||
signal: Signal::SIGUSR2,
|
||||
si_value: 0 //TODO: validate in sigfunc
|
||||
},
|
||||
LioOpcode::LIO_NOP);
|
||||
aiocb.write().unwrap();
|
||||
while !SIGNALED.load(Ordering::Relaxed) {
|
||||
thread::sleep(time::Duration::from_millis(10));
|
||||
}
|
||||
|
||||
assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.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);
|
||||
}
|
||||
|
||||
// Test LioCb::listio with LIO_WAIT, so all AIO ops should be complete by the
|
||||
// time listio returns.
|
||||
#[test]
|
||||
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
|
||||
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
|
||||
fn test_liocb_listio_wait() {
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
const WBUF: &[u8] = b"CDEF";
|
||||
let mut rbuf = vec![0; 4];
|
||||
let rlen = rbuf.len();
|
||||
let mut rbuf2 = Vec::new();
|
||||
const EXPECT: &[u8] = b"abCDEF123456";
|
||||
let mut f = tempfile().unwrap();
|
||||
|
||||
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 err = liocb.listio(LioMode::LIO_WAIT, SigevNotify::SigevNone);
|
||||
err.expect("lio_listio");
|
||||
|
||||
assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len());
|
||||
assert_eq!(liocb.aio_return(1).unwrap() as usize, rlen);
|
||||
}
|
||||
assert_eq!(rbuf.deref().deref(), b"3456");
|
||||
|
||||
f.seek(SeekFrom::Start(0)).unwrap();
|
||||
let len = f.read_to_end(&mut rbuf2).unwrap();
|
||||
assert_eq!(len, EXPECT.len());
|
||||
assert_eq!(rbuf2, EXPECT);
|
||||
}
|
||||
|
||||
// Test LioCb::listio with LIO_NOWAIT and no SigEvent, so we must use some other
|
||||
// mechanism to check for the individual AioCb's completion.
|
||||
#[test]
|
||||
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
|
||||
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
|
||||
fn test_liocb_listio_nowait() {
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
const WBUF: &[u8] = b"CDEF";
|
||||
let mut rbuf = vec![0; 4];
|
||||
let rlen = rbuf.len();
|
||||
let mut rbuf2 = Vec::new();
|
||||
const EXPECT: &[u8] = b"abCDEF123456";
|
||||
let mut f = tempfile().unwrap();
|
||||
|
||||
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 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);
|
||||
}
|
||||
assert_eq!(rbuf.deref().deref(), b"3456");
|
||||
|
||||
f.seek(SeekFrom::Start(0)).unwrap();
|
||||
let len = f.read_to_end(&mut rbuf2).unwrap();
|
||||
assert_eq!(len, EXPECT.len());
|
||||
assert_eq!(rbuf2, EXPECT);
|
||||
}
|
||||
|
||||
// Test LioCb::listio with LIO_NOWAIT and a SigEvent to indicate when all
|
||||
// AioCb's are complete.
|
||||
// FIXME: This test is ignored on mips/mips64 because of failures in qemu in CI.
|
||||
#[test]
|
||||
#[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().expect("Mutex got poisoned by another test");
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
const WBUF: &[u8] = b"CDEF";
|
||||
let mut rbuf = vec![0; 4];
|
||||
let rlen = rbuf.len();
|
||||
let mut rbuf2 = Vec::new();
|
||||
const EXPECT: &[u8] = b"abCDEF123456";
|
||||
let mut f = tempfile().unwrap();
|
||||
let sa = SigAction::new(SigHandler::Handler(sigfunc),
|
||||
SaFlags::SA_RESETHAND,
|
||||
SigSet::empty());
|
||||
let sigev_notify = SigevNotify::SigevSignal { signal: Signal::SIGUSR2,
|
||||
si_value: 0 };
|
||||
|
||||
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();
|
||||
SIGNALED.store(false, Ordering::Relaxed);
|
||||
unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap();
|
||||
let err = liocb.listio(LioMode::LIO_NOWAIT, sigev_notify);
|
||||
err.expect("lio_listio");
|
||||
while !SIGNALED.load(Ordering::Relaxed) {
|
||||
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!(rbuf.deref().deref(), b"3456");
|
||||
|
||||
f.seek(SeekFrom::Start(0)).unwrap();
|
||||
let len = f.read_to_end(&mut rbuf2).unwrap();
|
||||
assert_eq!(len, EXPECT.len());
|
||||
assert_eq!(rbuf2, EXPECT);
|
||||
}
|
||||
|
||||
// Try to use LioCb::listio to read into an immutable buffer. It should fail
|
||||
// FIXME: This test fails to panic on Linux/musl
|
||||
#[test]
|
||||
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
|
||||
#[should_panic(expected = "Can't read into an immutable buffer")]
|
||||
#[cfg_attr(target_env = "musl", ignore)]
|
||||
fn test_liocb_listio_read_immutable() {
|
||||
let rbuf: &[u8] = b"abcd";
|
||||
let f = tempfile().unwrap();
|
||||
|
||||
|
||||
let mut liocb = LioCbBuilder::with_capacity(1)
|
||||
.emplace_slice(
|
||||
f.as_raw_fd(),
|
||||
2, //offset
|
||||
rbuf,
|
||||
0, //priority
|
||||
SigevNotify::SigevNone,
|
||||
LioOpcode::LIO_READ
|
||||
).finish();
|
||||
let _ = liocb.listio(LioMode::LIO_NOWAIT, SigevNotify::SigevNone);
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
// Test dropping an AioCb that hasn't yet finished.
|
||||
// This must happen in its own process, because on OSX this test seems to hose
|
||||
// the AIO subsystem and causes subsequent tests to fail
|
||||
#[test]
|
||||
#[should_panic(expected = "Dropped an in-progress AioCb")]
|
||||
#[cfg(all(not(target_env = "musl"),
|
||||
any(target_os = "linux",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd")))]
|
||||
fn test_drop() {
|
||||
use nix::sys::aio::*;
|
||||
use nix::sys::signal::*;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use tempfile::tempfile;
|
||||
|
||||
const WBUF: &[u8] = b"CDEF";
|
||||
|
||||
let f = tempfile().unwrap();
|
||||
f.set_len(6).unwrap();
|
||||
let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
|
||||
2, //offset
|
||||
WBUF,
|
||||
0, //priority
|
||||
SigevNotify::SigevNone,
|
||||
LioOpcode::LIO_NOP);
|
||||
aiocb.write().unwrap();
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
use nix::sys::epoll::{EpollCreateFlags, EpollFlags, EpollOp, EpollEvent};
|
||||
use nix::sys::epoll::{epoll_create1, epoll_ctl};
|
||||
use nix::errno::Errno;
|
||||
|
||||
#[test]
|
||||
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);
|
||||
|
||||
let result = epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, None);
|
||||
assert!(result.is_err());
|
||||
assert_eq!(result.unwrap_err(), Errno::EINVAL);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_epoll_ctl() {
|
||||
let efd = epoll_create1(EpollCreateFlags::empty()).unwrap();
|
||||
let mut event = EpollEvent::new(EpollFlags::EPOLLIN | EpollFlags::EPOLLERR, 1);
|
||||
epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, &mut event).unwrap();
|
||||
epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None).unwrap();
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
use nix::sys::inotify::{AddWatchFlags,InitFlags,Inotify};
|
||||
use nix::errno::Errno;
|
||||
use std::ffi::OsString;
|
||||
use std::fs::{rename, File};
|
||||
|
||||
#[test]
|
||||
pub fn test_inotify() {
|
||||
let instance = Inotify::init(InitFlags::IN_NONBLOCK)
|
||||
.unwrap();
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
|
||||
instance.add_watch(tempdir.path(), AddWatchFlags::IN_ALL_EVENTS).unwrap();
|
||||
|
||||
let events = instance.read_events();
|
||||
assert_eq!(events.unwrap_err(), Errno::EAGAIN);
|
||||
|
||||
File::create(tempdir.path().join("test")).unwrap();
|
||||
|
||||
let events = instance.read_events().unwrap();
|
||||
assert_eq!(events[0].name, Some(OsString::from("test")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_inotify_multi_events() {
|
||||
let instance = Inotify::init(InitFlags::IN_NONBLOCK)
|
||||
.unwrap();
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
|
||||
instance.add_watch(tempdir.path(), AddWatchFlags::IN_ALL_EVENTS).unwrap();
|
||||
|
||||
let events = instance.read_events();
|
||||
assert_eq!(events.unwrap_err(), Errno::EAGAIN);
|
||||
|
||||
File::create(tempdir.path().join("test")).unwrap();
|
||||
rename(tempdir.path().join("test"), tempdir.path().join("test2")).unwrap();
|
||||
|
||||
// Now there should be 5 events in queue:
|
||||
// - IN_CREATE on test
|
||||
// - IN_OPEN on test
|
||||
// - IN_CLOSE_WRITE on test
|
||||
// - IN_MOVED_FROM on test with a cookie
|
||||
// - IN_MOVED_TO on test2 with the same cookie
|
||||
|
||||
let events = instance.read_events().unwrap();
|
||||
assert_eq!(events.len(), 5);
|
||||
|
||||
assert_eq!(events[0].mask, AddWatchFlags::IN_CREATE);
|
||||
assert_eq!(events[0].name, Some(OsString::from("test")));
|
||||
|
||||
assert_eq!(events[1].mask, AddWatchFlags::IN_OPEN);
|
||||
assert_eq!(events[1].name, Some(OsString::from("test")));
|
||||
|
||||
assert_eq!(events[2].mask, AddWatchFlags::IN_CLOSE_WRITE);
|
||||
assert_eq!(events[2].name, Some(OsString::from("test")));
|
||||
|
||||
assert_eq!(events[3].mask, AddWatchFlags::IN_MOVED_FROM);
|
||||
assert_eq!(events[3].name, Some(OsString::from("test")));
|
||||
|
||||
assert_eq!(events[4].mask, AddWatchFlags::IN_MOVED_TO);
|
||||
assert_eq!(events[4].name, Some(OsString::from("test2")));
|
||||
|
||||
assert_eq!(events[3].cookie, events[4].cookie);
|
||||
}
|
337
vendor/nix-v0.23.1-patched/test/sys/test_ioctl.rs
vendored
337
vendor/nix-v0.23.1-patched/test/sys/test_ioctl.rs
vendored
|
@ -1,337 +0,0 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
// Simple tests to ensure macro generated fns compile
|
||||
ioctl_none_bad!(do_bad, 0x1234);
|
||||
ioctl_read_bad!(do_bad_read, 0x1234, u16);
|
||||
ioctl_write_int_bad!(do_bad_write_int, 0x1234);
|
||||
ioctl_write_ptr_bad!(do_bad_write_ptr, 0x1234, u8);
|
||||
ioctl_readwrite_bad!(do_bad_readwrite, 0x1234, u32);
|
||||
ioctl_none!(do_none, 0, 0);
|
||||
ioctl_read!(read_test, 0, 0, u32);
|
||||
ioctl_write_int!(write_ptr_int, 0, 0);
|
||||
ioctl_write_ptr!(write_ptr_u8, 0, 0, u8);
|
||||
ioctl_write_ptr!(write_ptr_u32, 0, 0, u32);
|
||||
ioctl_write_ptr!(write_ptr_u64, 0, 0, u64);
|
||||
ioctl_readwrite!(readwrite_test, 0, 0, u64);
|
||||
ioctl_read_buf!(readbuf_test, 0, 0, u32);
|
||||
const SPI_IOC_MAGIC: u8 = b'k';
|
||||
const SPI_IOC_MESSAGE: u8 = 0;
|
||||
ioctl_write_buf!(writebuf_test_consts, SPI_IOC_MAGIC, SPI_IOC_MESSAGE, u8);
|
||||
ioctl_write_buf!(writebuf_test_u8, 0, 0, u8);
|
||||
ioctl_write_buf!(writebuf_test_u32, 0, 0, u32);
|
||||
ioctl_write_buf!(writebuf_test_u64, 0, 0, u64);
|
||||
ioctl_readwrite_buf!(readwritebuf_test, 0, 0, u32);
|
||||
|
||||
// See C code for source of values for op calculations (does NOT work for mips/powerpc):
|
||||
// https://gist.github.com/posborne/83ea6880770a1aef332e
|
||||
//
|
||||
// TODO: Need a way to compute these constants at test time. Using precomputed
|
||||
// values is fragile and needs to be maintained.
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
mod linux {
|
||||
#[test]
|
||||
fn test_op_none() {
|
||||
if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){
|
||||
assert_eq!(request_code_none!(b'q', 10) as u32, 0x2000_710A);
|
||||
assert_eq!(request_code_none!(b'a', 255) as u32, 0x2000_61FF);
|
||||
} else {
|
||||
assert_eq!(request_code_none!(b'q', 10) as u32, 0x0000_710A);
|
||||
assert_eq!(request_code_none!(b'a', 255) as u32, 0x0000_61FF);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_op_write() {
|
||||
if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){
|
||||
assert_eq!(request_code_write!(b'z', 10, 1) as u32, 0x8001_7A0A);
|
||||
assert_eq!(request_code_write!(b'z', 10, 512) as u32, 0x8200_7A0A);
|
||||
} else {
|
||||
assert_eq!(request_code_write!(b'z', 10, 1) as u32, 0x4001_7A0A);
|
||||
assert_eq!(request_code_write!(b'z', 10, 512) as u32, 0x4200_7A0A);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[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,
|
||||
0x8000_7A0A);
|
||||
} else {
|
||||
assert_eq!(request_code_write!(b'z', 10, 1u64 << 32) as u32,
|
||||
0x4000_7A0A);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_op_read() {
|
||||
if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){
|
||||
assert_eq!(request_code_read!(b'z', 10, 1) as u32, 0x4001_7A0A);
|
||||
assert_eq!(request_code_read!(b'z', 10, 512) as u32, 0x4200_7A0A);
|
||||
} else {
|
||||
assert_eq!(request_code_read!(b'z', 10, 1) as u32, 0x8001_7A0A);
|
||||
assert_eq!(request_code_read!(b'z', 10, 512) as u32, 0x8200_7A0A);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[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,
|
||||
0x4000_7A0A);
|
||||
} else {
|
||||
assert_eq!(request_code_read!(b'z', 10, 1u64 << 32) as u32,
|
||||
0x8000_7A0A);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_op_read_write() {
|
||||
assert_eq!(request_code_readwrite!(b'z', 10, 1) as u32, 0xC001_7A0A);
|
||||
assert_eq!(request_code_readwrite!(b'z', 10, 512) as u32, 0xC200_7A0A);
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[test]
|
||||
fn test_op_read_write_64() {
|
||||
assert_eq!(request_code_readwrite!(b'z', 10, 1u64 << 32) as u32,
|
||||
0xC000_7A0A);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"))]
|
||||
mod bsd {
|
||||
#[test]
|
||||
fn test_op_none() {
|
||||
assert_eq!(request_code_none!(b'q', 10), 0x2000_710A);
|
||||
assert_eq!(request_code_none!(b'a', 255), 0x2000_61FF);
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
|
||||
#[test]
|
||||
fn test_op_write_int() {
|
||||
assert_eq!(request_code_write_int!(b'v', 4), 0x2004_7604);
|
||||
assert_eq!(request_code_write_int!(b'p', 2), 0x2004_7002);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_op_write() {
|
||||
assert_eq!(request_code_write!(b'z', 10, 1), 0x8001_7A0A);
|
||||
assert_eq!(request_code_write!(b'z', 10, 512), 0x8200_7A0A);
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[test]
|
||||
fn test_op_write_64() {
|
||||
assert_eq!(request_code_write!(b'z', 10, 1u64 << 32), 0x8000_7A0A);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_op_read() {
|
||||
assert_eq!(request_code_read!(b'z', 10, 1), 0x4001_7A0A);
|
||||
assert_eq!(request_code_read!(b'z', 10, 512), 0x4200_7A0A);
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[test]
|
||||
fn test_op_read_64() {
|
||||
assert_eq!(request_code_read!(b'z', 10, 1u64 << 32), 0x4000_7A0A);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_op_read_write() {
|
||||
assert_eq!(request_code_readwrite!(b'z', 10, 1), 0xC001_7A0A);
|
||||
assert_eq!(request_code_readwrite!(b'z', 10, 512), 0xC200_7A0A);
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[test]
|
||||
fn test_op_read_write_64() {
|
||||
assert_eq!(request_code_readwrite!(b'z', 10, 1u64 << 32), 0xC000_7A0A);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
mod linux_ioctls {
|
||||
use std::mem;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
use tempfile::tempfile;
|
||||
use libc::{TCGETS, TCSBRK, TCSETS, TIOCNXCL, termios};
|
||||
|
||||
use nix::errno::Errno;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
ioctl_read_bad!(tcgets, TCGETS, termios);
|
||||
#[test]
|
||||
fn test_ioctl_read_bad() {
|
||||
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));
|
||||
}
|
||||
|
||||
ioctl_write_int_bad!(tcsbrk, TCSBRK);
|
||||
#[test]
|
||||
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));
|
||||
}
|
||||
|
||||
ioctl_write_ptr_bad!(tcsets, TCSETS, termios);
|
||||
#[test]
|
||||
fn test_ioctl_write_ptr_bad() {
|
||||
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));
|
||||
}
|
||||
|
||||
// FIXME: Find a suitable example for `ioctl_readwrite_bad`
|
||||
|
||||
// From linux/videodev2.h
|
||||
ioctl_none!(log_status, b'V', 70);
|
||||
#[test]
|
||||
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));
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct v4l2_audio {
|
||||
index: u32,
|
||||
name: [u8; 32],
|
||||
capability: u32,
|
||||
mode: u32,
|
||||
reserved: [u32; 2],
|
||||
}
|
||||
|
||||
// From linux/videodev2.h
|
||||
ioctl_write_ptr!(s_audio, b'V', 34, v4l2_audio);
|
||||
#[test]
|
||||
fn test_ioctl_write_ptr() {
|
||||
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));
|
||||
}
|
||||
|
||||
// From linux/net/bluetooth/hci_sock.h
|
||||
const HCI_IOC_MAGIC: u8 = b'H';
|
||||
const HCI_IOC_HCIDEVUP: u8 = 201;
|
||||
ioctl_write_int!(hcidevup, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP);
|
||||
#[test]
|
||||
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));
|
||||
}
|
||||
|
||||
// From linux/videodev2.h
|
||||
ioctl_read!(g_audio, b'V', 33, v4l2_audio);
|
||||
#[test]
|
||||
fn test_ioctl_read() {
|
||||
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));
|
||||
}
|
||||
|
||||
// From linux/videodev2.h
|
||||
ioctl_readwrite!(enum_audio, b'V', 65, v4l2_audio);
|
||||
#[test]
|
||||
fn test_ioctl_readwrite() {
|
||||
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));
|
||||
}
|
||||
|
||||
// FIXME: Find a suitable example for `ioctl_read_buf`.
|
||||
|
||||
#[repr(C)]
|
||||
pub struct spi_ioc_transfer {
|
||||
tx_buf: u64,
|
||||
rx_buf: u64,
|
||||
len: u32,
|
||||
speed_hz: u32,
|
||||
delay_usecs: u16,
|
||||
bits_per_word: u8,
|
||||
cs_change: u8,
|
||||
tx_nbits: u8,
|
||||
rx_nbits: u8,
|
||||
pad: u16,
|
||||
}
|
||||
|
||||
// From linux/spi/spidev.h
|
||||
ioctl_write_buf!(spi_ioc_message, super::SPI_IOC_MAGIC, super::SPI_IOC_MESSAGE, spi_ioc_transfer);
|
||||
#[test]
|
||||
fn test_ioctl_write_buf() {
|
||||
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));
|
||||
}
|
||||
|
||||
// FIXME: Find a suitable example for `ioctl_readwrite_buf`.
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
mod freebsd_ioctls {
|
||||
use std::mem;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
use tempfile::tempfile;
|
||||
use libc::termios;
|
||||
|
||||
use nix::errno::Errno;
|
||||
|
||||
// From sys/sys/ttycom.h
|
||||
const TTY_IOC_MAGIC: u8 = b't';
|
||||
const TTY_IOC_TYPE_NXCL: u8 = 14;
|
||||
const TTY_IOC_TYPE_GETA: u8 = 19;
|
||||
const TTY_IOC_TYPE_SETA: u8 = 20;
|
||||
|
||||
ioctl_none!(tiocnxcl, TTY_IOC_MAGIC, TTY_IOC_TYPE_NXCL);
|
||||
#[test]
|
||||
fn test_ioctl_none() {
|
||||
let file = tempfile().unwrap();
|
||||
let res = unsafe { tiocnxcl(file.as_raw_fd()) };
|
||||
assert_eq!(res, Err(Errno::ENOTTY));
|
||||
}
|
||||
|
||||
ioctl_read!(tiocgeta, TTY_IOC_MAGIC, TTY_IOC_TYPE_GETA, termios);
|
||||
#[test]
|
||||
fn test_ioctl_read() {
|
||||
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));
|
||||
}
|
||||
|
||||
ioctl_write_ptr!(tiocseta, TTY_IOC_MAGIC, TTY_IOC_TYPE_SETA, termios);
|
||||
#[test]
|
||||
fn test_ioctl_write_ptr() {
|
||||
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));
|
||||
}
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
// vim: tw=80
|
||||
|
||||
// Annoyingly, Cargo is unable to conditionally build an entire test binary. So
|
||||
// we must disable the test here rather than in Cargo.toml
|
||||
#![cfg(target_os = "freebsd")]
|
||||
|
||||
use nix::errno::*;
|
||||
use nix::libc::off_t;
|
||||
use nix::sys::aio::*;
|
||||
use nix::sys::signal::SigevNotify;
|
||||
use nix::unistd::{SysconfVar, sysconf};
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::{thread, time};
|
||||
use sysctl::CtlValue;
|
||||
use tempfile::tempfile;
|
||||
|
||||
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() {
|
||||
loop {
|
||||
let e = liocb.error(j);
|
||||
match e {
|
||||
Ok(()) => break,
|
||||
Err(Errno::EINPROGRESS) =>
|
||||
thread::sleep(time::Duration::from_millis(10)),
|
||||
Err(x) => panic!("aio_error({:?})", x)
|
||||
}
|
||||
}
|
||||
assert_eq!(liocb.aio_return(j).unwrap(), BYTES_PER_OP as isize);
|
||||
}
|
||||
}
|
||||
|
||||
// Deliberately exceed system resource limits, causing lio_listio to return EIO.
|
||||
// This test must run in its own process since it deliberately uses all AIO
|
||||
// resources. ATM it is only enabled on FreeBSD, because I don't know how to
|
||||
// check system AIO limits on other operating systems.
|
||||
#[test]
|
||||
fn test_lio_listio_resubmit() {
|
||||
let mut resubmit_count = 0;
|
||||
|
||||
// Lookup system resource limits
|
||||
let alm = sysconf(SysconfVar::AIO_LISTIO_MAX)
|
||||
.expect("sysconf").unwrap() as usize;
|
||||
let maqpp = if let CtlValue::Int(x) = sysctl::value(
|
||||
"vfs.aio.max_aio_queue_per_proc").unwrap(){
|
||||
x as usize
|
||||
} else {
|
||||
panic!("unknown sysctl");
|
||||
};
|
||||
|
||||
// Find lio_listio sizes that satisfy the AIO_LISTIO_MAX constraint and also
|
||||
// result in a final lio_listio call that can only partially be queued
|
||||
let target_ops = maqpp + alm / 2;
|
||||
let num_listios = (target_ops + alm - 3) / (alm - 2);
|
||||
let ops_per_listio = (target_ops + num_listios - 1) / num_listios;
|
||||
assert!((num_listios - 1) * ops_per_listio < maqpp,
|
||||
"the last lio_listio won't make any progress; fix the algorithm");
|
||||
println!("Using {:?} LioCbs of {:?} operations apiece", num_listios,
|
||||
ops_per_listio);
|
||||
|
||||
let f = tempfile().unwrap();
|
||||
let buffer_set = (0..num_listios).map(|_| {
|
||||
(0..ops_per_listio).map(|_| {
|
||||
vec![0u8; BYTES_PER_OP]
|
||||
}).collect::<Vec<_>>()
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
let mut liocbs = (0..num_listios).map(|i| {
|
||||
let mut builder = LioCbBuilder::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 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) {
|
||||
//
|
||||
thread::sleep(time::Duration::from_millis(10));
|
||||
resubmit_count += 1;
|
||||
err = liocb.listio_resubmit(LioMode::LIO_NOWAIT,
|
||||
SigevNotify::SigevNone);
|
||||
}
|
||||
liocb
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
// Ensure that every AioCb completed
|
||||
for liocb in liocbs.iter_mut() {
|
||||
finish_liocb(liocb);
|
||||
}
|
||||
|
||||
if resubmit_count > 0 {
|
||||
println!("Resubmitted {:?} times, test passed", resubmit_count);
|
||||
} else {
|
||||
println!("Never resubmitted. Test ambiguous");
|
||||
}
|
||||
}
|
92
vendor/nix-v0.23.1-patched/test/sys/test_mman.rs
vendored
92
vendor/nix-v0.23.1-patched/test/sys/test_mman.rs
vendored
|
@ -1,92 +0,0 @@
|
|||
use nix::sys::mman::{mmap, MapFlags, ProtFlags};
|
||||
|
||||
#[test]
|
||||
fn test_mmap_anonymous() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(target_os = "linux", target_os = "netbsd"))]
|
||||
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,
|
||||
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
|
||||
MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, -1, 0)
|
||||
.unwrap();
|
||||
std::slice::from_raw_parts_mut(mem as * mut u8, ONE_K)
|
||||
};
|
||||
assert_eq !(slice[ONE_K - 1], 0x00);
|
||||
slice[ONE_K - 1] = 0xFF;
|
||||
assert_eq !(slice[ONE_K - 1], 0xFF);
|
||||
|
||||
let slice : &mut[u8] = unsafe {
|
||||
#[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)
|
||||
};
|
||||
|
||||
// The first KB should still have the old data in it.
|
||||
assert_eq !(slice[ONE_K - 1], 0xFF);
|
||||
|
||||
// The additional range should be zero-init'd and accessible.
|
||||
assert_eq !(slice[10 * ONE_K - 1], 0x00);
|
||||
slice[10 * ONE_K - 1] = 0xFF;
|
||||
assert_eq !(slice[10 * ONE_K - 1], 0xFF);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(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)]
|
||||
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,
|
||||
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
|
||||
MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, -1, 0)
|
||||
.unwrap();
|
||||
std::slice::from_raw_parts_mut(mem as * mut u8, ONE_K)
|
||||
};
|
||||
assert_eq !(slice[ONE_K - 1], 0x00);
|
||||
slice[ONE_K - 1] = 0xFF;
|
||||
assert_eq !(slice[ONE_K - 1], 0xFF);
|
||||
|
||||
let slice : &mut[u8] = unsafe {
|
||||
#[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)
|
||||
};
|
||||
|
||||
// The first KB should still be accessible and have the old data in it.
|
||||
assert_eq !(slice[ONE_K - 1], 0xFF);
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
use nix::sys::pthread::*;
|
||||
|
||||
#[cfg(any(target_env = "musl", target_os = "redox"))]
|
||||
#[test]
|
||||
fn test_pthread_self() {
|
||||
let tid = pthread_self();
|
||||
assert!(tid != ::std::ptr::null_mut());
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_env = "musl", target_os = "redox")))]
|
||||
#[test]
|
||||
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.");
|
||||
}
|
219
vendor/nix-v0.23.1-patched/test/sys/test_ptrace.rs
vendored
219
vendor/nix-v0.23.1-patched/test/sys/test_ptrace.rs
vendored
|
@ -1,219 +0,0 @@
|
|||
use nix::errno::Errno;
|
||||
use nix::unistd::getpid;
|
||||
use nix::sys::ptrace;
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
use nix::sys::ptrace::Options;
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
use std::mem;
|
||||
|
||||
use crate::*;
|
||||
|
||||
#[test]
|
||||
fn test_ptrace() {
|
||||
// Just make sure ptrace can be called at all, for now.
|
||||
// FIXME: qemu-user doesn't implement ptrace on all arches, so permit ENOSYS
|
||||
require_capability!("test_ptrace", CAP_SYS_PTRACE);
|
||||
let err = ptrace::attach(getpid()).unwrap_err();
|
||||
assert!(err == Errno::EPERM || err == Errno::EINVAL ||
|
||||
err == 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);
|
||||
let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD).unwrap_err();
|
||||
assert!(err != Errno::EOPNOTSUPP);
|
||||
}
|
||||
|
||||
// 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);
|
||||
let err = ptrace::getevent(getpid()).unwrap_err();
|
||||
assert!(err != Errno::EOPNOTSUPP);
|
||||
}
|
||||
|
||||
// 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!");
|
||||
}
|
||||
}
|
||||
|
||||
// Just make sure ptrace_setsiginfo can be called at all, for now.
|
||||
#[test]
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
fn test_ptrace_setsiginfo() {
|
||||
require_capability!("test_ptrace_setsiginfo", CAP_SYS_PTRACE);
|
||||
let siginfo = unsafe { mem::zeroed() };
|
||||
if let Err(Errno::EOPNOTSUPP) = ptrace::setsiginfo(getpid(), &siginfo) {
|
||||
panic!("ptrace_setsiginfo returns Errno::EOPNOTSUPP!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_ptrace_cont() {
|
||||
use nix::sys::ptrace;
|
||||
use nix::sys::signal::{raise, Signal};
|
||||
use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus};
|
||||
use nix::unistd::fork;
|
||||
use nix::unistd::ForkResult::*;
|
||||
|
||||
require_capability!("test_ptrace_cont", CAP_SYS_PTRACE);
|
||||
|
||||
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.
|
||||
// We (ab)use this behavior to detect the affected platforms
|
||||
// and skip the test then.
|
||||
// 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 {
|
||||
return;
|
||||
}
|
||||
|
||||
match unsafe{fork()}.expect("Error: Fork Failed") {
|
||||
Child => {
|
||||
ptrace::traceme().unwrap();
|
||||
// As recommended by ptrace(2), raise SIGTRAP to pause the child
|
||||
// until the parent is ready to continue
|
||||
loop {
|
||||
raise(Signal::SIGTRAP).unwrap();
|
||||
}
|
||||
|
||||
},
|
||||
Parent { child } => {
|
||||
assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)));
|
||||
ptrace::cont(child, None).unwrap();
|
||||
assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)));
|
||||
ptrace::cont(child, Some(Signal::SIGKILL)).unwrap();
|
||||
match waitpid(child, None) {
|
||||
Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) if pid == child => {
|
||||
// FIXME It's been observed on some systems (apple) the
|
||||
// tracee may not be killed but remain as a zombie process
|
||||
// affecting other wait based tests. Add an extra kill just
|
||||
// to make sure there are no zombies.
|
||||
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"),
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[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().expect("Mutex got poisoned by another test");
|
||||
|
||||
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",
|
||||
target_arch = "x86"),
|
||||
target_env = "gnu"))]
|
||||
#[test]
|
||||
fn test_ptrace_syscall() {
|
||||
use nix::sys::signal::kill;
|
||||
use nix::sys::ptrace;
|
||||
use nix::sys::signal::Signal;
|
||||
use nix::sys::wait::{waitpid, WaitStatus};
|
||||
use nix::unistd::fork;
|
||||
use nix::unistd::getpid;
|
||||
use nix::unistd::ForkResult::*;
|
||||
|
||||
require_capability!("test_ptrace_syscall", 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::traceme().unwrap();
|
||||
// first sigstop until parent is ready to continue
|
||||
let pid = getpid();
|
||||
kill(pid, Signal::SIGSTOP).unwrap();
|
||||
kill(pid, Signal::SIGTERM).unwrap();
|
||||
unsafe { ::libc::_exit(0); }
|
||||
},
|
||||
|
||||
Parent { child } => {
|
||||
assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGSTOP)));
|
||||
|
||||
// set this option to recognize syscall-stops
|
||||
ptrace::setoptions(child, ptrace::Options::PTRACE_O_TRACESYSGOOD).unwrap();
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let get_syscall_id = || ptrace::getregs(child).unwrap().orig_rax as libc::c_long;
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
let get_syscall_id = || ptrace::getregs(child).unwrap().orig_eax as libc::c_long;
|
||||
|
||||
// kill entry
|
||||
ptrace::syscall(child, None).unwrap();
|
||||
assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
|
||||
assert_eq!(get_syscall_id(), ::libc::SYS_kill);
|
||||
|
||||
// kill exit
|
||||
ptrace::syscall(child, None).unwrap();
|
||||
assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
|
||||
assert_eq!(get_syscall_id(), ::libc::SYS_kill);
|
||||
|
||||
// receive signal
|
||||
ptrace::syscall(child, None).unwrap();
|
||||
assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTERM)));
|
||||
|
||||
// inject signal
|
||||
ptrace::syscall(child, Signal::SIGTERM).unwrap();
|
||||
assert_eq!(waitpid(child, None), Ok(WaitStatus::Signaled(child, Signal::SIGTERM, false)));
|
||||
},
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
use nix::sys::select::*;
|
||||
use nix::unistd::{pipe, write};
|
||||
use nix::sys::signal::SigSet;
|
||||
use nix::sys::time::{TimeSpec, TimeValLike};
|
||||
|
||||
#[test]
|
||||
pub fn test_pselect() {
|
||||
let _mtx = crate::SIGNAL_MTX
|
||||
.lock()
|
||||
.expect("Mutex got poisoned by another test");
|
||||
|
||||
let (r1, w1) = pipe().unwrap();
|
||||
write(w1, b"hi!").unwrap();
|
||||
let (r2, _w2) = pipe().unwrap();
|
||||
|
||||
let mut fd_set = FdSet::new();
|
||||
fd_set.insert(r1);
|
||||
fd_set.insert(r2);
|
||||
|
||||
let timeout = TimeSpec::seconds(10);
|
||||
let sigmask = SigSet::empty();
|
||||
assert_eq!(
|
||||
1,
|
||||
pselect(None, &mut fd_set, None, None, &timeout, &sigmask).unwrap()
|
||||
);
|
||||
assert!(fd_set.contains(r1));
|
||||
assert!(!fd_set.contains(r2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_pselect_nfds2() {
|
||||
let (r1, w1) = pipe().unwrap();
|
||||
write(w1, b"hi!").unwrap();
|
||||
let (r2, _w2) = pipe().unwrap();
|
||||
|
||||
let mut fd_set = FdSet::new();
|
||||
fd_set.insert(r1);
|
||||
fd_set.insert(r2);
|
||||
|
||||
let timeout = TimeSpec::seconds(10);
|
||||
assert_eq!(
|
||||
1,
|
||||
pselect(
|
||||
::std::cmp::max(r1, r2) + 1,
|
||||
&mut fd_set,
|
||||
None,
|
||||
None,
|
||||
&timeout,
|
||||
None
|
||||
).unwrap()
|
||||
);
|
||||
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,
|
||||
);
|
||||
}
|
121
vendor/nix-v0.23.1-patched/test/sys/test_signal.rs
vendored
121
vendor/nix-v0.23.1-patched/test/sys/test_signal.rs
vendored
|
@ -1,121 +0,0 @@
|
|||
#[cfg(not(target_os = "redox"))]
|
||||
use nix::errno::Errno;
|
||||
use nix::sys::signal::*;
|
||||
use nix::unistd::*;
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
#[test]
|
||||
fn test_kill_none() {
|
||||
kill(getpid(), None).expect("Should be able to send signal to myself.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_os = "fuchsia"))]
|
||||
fn test_killpg_none() {
|
||||
killpg(getpgrp(), None)
|
||||
.expect("Should be able to send signal to my process group.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_old_sigaction_flags() {
|
||||
let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
|
||||
|
||||
extern "C" fn handler(_: ::libc::c_int) {}
|
||||
let act = SigAction::new(
|
||||
SigHandler::Handler(handler),
|
||||
SaFlags::empty(),
|
||||
SigSet::empty(),
|
||||
);
|
||||
let oact = unsafe { sigaction(SIGINT, &act) }.unwrap();
|
||||
let _flags = oact.flags();
|
||||
let oact = unsafe { sigaction(SIGINT, &act) }.unwrap();
|
||||
let _flags = oact.flags();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sigprocmask_noop() {
|
||||
sigprocmask(SigmaskHow::SIG_BLOCK, None, None)
|
||||
.expect("this should be an effective noop");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sigprocmask() {
|
||||
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;
|
||||
|
||||
let mut old_signal_set = SigSet::empty();
|
||||
sigprocmask(SigmaskHow::SIG_BLOCK, None, Some(&mut old_signal_set))
|
||||
.expect("expect to be able to retrieve old signals");
|
||||
|
||||
// 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);
|
||||
|
||||
// Now block the signal.
|
||||
let mut signal_set = SigSet::empty();
|
||||
signal_set.add(SIGNAL);
|
||||
sigprocmask(SigmaskHow::SIG_BLOCK, Some(&signal_set), None)
|
||||
.expect("expect to be able to block signals");
|
||||
|
||||
// And test it again, to make sure the change was effective.
|
||||
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);
|
||||
|
||||
// Reset the signal.
|
||||
sigprocmask(SigmaskHow::SIG_UNBLOCK, Some(&signal_set), None)
|
||||
.expect("expect to be able to block signals");
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref SIGNALED: AtomicBool = AtomicBool::new(false);
|
||||
}
|
||||
|
||||
extern fn test_sigaction_handler(signal: libc::c_int) {
|
||||
let signal = Signal::try_from(signal).unwrap();
|
||||
SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
extern fn test_sigaction_action(_: libc::c_int, _: *mut libc::siginfo_t, _: *mut libc::c_void) {}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
fn test_signal_sigaction() {
|
||||
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);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_signal() {
|
||||
let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
|
||||
|
||||
unsafe { signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap();
|
||||
raise(Signal::SIGINT).unwrap();
|
||||
assert_eq!(unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), SigHandler::SigIgn);
|
||||
|
||||
let handler = SigHandler::Handler(test_sigaction_handler);
|
||||
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();
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
use std::convert::TryFrom;
|
||||
|
||||
#[test]
|
||||
fn test_signalfd() {
|
||||
use nix::sys::signalfd::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().expect("Mutex got poisoned by another test");
|
||||
|
||||
// Block the SIGUSR1 signal from automatic processing for this thread
|
||||
let mut mask = SigSet::empty();
|
||||
mask.add(signal::SIGUSR1);
|
||||
mask.thread_block().unwrap();
|
||||
|
||||
let mut fd = SignalFd::new(&mask).unwrap();
|
||||
|
||||
// Send a SIGUSR1 signal to the current process. Note that this uses `raise` instead of `kill`
|
||||
// because `kill` with `getpid` isn't correct during multi-threaded execution like during a
|
||||
// cargo test session. Instead use `raise` which does the correct thing by default.
|
||||
raise(signal::SIGUSR1).expect("Error: raise(SIGUSR1) failed");
|
||||
|
||||
// And now catch that same signal.
|
||||
let res = fd.read_signal().unwrap().unwrap();
|
||||
let signo = Signal::try_from(res.ssi_signo as i32).unwrap();
|
||||
assert_eq!(signo, signal::SIGUSR1);
|
||||
}
|
1941
vendor/nix-v0.23.1-patched/test/sys/test_socket.rs
vendored
1941
vendor/nix-v0.23.1-patched/test/sys/test_socket.rs
vendored
File diff suppressed because it is too large
Load diff
199
vendor/nix-v0.23.1-patched/test/sys/test_sockopt.rs
vendored
199
vendor/nix-v0.23.1-patched/test/sys/test_sockopt.rs
vendored
|
@ -1,199 +0,0 @@
|
|||
use rand::{thread_rng, Rng};
|
||||
use nix::sys::socket::{socket, sockopt, getsockopt, setsockopt, AddressFamily, SockType, SockFlag, SockProtocol};
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
use crate::*;
|
||||
|
||||
// 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);
|
||||
|
||||
let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
|
||||
setsockopt(s, sockopt::Mark, &1337).unwrap();
|
||||
let mark = getsockopt(s, sockopt::Mark).unwrap();
|
||||
assert_eq!(mark, 1337);
|
||||
}
|
||||
|
||||
#[test]
|
||||
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);
|
||||
setsockopt(fd, sockopt::SndBuf, &bufsize).unwrap();
|
||||
let actual = getsockopt(fd, sockopt::SndBuf).unwrap();
|
||||
assert!(actual >= bufsize);
|
||||
setsockopt(fd, sockopt::RcvBuf, &bufsize).unwrap();
|
||||
let actual = getsockopt(fd, sockopt::RcvBuf).unwrap();
|
||||
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.
|
||||
// So the syscall doesn't work properly unless the kernel is also emulated.
|
||||
#[test]
|
||||
#[cfg(all(
|
||||
any(target_arch = "x86", target_arch = "x86_64"),
|
||||
any(target_os = "freebsd", target_os = "linux")
|
||||
))]
|
||||
fn test_tcp_congestion() {
|
||||
use std::ffi::OsString;
|
||||
|
||||
let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
|
||||
|
||||
let val = getsockopt(fd, sockopt::TcpCongestion).unwrap();
|
||||
setsockopt(fd, sockopt::TcpCongestion, &val).unwrap();
|
||||
|
||||
setsockopt(fd, sockopt::TcpCongestion, &OsString::from("tcp_congestion_does_not_exist")).unwrap_err();
|
||||
|
||||
assert_eq!(
|
||||
getsockopt(fd, sockopt::TcpCongestion).unwrap(),
|
||||
val
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
fn test_bindtodevice() {
|
||||
skip_if_not_root!("test_bindtodevice");
|
||||
|
||||
let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
|
||||
|
||||
let val = getsockopt(fd, sockopt::BindToDevice).unwrap();
|
||||
setsockopt(fd, sockopt::BindToDevice, &val).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
getsockopt(fd, sockopt::BindToDevice).unwrap(),
|
||||
val
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
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());
|
||||
|
||||
#[cfg(any(target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux",
|
||||
target_os = "nacl"))] {
|
||||
let x = getsockopt(fd, sockopt::TcpKeepIdle).unwrap();
|
||||
setsockopt(fd, sockopt::TcpKeepIdle, &(x + 1)).unwrap();
|
||||
assert_eq!(getsockopt(fd, sockopt::TcpKeepIdle).unwrap(), x + 1);
|
||||
|
||||
let x = getsockopt(fd, sockopt::TcpKeepCount).unwrap();
|
||||
setsockopt(fd, sockopt::TcpKeepCount, &(x + 1)).unwrap();
|
||||
assert_eq!(getsockopt(fd, sockopt::TcpKeepCount).unwrap(), x + 1);
|
||||
|
||||
let x = getsockopt(fd, sockopt::TcpKeepInterval).unwrap();
|
||||
setsockopt(fd, sockopt::TcpKeepInterval, &(x + 1)).unwrap();
|
||||
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");
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
use nix::sys::sysinfo::*;
|
||||
|
||||
#[test]
|
||||
fn sysinfo_works() {
|
||||
let info = sysinfo().unwrap();
|
||||
|
||||
let (l1, l5, l15) = info.load_average();
|
||||
assert!(l1 >= 0.0);
|
||||
assert!(l5 >= 0.0);
|
||||
assert!(l15 >= 0.0);
|
||||
|
||||
info.uptime(); // just test Duration construction
|
||||
|
||||
assert!(info.swap_free() <= info.swap_total(),
|
||||
"more swap available than installed (free: {}, total: {})",
|
||||
info.swap_free(),
|
||||
info.swap_total());
|
||||
}
|
130
vendor/nix-v0.23.1-patched/test/sys/test_termios.rs
vendored
130
vendor/nix-v0.23.1-patched/test/sys/test_termios.rs
vendored
|
@ -1,130 +0,0 @@
|
|||
use std::os::unix::prelude::*;
|
||||
use tempfile::tempfile;
|
||||
|
||||
use nix::fcntl;
|
||||
use nix::errno::Errno;
|
||||
use nix::pty::openpty;
|
||||
use nix::sys::termios::{self, LocalFlags, OutputFlags, tcgetattr};
|
||||
use nix::unistd::{read, write, close};
|
||||
|
||||
/// Helper function analogous to `std::io::Write::write_all`, but for `RawFd`s
|
||||
fn write_all(f: RawFd, buf: &[u8]) {
|
||||
let mut len = 0;
|
||||
while len < buf.len() {
|
||||
len += write(f, &buf[len..]).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// Test tcgetattr on a terminal
|
||||
#[test]
|
||||
fn test_tcgetattr_pty() {
|
||||
// openpty uses ptname(3) internally
|
||||
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());
|
||||
close(pty.master).expect("closing the master failed");
|
||||
close(pty.slave).expect("closing the slave failed");
|
||||
}
|
||||
|
||||
// Test tcgetattr on something that isn't a terminal
|
||||
#[test]
|
||||
fn test_tcgetattr_enotty() {
|
||||
let file = tempfile().unwrap();
|
||||
assert_eq!(termios::tcgetattr(file.as_raw_fd()).err(),
|
||||
Some(Errno::ENOTTY));
|
||||
}
|
||||
|
||||
// Test tcgetattr on an invalid file descriptor
|
||||
#[test]
|
||||
fn test_tcgetattr_ebadf() {
|
||||
assert_eq!(termios::tcgetattr(-1).err(),
|
||||
Some(Errno::EBADF));
|
||||
}
|
||||
|
||||
// Test modifying output flags
|
||||
#[test]
|
||||
fn test_output_flags() {
|
||||
// openpty uses ptname(3) internally
|
||||
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 = {
|
||||
let pty = openpty(None, None).expect("openpty failed");
|
||||
assert!(pty.master > 0);
|
||||
assert!(pty.slave > 0);
|
||||
let termios = tcgetattr(pty.slave).expect("tcgetattr failed");
|
||||
close(pty.master).unwrap();
|
||||
close(pty.slave).unwrap();
|
||||
termios
|
||||
};
|
||||
|
||||
// Make sure postprocessing '\r' isn't specified by default or this test is useless.
|
||||
assert!(!termios.output_flags.contains(OutputFlags::OPOST | OutputFlags::OCRNL));
|
||||
|
||||
// Specify that '\r' characters should be transformed to '\n'
|
||||
// OPOST is specified to enable post-processing
|
||||
termios.output_flags.insert(OutputFlags::OPOST | OutputFlags::OCRNL);
|
||||
|
||||
// Open a pty
|
||||
let pty = openpty(None, &termios).unwrap();
|
||||
assert!(pty.master > 0);
|
||||
assert!(pty.slave > 0);
|
||||
|
||||
// Write into the master
|
||||
let string = "foofoofoo\r";
|
||||
write_all(pty.master, string.as_bytes());
|
||||
|
||||
// Read from the slave verifying that the output has been properly transformed
|
||||
let mut buf = [0u8; 10];
|
||||
crate::read_exact(pty.slave, &mut buf);
|
||||
let transformed_string = "foofoofoo\n";
|
||||
close(pty.master).unwrap();
|
||||
close(pty.slave).unwrap();
|
||||
assert_eq!(&buf, transformed_string.as_bytes());
|
||||
}
|
||||
|
||||
// Test modifying local flags
|
||||
#[test]
|
||||
fn test_local_flags() {
|
||||
// openpty uses ptname(3) internally
|
||||
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 = {
|
||||
let pty = openpty(None, None).unwrap();
|
||||
assert!(pty.master > 0);
|
||||
assert!(pty.slave > 0);
|
||||
let termios = tcgetattr(pty.slave).unwrap();
|
||||
close(pty.master).unwrap();
|
||||
close(pty.slave).unwrap();
|
||||
termios
|
||||
};
|
||||
|
||||
// Make sure echo is specified by default or this test is useless.
|
||||
assert!(termios.local_flags.contains(LocalFlags::ECHO));
|
||||
|
||||
// Disable local echo
|
||||
termios.local_flags.remove(LocalFlags::ECHO);
|
||||
|
||||
// Open a new pty with our modified termios settings
|
||||
let pty = openpty(None, &termios).unwrap();
|
||||
assert!(pty.master > 0);
|
||||
assert!(pty.slave > 0);
|
||||
|
||||
// Set the master is in nonblocking mode or reading will never return.
|
||||
let flags = fcntl::fcntl(pty.master, fcntl::F_GETFL).unwrap();
|
||||
let new_flags = fcntl::OFlag::from_bits_truncate(flags) | fcntl::OFlag::O_NONBLOCK;
|
||||
fcntl::fcntl(pty.master, fcntl::F_SETFL(new_flags)).unwrap();
|
||||
|
||||
// Write into the master
|
||||
let string = "foofoofoo\r";
|
||||
write_all(pty.master, string.as_bytes());
|
||||
|
||||
// Try to read from the master, which should not have anything as echoing was disabled.
|
||||
let mut buf = [0u8; 10];
|
||||
let read = read(pty.master, &mut buf).unwrap_err();
|
||||
close(pty.master).unwrap();
|
||||
close(pty.slave).unwrap();
|
||||
assert_eq!(read, Errno::EAGAIN);
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
use nix::sys::time::{TimeSpec, TimeValLike};
|
||||
use nix::sys::timerfd::{ClockId, Expiration, TimerFd, TimerFlags, TimerSetTimeFlags};
|
||||
use std::time::Instant;
|
||||
|
||||
#[test]
|
||||
pub fn test_timerfd_oneshot() {
|
||||
let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap();
|
||||
|
||||
let before = Instant::now();
|
||||
|
||||
timer
|
||||
.set(
|
||||
Expiration::OneShot(TimeSpec::seconds(1)),
|
||||
TimerSetTimeFlags::empty(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
timer.wait().unwrap();
|
||||
|
||||
let millis = before.elapsed().as_millis();
|
||||
assert!(millis > 900);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_timerfd_interval() {
|
||||
let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap();
|
||||
|
||||
let before = Instant::now();
|
||||
timer
|
||||
.set(
|
||||
Expiration::IntervalDelayed(TimeSpec::seconds(1), TimeSpec::seconds(2)),
|
||||
TimerSetTimeFlags::empty(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
timer.wait().unwrap();
|
||||
|
||||
let start_delay = before.elapsed().as_millis();
|
||||
assert!(start_delay > 900);
|
||||
|
||||
timer.wait().unwrap();
|
||||
|
||||
let interval_delay = before.elapsed().as_millis();
|
||||
assert!(interval_delay > 2900);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_timerfd_unset() {
|
||||
let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap();
|
||||
|
||||
timer
|
||||
.set(
|
||||
Expiration::OneShot(TimeSpec::seconds(1)),
|
||||
TimerSetTimeFlags::empty(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
timer.unset().unwrap();
|
||||
|
||||
assert!(timer.get().unwrap() == None);
|
||||
}
|
255
vendor/nix-v0.23.1-patched/test/sys/test_uio.rs
vendored
255
vendor/nix-v0.23.1-patched/test/sys/test_uio.rs
vendored
|
@ -1,255 +0,0 @@
|
|||
use nix::sys::uio::*;
|
||||
use nix::unistd::*;
|
||||
use rand::{thread_rng, Rng};
|
||||
use rand::distributions::Alphanumeric;
|
||||
use std::{cmp, iter};
|
||||
use std::fs::{OpenOptions};
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use tempfile::tempfile;
|
||||
use tempfile::tempdir;
|
||||
|
||||
#[test]
|
||||
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 b = s.as_bytes();
|
||||
to_write.extend(b.iter().cloned());
|
||||
}
|
||||
// Allocate and fill iovecs
|
||||
let mut iovecs = Vec::new();
|
||||
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 b = &to_write[consumed..consumed+slice_len];
|
||||
iovecs.push(IoVec::from_slice(b));
|
||||
consumed += slice_len;
|
||||
}
|
||||
let pipe_res = pipe();
|
||||
assert!(pipe_res.is_ok());
|
||||
let (reader, writer) = pipe_res.ok().unwrap();
|
||||
// FileDesc will close its filedesc (reader).
|
||||
let mut read_buf: Vec<u8> = iter::repeat(0u8).take(128 * 16).collect();
|
||||
// Blocking io, should write all data.
|
||||
let write_res = writev(writer, &iovecs);
|
||||
// Successful write
|
||||
assert!(write_res.is_ok());
|
||||
let written = write_res.ok().unwrap();
|
||||
// Check whether we written all data
|
||||
assert_eq!(to_write.len(), written);
|
||||
let read_res = read(reader, &mut read_buf[..]);
|
||||
// Successful read
|
||||
assert!(read_res.is_ok());
|
||||
let read = read_res.ok().unwrap() as usize;
|
||||
// Check we have read as much as we written
|
||||
assert_eq!(read, written);
|
||||
// Check equality of written and read data
|
||||
assert_eq!(&to_write, &read_buf);
|
||||
let close_res = close(writer);
|
||||
assert!(close_res.is_ok());
|
||||
let close_res = close(reader);
|
||||
assert!(close_res.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
fn test_readv() {
|
||||
let s:String = thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.map(char::from)
|
||||
.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 v: Vec<u8> = iter::repeat(0u8).take(vec_len).collect();
|
||||
storage.push(v);
|
||||
allocated += vec_len;
|
||||
}
|
||||
let mut iovecs = Vec::with_capacity(storage.len());
|
||||
for v in &mut storage {
|
||||
iovecs.push(IoVec::from_mut_slice(&mut v[..]));
|
||||
}
|
||||
let pipe_res = pipe();
|
||||
assert!(pipe_res.is_ok());
|
||||
let (reader, writer) = pipe_res.ok().unwrap();
|
||||
// Blocking io, should write all data.
|
||||
let write_res = write(writer, &to_write);
|
||||
// Successful write
|
||||
assert!(write_res.is_ok());
|
||||
let read_res = readv(reader, &mut iovecs[..]);
|
||||
assert!(read_res.is_ok());
|
||||
let read = read_res.ok().unwrap();
|
||||
// Check whether we've read all data
|
||||
assert_eq!(to_write.len(), read);
|
||||
// Cccumulate data from iovecs
|
||||
let mut read_buf = Vec::with_capacity(to_write.len());
|
||||
for iovec in &iovecs {
|
||||
read_buf.extend(iovec.as_slice().iter().cloned());
|
||||
}
|
||||
// Check whether iovecs contain all written data
|
||||
assert_eq!(read_buf.len(), to_write.len());
|
||||
// Check equality of written and read data
|
||||
assert_eq!(&read_buf, &to_write);
|
||||
let close_res = close(reader);
|
||||
assert!(close_res.is_ok());
|
||||
let close_res = close(writer);
|
||||
assert!(close_res.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
fn test_pwrite() {
|
||||
use std::io::Read;
|
||||
|
||||
let mut file = tempfile().unwrap();
|
||||
let buf = [1u8;8];
|
||||
assert_eq!(Ok(8), pwrite(file.as_raw_fd(), &buf, 8));
|
||||
let mut file_content = Vec::new();
|
||||
file.read_to_end(&mut file_content).unwrap();
|
||||
let mut expected = vec![0u8;8];
|
||||
expected.extend(vec![1;8]);
|
||||
assert_eq!(file_content, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pread() {
|
||||
use std::io::Write;
|
||||
|
||||
let tempdir = tempdir().unwrap();
|
||||
|
||||
let path = tempdir.path().join("pread_test_file");
|
||||
let mut file = OpenOptions::new().write(true).read(true).create(true)
|
||||
.truncate(true).open(path).unwrap();
|
||||
let file_content: Vec<u8> = (0..64).collect();
|
||||
file.write_all(&file_content).unwrap();
|
||||
|
||||
let mut buf = [0u8;16];
|
||||
assert_eq!(Ok(16), pread(file.as_raw_fd(), &mut buf, 16));
|
||||
let expected: Vec<_> = (16..32).collect();
|
||||
assert_eq!(&buf[..], &expected[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(any(target_os = "macos", target_os = "redox")))]
|
||||
fn test_pwritev() {
|
||||
use std::io::Read;
|
||||
|
||||
let to_write: Vec<u8> = (0..128).collect();
|
||||
let expected: Vec<u8> = [vec![0;100], to_write.clone()].concat();
|
||||
|
||||
let iovecs = [
|
||||
IoVec::from_slice(&to_write[0..17]),
|
||||
IoVec::from_slice(&to_write[17..64]),
|
||||
IoVec::from_slice(&to_write[64..128]),
|
||||
];
|
||||
|
||||
let tempdir = tempdir().unwrap();
|
||||
|
||||
// pwritev them into a temporary file
|
||||
let path = tempdir.path().join("pwritev_test_file");
|
||||
let mut file = OpenOptions::new().write(true).read(true).create(true)
|
||||
.truncate(true).open(path).unwrap();
|
||||
|
||||
let written = pwritev(file.as_raw_fd(), &iovecs, 100).ok().unwrap();
|
||||
assert_eq!(written, to_write.len());
|
||||
|
||||
// Read the data back and make sure it matches
|
||||
let mut contents = Vec::new();
|
||||
file.read_to_end(&mut contents).unwrap();
|
||||
assert_eq!(contents, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(any(target_os = "macos", target_os = "redox")))]
|
||||
fn test_preadv() {
|
||||
use std::io::Write;
|
||||
|
||||
let to_write: Vec<u8> = (0..200).collect();
|
||||
let expected: Vec<u8> = (100..200).collect();
|
||||
|
||||
let tempdir = tempdir().unwrap();
|
||||
|
||||
let path = tempdir.path().join("preadv_test_file");
|
||||
|
||||
let mut file = OpenOptions::new().read(true).write(true).create(true)
|
||||
.truncate(true).open(path).unwrap();
|
||||
file.write_all(&to_write).unwrap();
|
||||
|
||||
let mut buffers: Vec<Vec<u8>> = vec![
|
||||
vec![0; 24],
|
||||
vec![0; 1],
|
||||
vec![0; 75],
|
||||
];
|
||||
|
||||
{
|
||||
// Borrow the buffers into IoVecs and preadv into them
|
||||
let iovecs: Vec<_> = buffers.iter_mut().map(
|
||||
|buf| IoVec::from_mut_slice(&mut buf[..])).collect();
|
||||
assert_eq!(Ok(100), preadv(file.as_raw_fd(), &iovecs, 100));
|
||||
}
|
||||
|
||||
let all = buffers.concat();
|
||||
assert_eq!(all, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
// qemu-user doesn't implement process_vm_readv/writev on most arches
|
||||
#[cfg_attr(qemu, 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().expect("Mutex got poisoned by another test");
|
||||
|
||||
// Pre-allocate memory in the child, since allocation isn't safe
|
||||
// post-fork (~= async-signal-safe)
|
||||
let mut vector = vec![1u8, 2, 3, 4, 5];
|
||||
|
||||
let (r, w) = pipe().unwrap();
|
||||
match unsafe{fork()}.expect("Error: Fork Failed") {
|
||||
Parent { child } => {
|
||||
close(w).unwrap();
|
||||
// wait for child
|
||||
read(r, &mut [0u8]).unwrap();
|
||||
close(r).unwrap();
|
||||
|
||||
let ptr = vector.as_ptr() as usize;
|
||||
let remote_iov = RemoteIoVec { base: ptr, len: 5 };
|
||||
let mut buf = vec![0u8; 5];
|
||||
|
||||
let ret = process_vm_readv(child,
|
||||
&[IoVec::from_mut_slice(&mut buf)],
|
||||
&[remote_iov]);
|
||||
|
||||
kill(child, SIGTERM).unwrap();
|
||||
waitpid(child, None).unwrap();
|
||||
|
||||
assert_eq!(Ok(5), ret);
|
||||
assert_eq!(20u8, buf.iter().sum());
|
||||
},
|
||||
Child => {
|
||||
let _ = close(r);
|
||||
for i in &mut vector {
|
||||
*i += 1;
|
||||
}
|
||||
let _ = write(w, b"\0");
|
||||
let _ = close(w);
|
||||
loop { let _ = pause(); }
|
||||
},
|
||||
}
|
||||
}
|
107
vendor/nix-v0.23.1-patched/test/sys/test_wait.rs
vendored
107
vendor/nix-v0.23.1-patched/test/sys/test_wait.rs
vendored
|
@ -1,107 +0,0 @@
|
|||
use nix::errno::Errno;
|
||||
use nix::unistd::*;
|
||||
use nix::unistd::ForkResult::*;
|
||||
use nix::sys::signal::*;
|
||||
use nix::sys::wait::*;
|
||||
use libc::_exit;
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
fn test_wait_signal() {
|
||||
let _m = 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") {
|
||||
Child => {
|
||||
pause();
|
||||
unsafe { _exit(123) }
|
||||
},
|
||||
Parent { child } => {
|
||||
kill(child, Some(SIGKILL)).expect("Error: Kill Failed");
|
||||
assert_eq!(waitpid(child, None), Ok(WaitStatus::Signaled(child, SIGKILL, false)));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wait_exit() {
|
||||
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") {
|
||||
Child => unsafe { _exit(12); },
|
||||
Parent { child } => {
|
||||
assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 12)));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
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));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_waitstatus_pid() {
|
||||
let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
|
||||
|
||||
match unsafe{fork()}.unwrap() {
|
||||
Child => unsafe { _exit(0) },
|
||||
Parent { child } => {
|
||||
let status = waitpid(child, None).unwrap();
|
||||
assert_eq!(status.pid(), Some(child));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
// FIXME: qemu-user doesn't implement ptrace on most arches
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
mod ptrace {
|
||||
use nix::sys::ptrace::{self, Options, Event};
|
||||
use nix::sys::signal::*;
|
||||
use nix::sys::wait::*;
|
||||
use nix::unistd::*;
|
||||
use nix::unistd::ForkResult::*;
|
||||
use libc::_exit;
|
||||
use crate::*;
|
||||
|
||||
fn ptrace_child() -> ! {
|
||||
ptrace::traceme().unwrap();
|
||||
// As recommended by ptrace(2), raise SIGTRAP to pause the child
|
||||
// until the parent is ready to continue
|
||||
raise(SIGTRAP).unwrap();
|
||||
unsafe { _exit(0) }
|
||||
}
|
||||
|
||||
fn ptrace_parent(child: Pid) {
|
||||
// Wait for the raised SIGTRAP
|
||||
assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, SIGTRAP)));
|
||||
// We want to test a syscall stop and a PTRACE_EVENT stop
|
||||
assert!(ptrace::setoptions(child, Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT).is_ok());
|
||||
|
||||
// First, stop on the next system call, which will be exit()
|
||||
assert!(ptrace::syscall(child, None).is_ok());
|
||||
assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
|
||||
// Then get the ptrace event for the process exiting
|
||||
assert!(ptrace::cont(child, None).is_ok());
|
||||
assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceEvent(child, SIGTRAP, Event::PTRACE_EVENT_EXIT as i32)));
|
||||
// Finally get the normal wait() result, now that the process has exited
|
||||
assert!(ptrace::cont(child, None).is_ok());
|
||||
assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wait_ptrace() {
|
||||
require_capability!("test_wait_ptrace", 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(),
|
||||
Parent { child } => ptrace_parent(child),
|
||||
}
|
||||
}
|
||||
}
|
103
vendor/nix-v0.23.1-patched/test/test.rs
vendored
103
vendor/nix-v0.23.1-patched/test/test.rs
vendored
|
@ -1,103 +0,0 @@
|
|||
#[macro_use]
|
||||
extern crate cfg_if;
|
||||
#[cfg_attr(not(target_os = "redox"), macro_use)]
|
||||
extern crate nix;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
mod common;
|
||||
mod sys;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
mod test_dir;
|
||||
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",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd"))]
|
||||
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;
|
||||
#[cfg(any(target_os = "android",
|
||||
target_os = "linux"))]
|
||||
mod test_sched;
|
||||
#[cfg(any(target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
mod test_sendfile;
|
||||
mod test_stat;
|
||||
mod test_time;
|
||||
mod test_unistd;
|
||||
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::{Mutex, RwLock, RwLockWriteGuard};
|
||||
use nix::unistd::{chdir, getcwd, read};
|
||||
|
||||
|
||||
/// Helper function analogous to `std::io::Read::read_exact`, but for `RawFD`s
|
||||
fn read_exact(f: RawFd, buf: &mut [u8]) {
|
||||
let mut len = 0;
|
||||
while len < buf.len() {
|
||||
// get_mut would be better than split_at_mut, but it requires nightly
|
||||
let (_, remaining) = buf.split_at_mut(len);
|
||||
len += read(f, remaining).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// Any test that changes the process's current working directory must grab
|
||||
/// the RwLock exclusively. Any process that cares about the current
|
||||
/// working directory must grab it shared.
|
||||
pub static ref CWD_LOCK: RwLock<()> = RwLock::new(());
|
||||
/// Any test that creates child processes must grab this mutex, regardless
|
||||
/// of what it does with those children.
|
||||
pub static ref FORK_MTX: Mutex<()> = Mutex::new(());
|
||||
/// Any test that changes the process's supplementary groups must grab this
|
||||
/// mutex
|
||||
pub static ref GROUPS_MTX: Mutex<()> = Mutex::new(());
|
||||
/// Any tests that loads or unloads kernel modules must grab this mutex
|
||||
pub static ref KMOD_MTX: Mutex<()> = Mutex::new(());
|
||||
/// Any test that calls ptsname(3) must grab this mutex.
|
||||
pub static ref PTSNAME_MTX: Mutex<()> = Mutex::new(());
|
||||
/// Any test that alters signal handling must grab this mutex.
|
||||
pub static ref SIGNAL_MTX: Mutex<()> = Mutex::new(());
|
||||
}
|
||||
|
||||
/// RAII object that restores a test's original directory on drop
|
||||
struct DirRestore<'a> {
|
||||
d: PathBuf,
|
||||
_g: RwLockWriteGuard<'a, ()>
|
||||
}
|
||||
|
||||
impl<'a> DirRestore<'a> {
|
||||
fn new() -> Self {
|
||||
let guard = crate::CWD_LOCK.write()
|
||||
.expect("Lock got poisoned by another test");
|
||||
DirRestore{
|
||||
_g: guard,
|
||||
d: getcwd().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for DirRestore<'a> {
|
||||
fn drop(&mut self) {
|
||||
let r = chdir(&self.d);
|
||||
if std::thread::panicking() {
|
||||
r.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
use std::env;
|
||||
|
||||
#[test]
|
||||
fn clearenv() {
|
||||
env::set_var("FOO", "BAR");
|
||||
unsafe { nix::env::clearenv() }.unwrap();
|
||||
assert_eq!(env::var("FOO").unwrap_err(), env::VarError::NotPresent);
|
||||
assert_eq!(env::vars().count(), 0);
|
||||
}
|
56
vendor/nix-v0.23.1-patched/test/test_dir.rs
vendored
56
vendor/nix-v0.23.1-patched/test/test_dir.rs
vendored
|
@ -1,56 +0,0 @@
|
|||
use nix::dir::{Dir, Type};
|
||||
use nix::fcntl::OFlag;
|
||||
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 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
|
||||
.iter()
|
||||
.map(|e| e.file_name().to_str().unwrap().to_owned())
|
||||
.collect();
|
||||
assert_eq!(&entry_names[..], &[".", "..", "bar", "foo"]);
|
||||
|
||||
// Check file types. The system is allowed to return DT_UNKNOWN (aka None here) but if it does
|
||||
// return a type, ensure it's correct.
|
||||
assert!(&[Some(Type::Directory), None].contains(&entries[0].file_type())); // .: dir
|
||||
assert!(&[Some(Type::Directory), None].contains(&entries[1].file_type())); // ..: dir
|
||||
assert!(&[Some(Type::Symlink), None].contains(&entries[2].file_type())); // bar: symlink
|
||||
assert!(&[Some(Type::File), None].contains(&entries[3].file_type())); // foo: regular file
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rewind() {
|
||||
let tmp = tempdir().unwrap();
|
||||
let mut dir = Dir::open(tmp.path(), flags(), Mode::empty()).unwrap();
|
||||
let entries1: Vec<_> = dir.iter().map(|e| e.unwrap().file_name().to_owned()).collect();
|
||||
let entries2: Vec<_> = dir.iter().map(|e| e.unwrap().file_name().to_owned()).collect();
|
||||
let entries3: Vec<_> = dir.into_iter().map(|e| e.unwrap().file_name().to_owned()).collect();
|
||||
assert_eq!(entries1, entries2);
|
||||
assert_eq!(entries2, entries3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ebadf() {
|
||||
assert_eq!(Dir::from_fd(-1).unwrap_err(), nix::Error::EBADF);
|
||||
}
|
540
vendor/nix-v0.23.1-patched/test/test_fcntl.rs
vendored
540
vendor/nix-v0.23.1-patched/test/test_fcntl.rs
vendored
|
@ -1,540 +0,0 @@
|
|||
#[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"))]
|
||||
use nix::unistd::{close, read};
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use tempfile::{self, NamedTempFile};
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use std::fs::File;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use std::io::prelude::*;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use std::os::unix::fs;
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
fn test_openat() {
|
||||
const CONTENTS: &[u8] = b"abcd";
|
||||
let mut tmp = NamedTempFile::new().unwrap();
|
||||
tmp.write_all(CONTENTS).unwrap();
|
||||
|
||||
let dirfd = open(tmp.path().parent().unwrap(),
|
||||
OFlag::empty(),
|
||||
Mode::empty()).unwrap();
|
||||
let fd = openat(dirfd,
|
||||
tmp.path().file_name().unwrap(),
|
||||
OFlag::O_RDONLY,
|
||||
Mode::empty()).unwrap();
|
||||
|
||||
let mut buf = [0u8; 1024];
|
||||
assert_eq!(4, read(fd, &mut buf).unwrap());
|
||||
assert_eq!(CONTENTS, &buf[0..4]);
|
||||
|
||||
close(fd).unwrap();
|
||||
close(dirfd).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
fn test_renameat() {
|
||||
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();
|
||||
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
|
||||
);
|
||||
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();
|
||||
let src = tempdir.path().join("a");
|
||||
let dst = tempdir.path().join("b");
|
||||
println!("a: {:?}, b: {:?}", &src, &dst);
|
||||
fs::symlink(&src.as_path(), &dst.as_path()).unwrap();
|
||||
let dirfd = open(tempdir.path(),
|
||||
OFlag::empty(),
|
||||
Mode::empty()).unwrap();
|
||||
let expected_dir = src.to_str().unwrap();
|
||||
|
||||
assert_eq!(readlink(&dst).unwrap().to_str().unwrap(), expected_dir);
|
||||
assert_eq!(readlinkat(dirfd, "b").unwrap().to_str().unwrap(), expected_dir);
|
||||
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
mod linux_android {
|
||||
use std::io::prelude::*;
|
||||
use std::io::SeekFrom;
|
||||
use std::os::unix::prelude::*;
|
||||
use libc::loff_t;
|
||||
|
||||
use nix::fcntl::*;
|
||||
use nix::sys::uio::IoVec;
|
||||
use nix::unistd::{close, pipe, read, write};
|
||||
|
||||
use tempfile::tempfile;
|
||||
#[cfg(any(target_os = "linux"))]
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
use crate::*;
|
||||
|
||||
/// This test creates a temporary file containing the contents
|
||||
/// 'foobarbaz' and uses the `copy_file_range` call to transfer
|
||||
/// 3 bytes at offset 3 (`bar`) to another empty file at offset 0. The
|
||||
/// resulting file is read and should contain the contents `bar`.
|
||||
/// The from_offset should be updated by the call to reflect
|
||||
/// the 3 bytes read (6).
|
||||
#[test]
|
||||
// QEMU does not support copy_file_range. Skip under qemu
|
||||
#[cfg_attr(qemu, ignore)]
|
||||
fn test_copy_file_range() {
|
||||
const CONTENTS: &[u8] = b"foobarbaz";
|
||||
|
||||
let mut tmp1 = tempfile().unwrap();
|
||||
let mut tmp2 = tempfile().unwrap();
|
||||
|
||||
tmp1.write_all(CONTENTS).unwrap();
|
||||
tmp1.flush().unwrap();
|
||||
|
||||
let mut from_offset: i64 = 3;
|
||||
copy_file_range(
|
||||
tmp1.as_raw_fd(),
|
||||
Some(&mut from_offset),
|
||||
tmp2.as_raw_fd(),
|
||||
None,
|
||||
3,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut res: String = String::new();
|
||||
tmp2.seek(SeekFrom::Start(0)).unwrap();
|
||||
tmp2.read_to_string(&mut res).unwrap();
|
||||
|
||||
assert_eq!(res, String::from("bar"));
|
||||
assert_eq!(from_offset, 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_splice() {
|
||||
const CONTENTS: &[u8] = b"abcdef123456";
|
||||
let mut tmp = tempfile().unwrap();
|
||||
tmp.write_all(CONTENTS).unwrap();
|
||||
|
||||
let (rd, wr) = pipe().unwrap();
|
||||
let mut offset: loff_t = 5;
|
||||
let res = splice(tmp.as_raw_fd(), Some(&mut offset),
|
||||
wr, None, 2, SpliceFFlags::empty()).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();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tee() {
|
||||
let (rd1, wr1) = pipe().unwrap();
|
||||
let (rd2, wr2) = pipe().unwrap();
|
||||
|
||||
write(wr1, b"abc").unwrap();
|
||||
let res = tee(rd1, wr2, 2, SpliceFFlags::empty()).unwrap();
|
||||
|
||||
assert_eq!(2, res);
|
||||
|
||||
let mut buf = [0u8; 1024];
|
||||
|
||||
// Check the tee'd bytes are at rd2.
|
||||
assert_eq!(2, read(rd2, &mut buf).unwrap());
|
||||
assert_eq!(b"ab", &buf[0..2]);
|
||||
|
||||
// Check all the bytes are still at rd1.
|
||||
assert_eq!(3, read(rd1, &mut buf).unwrap());
|
||||
assert_eq!(b"abc", &buf[0..3]);
|
||||
|
||||
close(rd1).unwrap();
|
||||
close(wr1).unwrap();
|
||||
close(rd2).unwrap();
|
||||
close(wr2).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vmsplice() {
|
||||
let (rd, wr) = pipe().unwrap();
|
||||
|
||||
let buf1 = b"abcdef";
|
||||
let buf2 = b"defghi";
|
||||
let iovecs = vec![
|
||||
IoVec::from_slice(&buf1[0..3]),
|
||||
IoVec::from_slice(&buf2[0..3])
|
||||
];
|
||||
|
||||
let res = vmsplice(wr, &iovecs[..], SpliceFFlags::empty()).unwrap();
|
||||
|
||||
assert_eq!(6, res);
|
||||
|
||||
// Check the bytes can be read at rd.
|
||||
let mut buf = [0u8; 32];
|
||||
assert_eq!(6, read(rd, &mut buf).unwrap());
|
||||
assert_eq!(b"abcdef", &buf[0..6]);
|
||||
|
||||
close(rd).unwrap();
|
||||
close(wr).unwrap();
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux"))]
|
||||
#[test]
|
||||
fn test_fallocate() {
|
||||
let tmp = NamedTempFile::new().unwrap();
|
||||
|
||||
let fd = tmp.as_raw_fd();
|
||||
fallocate(fd, FallocateFlags::empty(), 0, 100).unwrap();
|
||||
|
||||
// Check if we read exactly 100 bytes
|
||||
let mut buf = [0u8; 200];
|
||||
assert_eq!(100, read(fd, &mut buf).unwrap());
|
||||
}
|
||||
|
||||
// The tests below are disabled for the listed targets
|
||||
// due to OFD locks not being available in the kernel/libc
|
||||
// versions used in the CI environment, probably because
|
||||
// they run under QEMU.
|
||||
|
||||
#[test]
|
||||
#[cfg(all(target_os = "linux", not(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();
|
||||
let statfs = nix::sys::statfs::fstatfs(&tmp).unwrap();
|
||||
if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC {
|
||||
// OverlayFS is a union file system. It returns one inode value in
|
||||
// stat(2), but a different one shows up in /proc/locks. So we must
|
||||
// skip the test.
|
||||
skip!("/proc/locks does not work on overlayfs");
|
||||
}
|
||||
let inode = fstat(fd).expect("fstat failed").st_ino as usize;
|
||||
|
||||
let mut flock: libc::flock = unsafe {
|
||||
mem::zeroed() // required for Linux/mips
|
||||
};
|
||||
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())),
|
||||
lock_info(inode)
|
||||
);
|
||||
|
||||
flock.l_type = libc::F_UNLCK as libc::c_short;
|
||||
fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("write unlock failed");
|
||||
assert_eq!(None, lock_info(inode));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(target_os = "linux", not(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();
|
||||
let statfs = nix::sys::statfs::fstatfs(&tmp).unwrap();
|
||||
if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC {
|
||||
// OverlayFS is a union file system. It returns one inode value in
|
||||
// stat(2), but a different one shows up in /proc/locks. So we must
|
||||
// skip the test.
|
||||
skip!("/proc/locks does not work on overlayfs");
|
||||
}
|
||||
let inode = fstat(fd).expect("fstat failed").st_ino as usize;
|
||||
|
||||
let mut flock: libc::flock = unsafe {
|
||||
mem::zeroed() // required for Linux/mips
|
||||
};
|
||||
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())),
|
||||
lock_info(inode)
|
||||
);
|
||||
|
||||
flock.l_type = libc::F_UNLCK as libc::c_short;
|
||||
fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("read unlock failed");
|
||||
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);
|
||||
|
||||
for line in buf.lines() {
|
||||
let line = line.unwrap();
|
||||
let parts: Vec<_> = line.split_whitespace().collect();
|
||||
let lock_type = parts[1];
|
||||
let lock_access = parts[3];
|
||||
let ino_parts: Vec<_> = parts[5].split(':').collect();
|
||||
let ino: usize = ino_parts[2].parse().unwrap();
|
||||
if ino == inode {
|
||||
return Some((lock_type.to_string(), lock_access.to_string()));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
any(target_os = "wasi", target_env = "wasi"),
|
||||
target_env = "uclibc",
|
||||
target_os = "freebsd"))]
|
||||
mod test_posix_fadvise {
|
||||
|
||||
use tempfile::NamedTempFile;
|
||||
use std::os::unix::io::{RawFd, AsRawFd};
|
||||
use nix::errno::Errno;
|
||||
use nix::fcntl::*;
|
||||
use nix::unistd::pipe;
|
||||
|
||||
#[test]
|
||||
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);
|
||||
|
||||
assert!(res.is_ok());
|
||||
}
|
||||
|
||||
#[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));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
any(target_os = "wasi", target_env = "wasi"),
|
||||
target_os = "freebsd"))]
|
||||
mod test_posix_fallocate {
|
||||
|
||||
use tempfile::NamedTempFile;
|
||||
use std::{io::Read, os::unix::io::{RawFd, AsRawFd}};
|
||||
use nix::errno::Errno;
|
||||
use nix::fcntl::*;
|
||||
use nix::unistd::pipe;
|
||||
|
||||
#[test]
|
||||
fn success() {
|
||||
const LEN: usize = 100;
|
||||
let mut tmp = NamedTempFile::new().unwrap();
|
||||
let fd = tmp.as_raw_fd();
|
||||
let res = posix_fallocate(fd, 0, LEN as libc::off_t);
|
||||
match res {
|
||||
Ok(_) => {
|
||||
let mut data = [1u8; LEN];
|
||||
assert_eq!(tmp.read(&mut data).expect("read failure"), LEN);
|
||||
assert_eq!(&data[..], &[0u8; LEN][..]);
|
||||
}
|
||||
Err(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.
|
||||
// There's no way to tell for sure whether the file system
|
||||
// supports posix_fallocate, so we must pass the test if it
|
||||
// returns EINVAL.
|
||||
}
|
||||
_ => res.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn errno() {
|
||||
let (rd, _wr) = pipe().unwrap();
|
||||
let err = posix_fallocate(rd as RawFd, 0, 100).unwrap_err();
|
||||
match err {
|
||||
Errno::EINVAL | Errno::ENODEV | Errno::ESPIPE | Errno::EBADF => (),
|
||||
errno =>
|
||||
panic!(
|
||||
"unexpected errno {}",
|
||||
errno,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
obj-m += hello.o
|
||||
|
||||
all:
|
||||
make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules
|
||||
|
||||
clean:
|
||||
make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0+ or MIT
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
static int number= 1;
|
||||
static char *who = "World";
|
||||
|
||||
module_param(number, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
MODULE_PARM_DESC(myint, "Just some number");
|
||||
module_param(who, charp, 0000);
|
||||
MODULE_PARM_DESC(who, "Whot to greet");
|
||||
|
||||
int init_module(void)
|
||||
{
|
||||
printk(KERN_INFO "Hello %s (%d)!\n", who, number);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cleanup_module(void)
|
||||
{
|
||||
printk(KERN_INFO "Goodbye %s (%d)!\n", who, number);
|
||||
}
|
||||
|
||||
MODULE_LICENSE("Dual MIT/GPL");
|
166
vendor/nix-v0.23.1-patched/test/test_kmod/mod.rs
vendored
166
vendor/nix-v0.23.1-patched/test/test_kmod/mod.rs
vendored
|
@ -1,166 +0,0 @@
|
|||
use std::fs::copy;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use tempfile::{tempdir, TempDir};
|
||||
use crate::*;
|
||||
|
||||
fn compile_kernel_module() -> (PathBuf, String, TempDir) {
|
||||
let _m = crate::FORK_MTX
|
||||
.lock()
|
||||
.expect("Mutex got poisoned by another test");
|
||||
|
||||
let tmp_dir = tempdir().expect("unable to create temporary build directory");
|
||||
|
||||
copy(
|
||||
"test/test_kmod/hello_mod/hello.c",
|
||||
&tmp_dir.path().join("hello.c"),
|
||||
).expect("unable to copy hello.c to temporary build directory");
|
||||
copy(
|
||||
"test/test_kmod/hello_mod/Makefile",
|
||||
&tmp_dir.path().join("Makefile"),
|
||||
).expect("unable to copy Makefile to temporary build directory");
|
||||
|
||||
let status = Command::new("make")
|
||||
.current_dir(tmp_dir.path())
|
||||
.status()
|
||||
.expect("failed to run make");
|
||||
|
||||
assert!(status.success());
|
||||
|
||||
// Return the relative path of the build kernel module
|
||||
(tmp_dir.path().join("hello.ko"), "hello".to_owned(), tmp_dir)
|
||||
}
|
||||
|
||||
use nix::errno::Errno;
|
||||
use nix::kmod::{delete_module, DeleteModuleFlags};
|
||||
use nix::kmod::{finit_module, init_module, ModuleInitFlags};
|
||||
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().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();
|
||||
|
||||
let f = File::open(kmod_path).expect("unable to open kernel module");
|
||||
finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty())
|
||||
.expect("unable to load kernel module");
|
||||
|
||||
delete_module(
|
||||
&CString::new(kmod_name).unwrap(),
|
||||
DeleteModuleFlags::empty(),
|
||||
).expect("unable to unload kernel 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().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();
|
||||
|
||||
let f = File::open(kmod_path).expect("unable to open kernel module");
|
||||
finit_module(
|
||||
&f,
|
||||
&CString::new("who=Rust number=2018").unwrap(),
|
||||
ModuleInitFlags::empty(),
|
||||
).expect("unable to load kernel module");
|
||||
|
||||
delete_module(
|
||||
&CString::new(kmod_name).unwrap(),
|
||||
DeleteModuleFlags::empty(),
|
||||
).expect("unable to unload kernel module");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_init_and_delete_module() {
|
||||
require_capability!("test_init_and_delete_module", 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();
|
||||
|
||||
let mut f = File::open(kmod_path).expect("unable to open kernel 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");
|
||||
|
||||
delete_module(
|
||||
&CString::new(kmod_name).unwrap(),
|
||||
DeleteModuleFlags::empty(),
|
||||
).expect("unable to unload kernel 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().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();
|
||||
|
||||
let mut f = File::open(kmod_path).expect("unable to open kernel 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("who=Nix number=2015").unwrap())
|
||||
.expect("unable to load kernel module");
|
||||
|
||||
delete_module(
|
||||
&CString::new(kmod_name).unwrap(),
|
||||
DeleteModuleFlags::empty(),
|
||||
).expect("unable to unload kernel module");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_finit_module_invalid() {
|
||||
require_capability!("test_finit_module_invalid", 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);
|
||||
}
|
||||
|
||||
#[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().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();
|
||||
|
||||
let f = File::open(kmod_path).expect("unable to open kernel module");
|
||||
finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty())
|
||||
.expect("unable to load kernel module");
|
||||
|
||||
let result = finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty());
|
||||
|
||||
assert_eq!(result.unwrap_err(), Errno::EEXIST);
|
||||
|
||||
delete_module(
|
||||
&CString::new(kmod_name).unwrap(),
|
||||
DeleteModuleFlags::empty(),
|
||||
).expect("unable to unload kernel module");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delete_module_not_loaded() {
|
||||
require_capability!("test_delete_module_not_loaded", 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);
|
||||
}
|
236
vendor/nix-v0.23.1-patched/test/test_mount.rs
vendored
236
vendor/nix-v0.23.1-patched/test/test_mount.rs
vendored
|
@ -1,236 +0,0 @@
|
|||
mod common;
|
||||
|
||||
// Impelmentation note: to allow unprivileged users to run it, this test makes
|
||||
// use of user and mount namespaces. On systems that allow unprivileged user
|
||||
// namespaces (Linux >= 3.8 compiled with CONFIG_USER_NS), the test should run
|
||||
// without root.
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
mod test_mount {
|
||||
use std::fs::{self, File};
|
||||
use std::io::{self, Read, Write};
|
||||
use std::os::unix::fs::OpenOptionsExt;
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::process::{self, Command};
|
||||
|
||||
use libc::{EACCES, EROFS};
|
||||
|
||||
use nix::errno::Errno;
|
||||
use nix::mount::{mount, umount, MsFlags};
|
||||
use nix::sched::{unshare, CloneFlags};
|
||||
use nix::sys::stat::{self, Mode};
|
||||
use nix::unistd::getuid;
|
||||
|
||||
static SCRIPT_CONTENTS: &[u8] = b"#!/bin/sh
|
||||
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();
|
||||
|
||||
mount(NONE,
|
||||
tempdir.path(),
|
||||
Some(b"tmpfs".as_ref()),
|
||||
MsFlags::empty(),
|
||||
NONE)
|
||||
.unwrap_or_else(|e| panic!("mount failed: {}", e));
|
||||
|
||||
let test_path = tempdir.path().join("test");
|
||||
|
||||
// Verify write.
|
||||
fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
|
||||
.open(&test_path)
|
||||
.or_else(|e|
|
||||
if Errno::from_i32(e.raw_os_error().unwrap()) == Errno::EOVERFLOW {
|
||||
// Skip tests on certain Linux kernels which have a bug
|
||||
// regarding tmpfs in namespaces.
|
||||
// Ubuntu 14.04 and 16.04 are known to be affected; 16.10 is
|
||||
// not. There is no legitimate reason for open(2) to return
|
||||
// EOVERFLOW here.
|
||||
// https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1659087
|
||||
let stderr = io::stderr();
|
||||
let mut handle = stderr.lock();
|
||||
writeln!(handle, "Buggy Linux kernel detected. Skipping test.")
|
||||
.unwrap();
|
||||
process::exit(0);
|
||||
} else {
|
||||
panic!("open failed: {}", e);
|
||||
}
|
||||
)
|
||||
.and_then(|mut f| f.write(SCRIPT_CONTENTS))
|
||||
.unwrap_or_else(|e| panic!("write failed: {}", e));
|
||||
|
||||
// Verify read.
|
||||
let mut buf = Vec::new();
|
||||
File::open(&test_path)
|
||||
.and_then(|mut f| f.read_to_end(&mut buf))
|
||||
.unwrap_or_else(|e| panic!("read failed: {}", e));
|
||||
assert_eq!(buf, SCRIPT_CONTENTS);
|
||||
|
||||
// Verify execute.
|
||||
assert_eq!(EXPECTED_STATUS,
|
||||
Command::new(&test_path)
|
||||
.status()
|
||||
.unwrap_or_else(|e| panic!("exec failed: {}", e))
|
||||
.code()
|
||||
.unwrap_or_else(|| panic!("child killed by signal")));
|
||||
|
||||
umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {}", e));
|
||||
}
|
||||
|
||||
pub fn test_mount_rdonly_disallows_write() {
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
|
||||
mount(NONE,
|
||||
tempdir.path(),
|
||||
Some(b"tmpfs".as_ref()),
|
||||
MsFlags::MS_RDONLY,
|
||||
NONE)
|
||||
.unwrap_or_else(|e| panic!("mount failed: {}", e));
|
||||
|
||||
// EROFS: Read-only file system
|
||||
assert_eq!(EROFS as i32,
|
||||
File::create(tempdir.path().join("test")).unwrap_err().raw_os_error().unwrap());
|
||||
|
||||
umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {}", e));
|
||||
}
|
||||
|
||||
pub fn test_mount_noexec_disallows_exec() {
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
|
||||
mount(NONE,
|
||||
tempdir.path(),
|
||||
Some(b"tmpfs".as_ref()),
|
||||
MsFlags::MS_NOEXEC,
|
||||
NONE)
|
||||
.unwrap_or_else(|e| panic!("mount failed: {}", e));
|
||||
|
||||
let test_path = tempdir.path().join("test");
|
||||
|
||||
fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
|
||||
.open(&test_path)
|
||||
.and_then(|mut f| f.write(SCRIPT_CONTENTS))
|
||||
.unwrap_or_else(|e| panic!("write failed: {}", e));
|
||||
|
||||
// Verify that we cannot execute despite a+x permissions being set.
|
||||
let mode = stat::Mode::from_bits_truncate(fs::metadata(&test_path)
|
||||
.map(|md| md.permissions().mode())
|
||||
.unwrap_or_else(|e| {
|
||||
panic!("metadata failed: {}", e)
|
||||
}));
|
||||
|
||||
assert!(mode.contains(Mode::S_IXUSR | Mode::S_IXGRP | Mode::S_IXOTH),
|
||||
"{:?} did not have execute permissions",
|
||||
&test_path);
|
||||
|
||||
// EACCES: Permission denied
|
||||
assert_eq!(EACCES as i32,
|
||||
Command::new(&test_path).status().unwrap_err().raw_os_error().unwrap());
|
||||
|
||||
umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {}", e));
|
||||
}
|
||||
|
||||
pub fn test_mount_bind() {
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
let file_name = "test";
|
||||
|
||||
{
|
||||
let mount_point = tempfile::tempdir().unwrap();
|
||||
|
||||
mount(Some(tempdir.path()),
|
||||
mount_point.path(),
|
||||
NONE,
|
||||
MsFlags::MS_BIND,
|
||||
NONE)
|
||||
.unwrap_or_else(|e| panic!("mount failed: {}", e));
|
||||
|
||||
fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
|
||||
.open(mount_point.path().join(file_name))
|
||||
.and_then(|mut f| f.write(SCRIPT_CONTENTS))
|
||||
.unwrap_or_else(|e| panic!("write failed: {}", e));
|
||||
|
||||
umount(mount_point.path()).unwrap_or_else(|e| panic!("umount failed: {}", e));
|
||||
}
|
||||
|
||||
// Verify the file written in the mount shows up in source directory, even
|
||||
// after unmounting.
|
||||
|
||||
let mut buf = Vec::new();
|
||||
File::open(tempdir.path().join(file_name))
|
||||
.and_then(|mut f| f.read_to_end(&mut buf))
|
||||
.unwrap_or_else(|e| panic!("read failed: {}", e));
|
||||
assert_eq!(buf, SCRIPT_CONTENTS);
|
||||
}
|
||||
|
||||
pub fn setup_namespaces() {
|
||||
// Hold on to the uid in the parent namespace.
|
||||
let uid = getuid();
|
||||
|
||||
unshare(CloneFlags::CLONE_NEWNS | CloneFlags::CLONE_NEWUSER).unwrap_or_else(|e| {
|
||||
let stderr = io::stderr();
|
||||
let mut handle = stderr.lock();
|
||||
writeln!(handle,
|
||||
"unshare failed: {}. Are unprivileged user namespaces available?",
|
||||
e).unwrap();
|
||||
writeln!(handle, "mount is not being tested").unwrap();
|
||||
// Exit with success because not all systems support unprivileged user namespaces, and
|
||||
// that's not what we're testing for.
|
||||
process::exit(0);
|
||||
});
|
||||
|
||||
// Map user as uid 1000.
|
||||
fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.open("/proc/self/uid_map")
|
||||
.and_then(|mut f| f.write(format!("1000 {} 1\n", uid).as_bytes()))
|
||||
.unwrap_or_else(|e| panic!("could not write uid map: {}", e));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Test runner
|
||||
|
||||
/// Mimic normal test output (hackishly).
|
||||
#[cfg(target_os = "linux")]
|
||||
macro_rules! run_tests {
|
||||
( $($test_fn:ident),* ) => {{
|
||||
println!();
|
||||
|
||||
$(
|
||||
print!("test test_mount::{} ... ", stringify!($test_fn));
|
||||
$test_fn();
|
||||
println!("ok");
|
||||
)*
|
||||
|
||||
println!();
|
||||
}}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn main() {
|
||||
use test_mount::{setup_namespaces, test_mount_tmpfs_without_flags_allows_rwx,
|
||||
test_mount_rdonly_disallows_write, test_mount_noexec_disallows_exec,
|
||||
test_mount_bind};
|
||||
skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1351");
|
||||
setup_namespaces();
|
||||
|
||||
run_tests!(test_mount_tmpfs_without_flags_allows_rwx,
|
||||
test_mount_rdonly_disallows_write,
|
||||
test_mount_noexec_disallows_exec,
|
||||
test_mount_bind);
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
fn main() {}
|
157
vendor/nix-v0.23.1-patched/test/test_mq.rs
vendored
157
vendor/nix-v0.23.1-patched/test/test_mq.rs
vendored
|
@ -1,157 +0,0 @@
|
|||
use std::ffi::CString;
|
||||
use std::str;
|
||||
|
||||
use nix::errno::Errno;
|
||||
use nix::mqueue::{mq_open, mq_close, mq_send, mq_receive, mq_attr_member_t};
|
||||
use nix::mqueue::{MqAttr, MQ_OFlag};
|
||||
use nix::sys::stat::Mode;
|
||||
|
||||
#[test]
|
||||
fn test_mq_send_and_receive() {
|
||||
const MSG_SIZE: mq_attr_member_t = 32;
|
||||
let attr = MqAttr::new(0, 10, MSG_SIZE, 0);
|
||||
let mq_name= &CString::new(b"/a_nix_test_queue".as_ref()).unwrap();
|
||||
|
||||
let oflag0 = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
|
||||
let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
|
||||
let r0 = mq_open(mq_name, oflag0, mode, Some(&attr));
|
||||
if let Err(Errno::ENOSYS) = r0 {
|
||||
println!("message queues not supported or module not loaded?");
|
||||
return;
|
||||
};
|
||||
let mqd0 = r0.unwrap();
|
||||
let msg_to_send = "msg_1";
|
||||
mq_send(mqd0, msg_to_send.as_bytes(), 1).unwrap();
|
||||
|
||||
let oflag1 = MQ_OFlag::O_CREAT | MQ_OFlag::O_RDONLY;
|
||||
let mqd1 = mq_open(mq_name, oflag1, mode, Some(&attr)).unwrap();
|
||||
let mut buf = [0u8; 32];
|
||||
let mut prio = 0u32;
|
||||
let len = mq_receive(mqd1, &mut buf, &mut prio).unwrap();
|
||||
assert_eq!(prio, 1);
|
||||
|
||||
mq_close(mqd1).unwrap();
|
||||
mq_close(mqd0).unwrap();
|
||||
assert_eq!(msg_to_send, str::from_utf8(&buf[0..len]).unwrap());
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
#[cfg(not(any(target_os = "netbsd")))]
|
||||
fn test_mq_getattr() {
|
||||
use nix::mqueue::mq_getattr;
|
||||
const MSG_SIZE: mq_attr_member_t = 32;
|
||||
let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0);
|
||||
let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap();
|
||||
let 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 {
|
||||
println!("message queues not supported or module not loaded?");
|
||||
return;
|
||||
};
|
||||
let mqd = r.unwrap();
|
||||
|
||||
let read_attr = mq_getattr(mqd).unwrap();
|
||||
assert_eq!(read_attr, initial_attr);
|
||||
mq_close(mqd).unwrap();
|
||||
}
|
||||
|
||||
// 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
|
||||
)]
|
||||
fn test_mq_setattr() {
|
||||
use nix::mqueue::{mq_getattr, mq_setattr};
|
||||
const MSG_SIZE: mq_attr_member_t = 32;
|
||||
let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0);
|
||||
let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap();
|
||||
let 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 {
|
||||
println!("message queues not supported or module not loaded?");
|
||||
return;
|
||||
};
|
||||
let mqd = r.unwrap();
|
||||
|
||||
let new_attr = MqAttr::new(0, 20, MSG_SIZE * 2, 100);
|
||||
let old_attr = mq_setattr(mqd, &new_attr).unwrap();
|
||||
assert_eq!(old_attr, initial_attr);
|
||||
|
||||
let new_attr_get = mq_getattr(mqd).unwrap();
|
||||
// The following tests make sense. No changes here because according to the Linux man page only
|
||||
// O_NONBLOCK can be set (see tests below)
|
||||
assert_ne!(new_attr_get, new_attr);
|
||||
|
||||
let new_attr_non_blocking = MqAttr::new(MQ_OFlag::O_NONBLOCK.bits() as mq_attr_member_t, 10, MSG_SIZE, 0);
|
||||
mq_setattr(mqd, &new_attr_non_blocking).unwrap();
|
||||
let new_attr_get = mq_getattr(mqd).unwrap();
|
||||
|
||||
// now the O_NONBLOCK flag has been set
|
||||
assert_ne!(new_attr_get, initial_attr);
|
||||
assert_eq!(new_attr_get, new_attr_non_blocking);
|
||||
mq_close(mqd).unwrap();
|
||||
}
|
||||
|
||||
// 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
|
||||
)]
|
||||
fn test_mq_set_nonblocking() {
|
||||
use nix::mqueue::{mq_getattr, mq_set_nonblock, mq_remove_nonblock};
|
||||
const MSG_SIZE: mq_attr_member_t = 32;
|
||||
let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0);
|
||||
let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap();
|
||||
let 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 {
|
||||
println!("message queues not supported or module not loaded?");
|
||||
return;
|
||||
};
|
||||
let mqd = r.unwrap();
|
||||
mq_set_nonblock(mqd).unwrap();
|
||||
let new_attr = mq_getattr(mqd);
|
||||
assert_eq!(new_attr.unwrap().flags(), MQ_OFlag::O_NONBLOCK.bits() as mq_attr_member_t);
|
||||
mq_remove_nonblock(mqd).unwrap();
|
||||
let new_attr = mq_getattr(mqd);
|
||||
assert_eq!(new_attr.unwrap().flags(), 0);
|
||||
mq_close(mqd).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(any(target_os = "netbsd")))]
|
||||
fn test_mq_unlink() {
|
||||
use nix::mqueue::mq_unlink;
|
||||
const MSG_SIZE: mq_attr_member_t = 32;
|
||||
let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0);
|
||||
let mq_name_opened = &CString::new(b"/mq_unlink_test".as_ref()).unwrap();
|
||||
let mq_name_not_opened = &CString::new(b"/mq_unlink_test".as_ref()).unwrap();
|
||||
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 {
|
||||
println!("message queues not supported or module not loaded?");
|
||||
return;
|
||||
};
|
||||
let mqd = r.unwrap();
|
||||
|
||||
let res_unlink = mq_unlink(mq_name_opened);
|
||||
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) );
|
||||
|
||||
mq_close(mqd).unwrap();
|
||||
let res_unlink_after_close = mq_unlink(mq_name_opened);
|
||||
assert_eq!(res_unlink_after_close, Err(Errno::ENOENT) );
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue