mirror of
https://github.com/openharmony/third_party_rust_nix.git
synced 2026-06-30 21:27:54 -04:00
+8
-259
@@ -9,7 +9,7 @@ env:
|
||||
RUSTFLAGS: -D warnings
|
||||
RUSTDOCFLAGS: -D warnings
|
||||
TOOL: cargo
|
||||
MSRV: 1.56.1
|
||||
MSRV: 1.69.0
|
||||
ZFLAGS:
|
||||
|
||||
# Tests that don't require executing the build binaries
|
||||
@@ -18,9 +18,9 @@ build: &BUILD
|
||||
- . $HOME/.cargo/env || true
|
||||
- $TOOL -Vv
|
||||
- rustc -Vv
|
||||
- $TOOL $BUILD $ZFLAGS --target $TARGET --all-targets
|
||||
- $TOOL doc $ZFLAGS --no-deps --target $TARGET
|
||||
- $TOOL clippy $ZFLAGS --target $TARGET --all-targets -- $CLIPPYFLAGS
|
||||
- $TOOL $BUILD $ZFLAGS --target $TARGET --all-targets --all-features
|
||||
- $TOOL doc $ZFLAGS --no-deps --target $TARGET --all-features
|
||||
- $TOOL clippy $ZFLAGS --target $TARGET --all-targets --all-features -- $CLIPPYFLAGS
|
||||
- if [ -z "$NOHACK" ]; then mkdir -p $HOME/.cargo/bin; export PATH=$HOME/.cargo/bin:$PATH; fi
|
||||
- if [ -z "$NOHACK" ]; then curl -LsSf https://github.com/taiki-e/cargo-hack/releases/latest/download/cargo-hack-${HOST:-$TARGET}.tar.gz | tar xzf - -C ~/.cargo/bin; fi
|
||||
- if [ -z "$NOHACK" ]; then $TOOL hack $ZFLAGS check --target $TARGET --each-feature; fi
|
||||
@@ -40,12 +40,10 @@ task:
|
||||
env:
|
||||
TARGET: x86_64-unknown-freebsd
|
||||
matrix:
|
||||
- name: FreeBSD 12 amd64 & i686
|
||||
freebsd_instance:
|
||||
image: freebsd-12-3-release-amd64
|
||||
- name: FreeBSD 14 amd64 & i686
|
||||
freebsd_instance:
|
||||
image_family: freebsd-14-0-snap
|
||||
image: freebsd-14-1-release-amd64-ufs
|
||||
cpu: 1
|
||||
# Enable tests that would fail on FreeBSD 12
|
||||
RUSTFLAGS: --cfg fbsd14 -D warnings
|
||||
RUSTDOCFLAGS: --cfg fbsd14
|
||||
@@ -56,262 +54,13 @@ task:
|
||||
- . $HOME/.cargo/env
|
||||
- rustup target add i686-unknown-freebsd
|
||||
- rustup component add clippy
|
||||
- cp Cargo.lock.msrv Cargo.lock
|
||||
<< : *TEST
|
||||
i386_test_script:
|
||||
- . $HOME/.cargo/env
|
||||
- cargo build --target i686-unknown-freebsd
|
||||
- cargo doc --no-deps --target i686-unknown-freebsd
|
||||
- cargo build --target i686-unknown-freebsd --all-features
|
||||
- cargo doc --no-deps --target i686-unknown-freebsd --all-features
|
||||
- cargo test --target i686-unknown-freebsd
|
||||
i386_feature_script:
|
||||
- . $HOME/.cargo/env
|
||||
- if [ -z "$NOHACK" ]; then cargo hack check --each-feature --target i686-unknown-freebsd; fi
|
||||
before_cache_script: rm -rf $CARGO_HOME/registry/index
|
||||
|
||||
# Test macOS aarch64 in a full VM
|
||||
task:
|
||||
name: macOS aarch64
|
||||
env:
|
||||
TARGET: aarch64-apple-darwin
|
||||
macos_instance:
|
||||
image: ghcr.io/cirruslabs/macos-ventura-base:latest
|
||||
setup_script:
|
||||
- curl --proto '=https' --tlsv1.2 -sSf -o rustup.sh https://sh.rustup.rs
|
||||
- sh rustup.sh -y --profile=minimal --default-toolchain $MSRV
|
||||
- . $HOME/.cargo/env
|
||||
- rustup component add clippy
|
||||
- cp Cargo.lock.msrv Cargo.lock
|
||||
<< : *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
|
||||
HOST: x86_64-unknown-linux-gnu
|
||||
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 $MSRV
|
||||
- . $HOME/.cargo/env
|
||||
- cargo install cross --version 0.2.1 --locked # cross 0.2.2 bumped the MSRV to 1.58.1
|
||||
- cp Cargo.lock.msrv Cargo.lock
|
||||
<< : *TEST
|
||||
before_cache_script: rm -rf $CARGO_HOME/registry/index
|
||||
|
||||
# Tasks for Linux native builds
|
||||
task:
|
||||
matrix:
|
||||
- name: Linux aarch64
|
||||
arm_container:
|
||||
image: rust:1.56
|
||||
env:
|
||||
TARGET: aarch64-unknown-linux-gnu
|
||||
- name: Linux x86_64
|
||||
container:
|
||||
image: rust:1.56
|
||||
env:
|
||||
TARGET: x86_64-unknown-linux-gnu
|
||||
- name: Linux x86_64 musl
|
||||
container:
|
||||
image: rust:1.56
|
||||
env:
|
||||
TARGET: x86_64-unknown-linux-musl
|
||||
setup_script:
|
||||
- rustup target add $TARGET
|
||||
- rustup component add clippy
|
||||
- cp Cargo.lock.msrv Cargo.lock
|
||||
<< : *TEST
|
||||
before_cache_script: rm -rf $CARGO_HOME/registry/index
|
||||
|
||||
task:
|
||||
name: Rust Stable
|
||||
container:
|
||||
image: rust:latest
|
||||
env:
|
||||
TARGET: x86_64-unknown-linux-gnu
|
||||
setup_script:
|
||||
- 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.56
|
||||
env:
|
||||
BUILD: check
|
||||
HOST: x86_64-unknown-linux-gnu
|
||||
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
|
||||
# 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:
|
||||
# cargo hack tries to invoke the iphonesimulator SDK for iOS
|
||||
NOHACK: 1
|
||||
TARGET: aarch64-apple-ios
|
||||
- name: iOS x86_64
|
||||
env:
|
||||
# cargo hack tries to invoke the iphonesimulator SDK for iOS
|
||||
NOHACK: 1
|
||||
TARGET: x86_64-apple-ios
|
||||
# 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: macOS x86_64
|
||||
env:
|
||||
TARGET: x86_64-apple-darwin
|
||||
- name: NetBSD x86_64
|
||||
env:
|
||||
TARGET: x86_64-unknown-netbsd
|
||||
setup_script:
|
||||
- rustup target add $TARGET
|
||||
- rustup component add clippy
|
||||
- cp Cargo.lock.msrv Cargo.lock
|
||||
<< : *BUILD
|
||||
before_cache_script: rm -rf $CARGO_HOME/registry/index
|
||||
|
||||
task:
|
||||
container:
|
||||
# Redox's MSRV policy is unclear. Until they define it, use nightly.
|
||||
image: rustlang/rust:nightly
|
||||
env:
|
||||
BUILD: check
|
||||
name: Redox x86_64
|
||||
env:
|
||||
HOST: x86_64-unknown-linux-gnu
|
||||
TARGET: x86_64-unknown-redox
|
||||
CLIPPYFLAGS: -D warnings
|
||||
setup_script:
|
||||
- rustup target add $TARGET
|
||||
- rustup component add 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
|
||||
HOST: x86_64-unknown-linux-gnu
|
||||
ZFLAGS: -Zbuild-std
|
||||
CLIPPYFLAGS: -D warnings
|
||||
matrix:
|
||||
- name: DragonFly BSD x86_64
|
||||
env:
|
||||
TARGET: x86_64-unknown-dragonfly
|
||||
- name: OpenBSD x86_64
|
||||
env:
|
||||
TARGET: x86_64-unknown-openbsd
|
||||
- name: Linux armv7 uclibceabihf
|
||||
env:
|
||||
TARGET: armv7-unknown-linux-uclibceabihf
|
||||
- name: Haiku x86_64
|
||||
env:
|
||||
TARGET: x86_64-unknown-haiku
|
||||
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:
|
||||
HOST: x86_64-unknown-linux-gnu
|
||||
container:
|
||||
image: rustlang/rust:nightly
|
||||
setup_script:
|
||||
- cargo update -Zminimal-versions
|
||||
check_script:
|
||||
- cargo check
|
||||
before_cache_script: rm -rf $CARGO_HOME/registry/index
|
||||
|
||||
# Tasks that checks if the code is formatted right using `cargo fmt` tool
|
||||
task:
|
||||
name: Rust Formatter
|
||||
container:
|
||||
image: rust:latest
|
||||
setup_script: rustup component add rustfmt
|
||||
test_script: cargo fmt --all -- --check **/*.rs
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
## What does this PR do
|
||||
|
||||
## Checklist:
|
||||
|
||||
- [ ] I have read `CONTRIBUTING.md`
|
||||
- [ ] I have written necessary tests and rustdoc comments
|
||||
- [ ] A change log has been added if this PR modifies nix's API
|
||||
@@ -0,0 +1,72 @@
|
||||
name: 'Build'
|
||||
description: 'Build nix'
|
||||
inputs:
|
||||
# This is required
|
||||
TARGET:
|
||||
required: true
|
||||
|
||||
BUILD:
|
||||
required: false
|
||||
default: build
|
||||
|
||||
CLIPPYFLAGS:
|
||||
required: false
|
||||
default: -D warnings -A unknown-lints
|
||||
|
||||
RUSTFLAGS:
|
||||
required: false
|
||||
default: -D warnings -A unknown-lints
|
||||
|
||||
RUSTDOCFLAGS:
|
||||
required: false
|
||||
default: -D warnings
|
||||
|
||||
TOOL:
|
||||
description: 'Tool used to involve the BUILD command, can be cargo or cross'
|
||||
required: false
|
||||
default: cargo
|
||||
|
||||
ZFLAGS:
|
||||
required: false
|
||||
default:
|
||||
|
||||
NOHACK:
|
||||
description: "whether to run cargo hack"
|
||||
required: false
|
||||
default: false
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: set up Rust env
|
||||
shell: bash
|
||||
run: |
|
||||
echo "RUSTFLAGS=${{ inputs.RUSTFLAGS }}" >> $GITHUB_ENV
|
||||
echo "RUSTDOCFLAGS=${{ inputs.RUSTDOCFLAGS }}" >> $GITHUB_ENV
|
||||
|
||||
- name: debug info
|
||||
shell: bash
|
||||
run: |
|
||||
${{ inputs.TOOL }} -Vv
|
||||
rustc -Vv
|
||||
|
||||
- name: build
|
||||
shell: bash
|
||||
run: ${{ inputs.TOOL }} ${{ inputs.BUILD }} ${{ inputs.ZFLAGS }} --target ${{ inputs.TARGET }} --all-targets --all-features
|
||||
|
||||
- name: doc
|
||||
shell: bash
|
||||
run: ${{ inputs.TOOL }} doc ${{ inputs.ZFLAGS }} --no-deps --target ${{ inputs.TARGET }} --all-features
|
||||
|
||||
- name: clippy
|
||||
shell: bash
|
||||
run: ${{ inputs.TOOL}} clippy ${{ inputs.ZFLAGS }} --target ${{ inputs.TARGET }} --all-targets --all-features -- ${{ inputs.CLIPPYFLAGS }}
|
||||
|
||||
- name: Set up cargo-hack
|
||||
if: inputs.NOHACK == 'false'
|
||||
uses: taiki-e/install-action@cargo-hack
|
||||
|
||||
- name: run cargo hack
|
||||
shell: bash
|
||||
if: inputs.NOHACK == 'false'
|
||||
run: ${{ inputs.TOOL }} hack ${{ inputs.ZFLAGS }} check --target ${{ inputs.TARGET }} --each-feature
|
||||
@@ -0,0 +1,46 @@
|
||||
name: 'Check new CHANGELOG'
|
||||
description: 'Check new CHANGELOG kind and PR number'
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Get newly added CHANGELOGs
|
||||
id: new-changelogs
|
||||
uses: tj-actions/changed-files@v44
|
||||
with:
|
||||
# Only checek the files under the `changelog` directory
|
||||
files: changelog/**
|
||||
|
||||
- name: Check them
|
||||
shell: bash
|
||||
if: steps.new-changelogs.outputs.added_files_count != 0
|
||||
env:
|
||||
NEW_CHANGELOGS: ${{ steps.new-changelogs.outputs.added_files }}
|
||||
PR_NUMBER: ${{ github.event.number }}
|
||||
run: |
|
||||
# `cl` will be something like "changelog/1.added.md"
|
||||
for cl in ${NEW_CHANGELOGS}; do
|
||||
# Trim the directory name
|
||||
prefix="changelog/"; trimmed_cl=${cl/#$prefix}; cl="${trimmed_cl}";
|
||||
|
||||
# parse it
|
||||
IFS='.' read id kind file_extension <<< "${cl}"
|
||||
|
||||
# Check the kind field
|
||||
if [ "$kind" != "added" ] && [ "$kind" != "changed" ] && [ "$kind" != "fixed" ] && [ "$kind" != "removed" ]; then
|
||||
echo "Invalid CHANGELOG kind [${kind}] from [${cl}], available options are [added, changed, fixed, removed]";
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
# Check the file extension
|
||||
if [ "$file_extension" != "md" ]; then
|
||||
echo "Invalid file extension [${file_extension}] from [${cl}], it should be [md]";
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
# Check PR number
|
||||
if [ "$id" != "$PR_NUMBER" ]; then
|
||||
echo "Mismatched PR number [${id}] from [${cl}], it should be ${PR_NUMBER}";
|
||||
exit 1;
|
||||
fi
|
||||
done
|
||||
@@ -0,0 +1,32 @@
|
||||
name: 'Test'
|
||||
description: 'Test nix'
|
||||
inputs:
|
||||
# This is required
|
||||
TARGET:
|
||||
required: true
|
||||
|
||||
SUDO:
|
||||
description: 'Set it to an empty string to run the tests as the current user, leave it with the default value to test with "sudo"'
|
||||
required: false
|
||||
default: sudo --preserve-env=HOME
|
||||
|
||||
TOOL:
|
||||
description: 'Tool used to involve the test command, can be cargo or cross'
|
||||
required: false
|
||||
default: cargo
|
||||
|
||||
RUSTFLAGS:
|
||||
required: false
|
||||
default: -D warnings -A unknown-lints
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: set up Rust env
|
||||
shell: bash
|
||||
run: |
|
||||
echo "RUSTFLAGS=${{ inputs.RUSTFLAGS }}" >> $GITHUB_ENV
|
||||
|
||||
- name: test
|
||||
shell: bash
|
||||
run: ${{ inputs.SUDO }} $(which ${{ inputs.TOOL }}) test --target ${{ inputs.TARGET }}
|
||||
@@ -0,0 +1,18 @@
|
||||
name: Check new CHANGELOGs
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
check_new_changelog:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: check new CHANGELOG
|
||||
uses: ./.github/actions/check_new_changelog
|
||||
@@ -0,0 +1,441 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
merge_group:
|
||||
types: [checks_requested]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
MSRV: 1.69.0
|
||||
# Rust's Loongarch support merged in 1.71.0
|
||||
MSRV_LOONGARCH: 1.71.0
|
||||
# Minimal Rust version to support all 3 official OpenHarmony targets as tier2
|
||||
MSRV_OHOS: 1.78.0
|
||||
RUSTFLAGS: -Dwarnings
|
||||
|
||||
jobs:
|
||||
macos:
|
||||
runs-on: macos-13
|
||||
env:
|
||||
TARGET: x86_64-apple-darwin
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: setup Rust
|
||||
uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: '${{ env.MSRV }}'
|
||||
components: clippy
|
||||
|
||||
- name: build
|
||||
uses: ./.github/actions/build
|
||||
with:
|
||||
TARGET: '${{ env.TARGET }}'
|
||||
|
||||
- name: test
|
||||
uses: ./.github/actions/test
|
||||
with:
|
||||
TARGET: '${{ env.TARGET }}'
|
||||
|
||||
- name: before_cache_script
|
||||
run: sudo rm -rf $CARGO_HOME/registry/index
|
||||
|
||||
macos-aarch64:
|
||||
runs-on: macos-latest
|
||||
env:
|
||||
TARGET: aarch64-apple-darwin
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: setup Rust
|
||||
uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: '${{ env.MSRV }}'
|
||||
components: clippy
|
||||
|
||||
- name: build
|
||||
uses: ./.github/actions/build
|
||||
with:
|
||||
TARGET: "${{ env.TARGET }}"
|
||||
|
||||
- name: test
|
||||
uses: ./.github/actions/test
|
||||
with:
|
||||
TARGET: "${{ env.TARGET }}"
|
||||
|
||||
- name: before_cache_script
|
||||
run: sudo rm -rf $CARGO_HOME/registry/index
|
||||
|
||||
# Use cross for QEMU-based testing
|
||||
# cross needs to execute Docker, GitHub Action already has it installed
|
||||
cross:
|
||||
runs-on: ubuntu-24.04
|
||||
needs: [rustfmt, minver, macos, x86_64_linux_native_builds, rust_stable]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target: [
|
||||
arm-unknown-linux-gnueabi,
|
||||
armv7-unknown-linux-gnueabihf,
|
||||
i686-unknown-linux-gnu,
|
||||
i686-unknown-linux-musl,
|
||||
|
||||
# Disable MIPS CIs, see https://github.com/nix-rust/nix/issues/2593
|
||||
# for detailed info.
|
||||
#
|
||||
# mips-unknown-linux-gnu,
|
||||
# mips64-unknown-linux-gnuabi64,
|
||||
# mips64el-unknown-linux-gnuabi64,
|
||||
# mipsel-unknown-linux-gnu,
|
||||
|
||||
powerpc64le-unknown-linux-gnu,
|
||||
loongarch64-unknown-linux-gnu,
|
||||
]
|
||||
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: setup Rust
|
||||
uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
# Use a newer version rustc if the target is Loongarch, remove this workaround after MSRV is newer than 1.71.0
|
||||
toolchain: "${{ matrix.target == 'loongarch64-unknown-linux-gnu' && env.MSRV_LOONGARCH || env.MSRV }}"
|
||||
components: clippy
|
||||
|
||||
# cross relies on docker or podman, GitHub Acton already has it installed.
|
||||
- name: Set up cross
|
||||
uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: cross@0.2.5
|
||||
|
||||
- name: build
|
||||
uses: ./.github/actions/build
|
||||
with:
|
||||
TARGET: '${{ matrix.target }}'
|
||||
TOOL: cross
|
||||
RUSTFLAGS: --cfg qemu -D warnings
|
||||
|
||||
- name: test
|
||||
uses: ./.github/actions/test
|
||||
with:
|
||||
TARGET: '${{ matrix.target }}'
|
||||
SUDO: ""
|
||||
TOOL: cross
|
||||
RUSTFLAGS: --cfg qemu -D warnings
|
||||
|
||||
- name: before_cache_script
|
||||
run: rm -rf $CARGO_HOME/registry/index
|
||||
|
||||
|
||||
|
||||
# Tasks for x86_64 Linux native builds
|
||||
x86_64_linux_native_builds:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target: [
|
||||
x86_64-unknown-linux-gnu,
|
||||
x86_64-unknown-linux-musl,
|
||||
]
|
||||
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: setup Rust
|
||||
uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: '${{ env.MSRV }}'
|
||||
components: clippy
|
||||
|
||||
- name: install targets
|
||||
run: rustup target add ${{ matrix.target }}
|
||||
|
||||
- name: build
|
||||
uses: ./.github/actions/build
|
||||
with:
|
||||
TARGET: '${{ matrix.TARGET }}'
|
||||
|
||||
- name: test
|
||||
uses: ./.github/actions/test
|
||||
with:
|
||||
TARGET: '${{ matrix.TARGET }}'
|
||||
|
||||
- name: before_cache_script
|
||||
run: sudo rm -rf $CARGO_HOME/registry/index;
|
||||
|
||||
# Tasks for aarch64 Linux native builds
|
||||
aarch64_linux_native_builds:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target: [
|
||||
aarch64-unknown-linux-gnu,
|
||||
aarch64-unknown-linux-musl,
|
||||
]
|
||||
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: setup Rust
|
||||
uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: '${{ env.MSRV }}'
|
||||
components: clippy
|
||||
|
||||
- name: install targets
|
||||
run: rustup target add ${{ matrix.target }}
|
||||
|
||||
- name: build
|
||||
uses: ./.github/actions/build
|
||||
with:
|
||||
TARGET: '${{ matrix.TARGET }}'
|
||||
|
||||
- name: test
|
||||
uses: ./.github/actions/test
|
||||
with:
|
||||
TARGET: '${{ matrix.TARGET }}'
|
||||
|
||||
- name: before_cache_script
|
||||
run: sudo rm -rf $CARGO_HOME/registry/index;
|
||||
|
||||
rust_stable:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TARGET: x86_64-unknown-linux-gnu
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: setup Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: clippy
|
||||
|
||||
- name: build
|
||||
uses: ./.github/actions/build
|
||||
with:
|
||||
TARGET: '${{ env.TARGET }}'
|
||||
|
||||
- name: test
|
||||
uses: ./.github/actions/test
|
||||
with:
|
||||
TARGET: '${{ env.TARGET }}'
|
||||
|
||||
- name: before_cache_script
|
||||
run: sudo rm -rf $CARGO_HOME/registry/index
|
||||
|
||||
|
||||
|
||||
# Tasks for cross-compiling, but no testing
|
||||
cross_compiling:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [rustfmt, minver, macos, x86_64_linux_native_builds, rust_stable]
|
||||
env:
|
||||
BUILD: check
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# Cross claims to support Android, but when it tries to run Nix's tests it
|
||||
# reports undefined symbol references.
|
||||
- target: aarch64-linux-android
|
||||
- target: arm-linux-androideabi
|
||||
- target: armv7-linux-androideabi
|
||||
- target: i686-linux-android
|
||||
- target: x86_64-linux-android
|
||||
- target: arm-unknown-linux-musleabi
|
||||
- target: x86_64-unknown-fuchsia
|
||||
- target: x86_64-unknown-illumos
|
||||
# Cross claims to support running tests on iOS, but it actually doesn't.
|
||||
# https://github.com/rust-embedded/cross/issues/535
|
||||
- target: aarch64-apple-ios
|
||||
# cargo hack tries to invoke the iphonesimulator SDK for iOS
|
||||
NOHACK: true
|
||||
# Cross claims to support Linux powerpc64, but it really doesn't.
|
||||
# https://github.com/rust-embedded/cross/issues/441
|
||||
- target: powerpc64-unknown-linux-gnu
|
||||
- target: s390x-unknown-linux-gnu
|
||||
- target: x86_64-unknown-linux-gnux32
|
||||
- target: x86_64-unknown-netbsd
|
||||
- target: aarch64-unknown-linux-ohos
|
||||
- target: armv7-unknown-linux-ohos
|
||||
- target: x86_64-unknown-linux-ohos
|
||||
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: setup Rust
|
||||
uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
# Use a newer version rustc if it is OpenHarmony, remove this workaround after MSRV is newer than 1.78.0
|
||||
toolchain: "${{ contains(matrix.target, 'ohos') && env.MSRV_OHOS || env.MSRV }}"
|
||||
components: clippy
|
||||
|
||||
- name: install targets
|
||||
run: rustup target add ${{ matrix.target }}
|
||||
|
||||
- name: build
|
||||
uses: ./.github/actions/build
|
||||
with:
|
||||
TARGET: '${{ matrix.target }}'
|
||||
BUILD: '${{ env.BUILD }}'
|
||||
NOHACK: '${{ matrix.NOHACK }}'
|
||||
|
||||
- name: before_cache_script
|
||||
run: rm -rf $CARGO_HOME/registry/index
|
||||
|
||||
|
||||
redox:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [rustfmt, minver, macos, x86_64_linux_native_builds, rust_stable]
|
||||
env:
|
||||
TARGET: x86_64-unknown-redox
|
||||
CLIPPYFLAGS: -D warnings
|
||||
BUILD: check
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: setup Rust
|
||||
# Redox's MSRV policy is unclear. Until they define it, use nightly.
|
||||
uses: dtolnay/rust-toolchain@nightly
|
||||
with:
|
||||
components: clippy
|
||||
|
||||
- name: install targets
|
||||
run: rustup target add ${{ env.TARGET }}
|
||||
|
||||
- name: build
|
||||
uses: ./.github/actions/build
|
||||
with:
|
||||
TARGET: '${{ env.TARGET }}'
|
||||
BUILD: '${{ env.BUILD }}'
|
||||
CLIPPYFLAGS: '${{ env.CLIPPYFLAGS }}'
|
||||
|
||||
- name: before_cache_script
|
||||
run: rm -rf $CARGO_HOME/registry/index
|
||||
|
||||
|
||||
|
||||
# Rust Tier 3 targets can't use Rustup
|
||||
tier3:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
BUILD: check
|
||||
ZFLAGS: -Zbuild-std
|
||||
CLIPPYFLAGS: -D warnings
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- target: x86_64-unknown-dragonfly
|
||||
- target: x86_64-unknown-openbsd
|
||||
- target: x86_64-unknown-haiku
|
||||
- target: armv7-unknown-linux-uclibceabihf
|
||||
# Disable Hurd due to
|
||||
# 1. https://github.com/rust-lang/libc/issues/4421
|
||||
# 2. https://github.com/nix-rust/nix/pull/2635#issuecomment-2842062528
|
||||
#
|
||||
# We can bring it back when 1 gets fixed and it is applied to the std lib
|
||||
# - target: i686-unknown-hurd-gnu
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: setup Rust
|
||||
uses: dtolnay/rust-toolchain@nightly
|
||||
with:
|
||||
components: clippy
|
||||
|
||||
- name: install src
|
||||
run: rustup component add rust-src
|
||||
|
||||
- name: build
|
||||
uses: ./.github/actions/build
|
||||
with:
|
||||
TARGET: '${{ matrix.target }}'
|
||||
BUILD: '${{ env.BUILD }}'
|
||||
ZFLAGS: '${{ env.ZFLAGS }}'
|
||||
CLIPPYFLAGS: '${{ env.CLIPPYFLAGS }}'
|
||||
|
||||
- name: before_cache_script
|
||||
run: rm -rf $CARGO_HOME/registry/index
|
||||
|
||||
solaris:
|
||||
name: solaris (x86_64-pc-solaris)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: build and test
|
||||
uses: vmactions/solaris-vm@v1
|
||||
with:
|
||||
release: "11.4-gcc"
|
||||
usesh: true
|
||||
mem: 4096
|
||||
copyback: false
|
||||
prepare: |
|
||||
source <(curl -s https://raw.githubusercontent.com/psumbera/solaris-rust/refs/heads/main/sh.rust-web-install)
|
||||
echo "~~~~ rustc --version ~~~~"
|
||||
rustc --version
|
||||
echo "~~~~ Solaris-version ~~~~"
|
||||
uname -a
|
||||
run: |
|
||||
export PATH=$HOME/.rust_solaris/bin:$PATH
|
||||
cargo build --target x86_64-pc-solaris --all-targets --all-features && sudo cargo test
|
||||
|
||||
# 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.
|
||||
minver:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TARGET: x86_64-unknown-linux-gnu
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: setup Rust
|
||||
uses: dtolnay/rust-toolchain@nightly
|
||||
|
||||
- name: setup
|
||||
run: cargo update -Zdirect-minimal-versions
|
||||
|
||||
- name: check
|
||||
run: cargo check
|
||||
|
||||
- name: before_cache_script
|
||||
run: rm -rf $CARGO_HOME/registry/index
|
||||
|
||||
# Tasks that checks if the code is formatted right using `cargo fmt` tool
|
||||
rustfmt:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: rustfmt
|
||||
|
||||
- name: Check format
|
||||
run: cargo fmt --all -- --check **/*.rs
|
||||
|
||||
- name: before_cache_script
|
||||
run: rm -rf $CARGO_HOME/registry/index
|
||||
|
||||
@@ -19,8 +19,8 @@ ohos_cargo_crate("lib") {
|
||||
crate_root = "src/lib.rs"
|
||||
|
||||
sources = ["src/lib.rs"]
|
||||
edition = "2018"
|
||||
cargo_pkg_version = "0.26.4"
|
||||
edition = "2021"
|
||||
cargo_pkg_version = "0.30.1"
|
||||
cargo_pkg_authors = "The nix-rust Project Developers"
|
||||
cargo_pkg_name = "nix"
|
||||
cargo_pkg_description = "Rust friendly bindings to *nix APIs"
|
||||
@@ -30,14 +30,15 @@ ohos_cargo_crate("lib") {
|
||||
"//third_party/rust/crates/libc:lib",
|
||||
"//third_party/rust/crates/memoffset:lib",
|
||||
"//third_party/rust/crates/pin-utils:lib",
|
||||
"//third_party/rust/crates/static-assertions-rs:lib",
|
||||
]
|
||||
features = [
|
||||
"acct",
|
||||
"aio",
|
||||
"default",
|
||||
"dir",
|
||||
"env",
|
||||
"event",
|
||||
"fanotify",
|
||||
"feature",
|
||||
"fs",
|
||||
"hostname",
|
||||
@@ -47,9 +48,9 @@ ohos_cargo_crate("lib") {
|
||||
"memoffset",
|
||||
"mman",
|
||||
"mount",
|
||||
"mqueue",
|
||||
"net",
|
||||
"personality",
|
||||
"pin-utils",
|
||||
"poll",
|
||||
"process",
|
||||
"pthread",
|
||||
@@ -60,6 +61,7 @@ ohos_cargo_crate("lib") {
|
||||
"sched",
|
||||
"signal",
|
||||
"socket",
|
||||
"syslog",
|
||||
"term",
|
||||
"time",
|
||||
"ucontext",
|
||||
|
||||
+542
-10
@@ -1,20 +1,549 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](https://semver.org/).
|
||||
|
||||
## [0.26.4] - 2023-08-28
|
||||
# Change Log
|
||||
|
||||
## [0.30.1] - 2025-05-04
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed an unintended API change in release 0.26.3, due to the upgrade of the
|
||||
bitflags dependency.
|
||||
([#2117](https://github.com/nix-rust/nix/pull/2117))
|
||||
- doc.rs build
|
||||
([#2634](https://github.com/nix-rust/nix/pull/2634))
|
||||
|
||||
|
||||
## [0.30.0] - 2025-04-29
|
||||
|
||||
|
||||
### Added
|
||||
|
||||
- Add socket option `IPV6_PKTINFO` for BSDs/Linux/Android, also
|
||||
`IPV6_RECVPKTINFO` for DragonFlyBSD
|
||||
([#2113](https://github.com/nix-rust/nix/pull/2113))
|
||||
- Add `fcntl`'s `F_PREALLOCATE` constant for Apple targets.
|
||||
([#2393](https://github.com/nix-rust/nix/pull/2393))
|
||||
- Improve support for extracting the TTL / Hop Limit from incoming packets
|
||||
and support for DSCP (ToS / Traffic Class).
|
||||
([#2425](https://github.com/nix-rust/nix/pull/2425))
|
||||
- Add socket option IP_TOS (nix::sys::socket::sockopt::IpTos) IPV6_TCLASS
|
||||
(nix::sys::socket::sockopt::Ipv6TClass) on Android/FreeBSD
|
||||
([#2464](https://github.com/nix-rust/nix/pull/2464))
|
||||
- Add `SeekData` and `SeekHole` to `Whence` for hurd and apple targets
|
||||
([#2473](https://github.com/nix-rust/nix/pull/2473))
|
||||
- Add `From` trait implementation between `SocketAddr` and `Sockaddr`,
|
||||
`Sockaddr6` ([#2474](https://github.com/nix-rust/nix/pull/2474))
|
||||
- Added wrappers for `posix_spawn` API
|
||||
([#2475](https://github.com/nix-rust/nix/pull/2475))
|
||||
- Add the support for Emscripten.
|
||||
([#2477](https://github.com/nix-rust/nix/pull/2477))
|
||||
- Add fcntl constant `F_RDADVISE` for Apple target
|
||||
([#2480](https://github.com/nix-rust/nix/pull/2480))
|
||||
- Add fcntl constant `F_RDAHEAD` for Apple target
|
||||
([#2482](https://github.com/nix-rust/nix/pull/2482))
|
||||
- Add `F_LOG2PHYS` and `F_LOG2PHYS_EXT` for Apple target
|
||||
([#2483](https://github.com/nix-rust/nix/pull/2483))
|
||||
- `MAP_SHARED_VALIDATE` was added for all linux targets. & `MAP_SYNC` was added
|
||||
for linux with the exclusion of mips architecures, and uclibc
|
||||
([#2499](https://github.com/nix-rust/nix/pull/2499))
|
||||
- Add `getregs()`/`getregset()`/`setregset()` for Linux/musl/aarch64
|
||||
([#2502](https://github.com/nix-rust/nix/pull/2502))
|
||||
- Add FcntlArgs `F_TRANSFEREXTENTS` constant for Apple targets
|
||||
([#2504](https://github.com/nix-rust/nix/pull/2504))
|
||||
- Add `MapFlags::MAP_STACK` in `sys::man` for netbsd
|
||||
([#2526](https://github.com/nix-rust/nix/pull/2526))
|
||||
- Add support for `libc::LOCAL_PEERTOKEN` in `getsockopt`.
|
||||
([#2529](https://github.com/nix-rust/nix/pull/2529))
|
||||
- Add support for `syslog`, `openlog`, `closelog` on all `unix`.
|
||||
([#2537](https://github.com/nix-rust/nix/pull/2537))
|
||||
- Add the `TCP_FUNCTION_BLK` sockopt, on FreeBSD.
|
||||
([#2539](https://github.com/nix-rust/nix/pull/2539))
|
||||
- Implements `Into<OwnedFd>` for `PtyMaster/Fanotify/Inotify/SignalFd/TimerFd`
|
||||
([#2548](https://github.com/nix-rust/nix/pull/2548))
|
||||
- Add `MremapFlags::MREMAP_DONTUNMAP` to `sys::mman::mremap` for linux target.
|
||||
([#2555](https://github.com/nix-rust/nix/pull/2555))
|
||||
- Added `sockopt_impl!` to the public API. It's now possible for users to
|
||||
define
|
||||
their own sockopts without needing to make a PR to Nix.
|
||||
([#2556](https://github.com/nix-rust/nix/pull/2556))
|
||||
- Add the `TCP_FUNCTION_ALIAS` sockopt, on FreeBSD.
|
||||
([#2558](https://github.com/nix-rust/nix/pull/2558))
|
||||
- Add `sys::mman::MmapAdvise` `MADV_PAGEOUT`, `MADV_COLD`, `MADV_WIPEONFORK`,
|
||||
`MADV_KEEPONFORK` for Linux and Android targets
|
||||
([#2559](https://github.com/nix-rust/nix/pull/2559))
|
||||
- Add socket protocol `Sctp`, as well as `MSG_NOTIFICATION` for non-Android
|
||||
Linux targets. ([#2562](https://github.com/nix-rust/nix/pull/2562))
|
||||
- Added `from_owned_fd` constructor to `EventFd`
|
||||
([#2563](https://github.com/nix-rust/nix/pull/2563))
|
||||
- Add `sys::mman::MmapAdvise` `MADV_POPULATE_READ`, `MADV_POPULATE_WRITE` for
|
||||
Linux and Android targets
|
||||
([#2565](https://github.com/nix-rust/nix/pull/2565))
|
||||
- Added `from_owned_fd` constructor to
|
||||
`PtyMaster/Fanotify/Inotify/SignalFd/TimerFd`
|
||||
([#2566](https://github.com/nix-rust/nix/pull/2566))
|
||||
- Added `FcntlArg::F_READAHEAD` for FreeBSD target
|
||||
([#2569](https://github.com/nix-rust/nix/pull/2569))
|
||||
- Added `sockopt::LingerSec` for Apple targets
|
||||
([#2572](https://github.com/nix-rust/nix/pull/2572))
|
||||
- Added `sockopt::EsclBind` for solarish targets
|
||||
([#2573](https://github.com/nix-rust/nix/pull/2573))
|
||||
- Exposed the ```std::os::fd::AsRawFd``` trait method for
|
||||
```nix::sys::fanotify::Fanotify``` struct
|
||||
([#2575](https://github.com/nix-rust/nix/pull/2575))
|
||||
- Add support for syslog's `setlogmask` on all `unix`.
|
||||
([#2579](https://github.com/nix-rust/nix/pull/2579))
|
||||
- Added Fuchsia support for `ioctl`.
|
||||
([#2580](https://github.com/nix-rust/nix/pull/2580))
|
||||
- Add ```sys::socket::SockProtocol::EthIp```,
|
||||
```sys::socket::SockProtocol::EthIpv6```,
|
||||
```sys::socket::SockProtocol::EthLoop```
|
||||
([#2581](https://github.com/nix-rust/nix/pull/2581))
|
||||
- Add OpenHarmony target into CI and Update documents.
|
||||
([#2599](https://github.com/nix-rust/nix/pull/2599))
|
||||
- Added the TcpMaxSeg `setsockopt` option for apple targets
|
||||
([#2603](https://github.com/nix-rust/nix/pull/2603))
|
||||
- Add `FilAttach` and `FilDetach` to socket::sockopt for Illumos
|
||||
([#2611](https://github.com/nix-rust/nix/pull/2611))
|
||||
- Add `PeerPidfd` (`SO_PEERPIDFD`) to `socket::sockopt` for Linux
|
||||
([#2620](https://github.com/nix-rust/nix/pull/2620))
|
||||
- Added `socket::sockopt::AttachReusePortCbpf` for Linux
|
||||
([#2621](https://github.com/nix-rust/nix/pull/2621))
|
||||
- Add `ptrace::syscall_info` for linux/glibc
|
||||
([#2627](https://github.com/nix-rust/nix/pull/2627))
|
||||
|
||||
### Changed
|
||||
|
||||
- Module sys/signal now adopts I/O safety
|
||||
([#1936](https://github.com/nix-rust/nix/pull/1936))
|
||||
- Change the type of the `name` argument of `memfd_create()` from `&CStr` to
|
||||
`<P: NixPath>(name: &P)` ([#2431](https://github.com/nix-rust/nix/pull/2431))
|
||||
- Public interfaces in `fcntl.rs` and `dir.rs` now use I/O-safe types.
|
||||
([#2434](https://github.com/nix-rust/nix/pull/2434))
|
||||
- Module `sys/stat` now adopts I/O safety.
|
||||
([#2439](https://github.com/nix-rust/nix/pull/2439))
|
||||
- Module unistd now adopts I/O safety.
|
||||
([#2440](https://github.com/nix-rust/nix/pull/2440))
|
||||
- Module sys/fanotify now adopts I/O safety
|
||||
([#2443](https://github.com/nix-rust/nix/pull/2443))
|
||||
- Socket option `IpTos` has been renamed to `Ipv4Tos`, the old symbol is
|
||||
deprecated since 0.30.0 ([#2465](https://github.com/nix-rust/nix/pull/2465))
|
||||
- Rename Flags `EventFlag` to `EvFlags`, and `MemFdCreateFlag` to `MFdFlags`
|
||||
([#2476](https://github.com/nix-rust/nix/pull/2476))
|
||||
- Made `nix::sys::socket::UnknownCmsg` public and more readable
|
||||
([#2520](https://github.com/nix-rust/nix/pull/2520))
|
||||
- recvmsg: take slice for cmsg_buffer instead of Vec
|
||||
([#2524](https://github.com/nix-rust/nix/pull/2524))
|
||||
- linkat: allow distinct types for path arguments
|
||||
([#2582](https://github.com/nix-rust/nix/pull/2582))
|
||||
|
||||
### Fixed
|
||||
|
||||
- Disable unsupported signals on sparc-linux
|
||||
([#2454](https://github.com/nix-rust/nix/pull/2454))
|
||||
- Fix cmsg_len() return type on OpenHarmony
|
||||
([#2456](https://github.com/nix-rust/nix/pull/2456))
|
||||
- The `ns` argument of `sys::prctl::set_timerslack()` should be of type
|
||||
`c_ulong` ([#2505](https://github.com/nix-rust/nix/pull/2505))
|
||||
- Properly exclude NUL characters from `OSString`s returned by `getsockopt`.
|
||||
([#2557](https://github.com/nix-rust/nix/pull/2557))
|
||||
- Fixes the build on OpenHarmony
|
||||
([#2587](https://github.com/nix-rust/nix/pull/2587))
|
||||
|
||||
### Removed
|
||||
|
||||
- Type `SigevNotify` is no longer `PartialEq`, `Eq` and `Hash` due to the use
|
||||
of `BorrowedFd` ([#1936](https://github.com/nix-rust/nix/pull/1936))
|
||||
- `EventFd::defuse()` is removed because it does nothing, `EventFd::arm()` is
|
||||
also removed for symmetry reasons.
|
||||
([#2452](https://github.com/nix-rust/nix/pull/2452))
|
||||
- Removed the `Copy` trait from `PollFd`
|
||||
([#2631](https://github.com/nix-rust/nix/pull/2631))
|
||||
|
||||
|
||||
## [0.29.0] - 2024-05-24
|
||||
|
||||
|
||||
### Added
|
||||
|
||||
- Add `getregset()/setregset()` for Linux/glibc/x86/x86_64/aarch64/riscv64 and
|
||||
`getregs()/setregs()` for Linux/glibc/aarch64/riscv64
|
||||
([#2044](https://github.com/nix-rust/nix/pull/2044))
|
||||
- Add socket option Ipv6Ttl for apple targets.
|
||||
([#2287](https://github.com/nix-rust/nix/pull/2287))
|
||||
- Add socket option UtunIfname.
|
||||
([#2325](https://github.com/nix-rust/nix/pull/2325))
|
||||
- make SigAction repr(transparent) & can be converted to the libc raw type
|
||||
([#2326](https://github.com/nix-rust/nix/pull/2326))
|
||||
- Add `From` trait implementation for conversions between `sockaddr_in` and
|
||||
`SockaddrIn`, `sockaddr_in6` and `SockaddrIn6`
|
||||
([#2328](https://github.com/nix-rust/nix/pull/2328))
|
||||
- Add socket option ReusePortLb for FreeBSD.
|
||||
([#2332](https://github.com/nix-rust/nix/pull/2332))
|
||||
- Added support for openat2 on linux.
|
||||
([#2339](https://github.com/nix-rust/nix/pull/2339))
|
||||
- Add if_indextoname function.
|
||||
([#2340](https://github.com/nix-rust/nix/pull/2340))
|
||||
- Add `mount` and `unmount` API for apple targets.
|
||||
([#2347](https://github.com/nix-rust/nix/pull/2347))
|
||||
- Added `_PC_MIN_HOLE_SIZE` for `pathconf` and `fpathconf`.
|
||||
([#2349](https://github.com/nix-rust/nix/pull/2349))
|
||||
- Added `impl AsFd for pty::PtyMaster`
|
||||
([#2355](https://github.com/nix-rust/nix/pull/2355))
|
||||
- Add `open` flag `O_SEARCH` to AIX, Empscripten, FreeBSD, Fuchsia, solarish,
|
||||
WASI ([#2374](https://github.com/nix-rust/nix/pull/2374))
|
||||
- Add prctl function `prctl_set_vma_anon_name` for Linux/Android.
|
||||
([#2378](https://github.com/nix-rust/nix/pull/2378))
|
||||
- Add `sync(2)` for `apple_targets/solarish/haiku/aix/hurd`, `syncfs(2)` for
|
||||
`hurd` and `fdatasync(2)` for `aix/hurd`
|
||||
([#2379](https://github.com/nix-rust/nix/pull/2379))
|
||||
- Add fdatasync support for Apple targets.
|
||||
([#2380](https://github.com/nix-rust/nix/pull/2380))
|
||||
- Add `fcntl::OFlag::O_PATH` for FreeBSD and Fuchsia
|
||||
([#2382](https://github.com/nix-rust/nix/pull/2382))
|
||||
- Added `PathconfVar::MIN_HOLE_SIZE` for apple_targets.
|
||||
([#2388](https://github.com/nix-rust/nix/pull/2388))
|
||||
- Add `open` flag `O_SEARCH` to apple_targets
|
||||
([#2391](https://github.com/nix-rust/nix/pull/2391))
|
||||
- `O_DSYNC` may now be used with `aio_fsync` and `fcntl` on FreeBSD.
|
||||
([#2404](https://github.com/nix-rust/nix/pull/2404))
|
||||
- Added `Flock::relock` for upgrading and downgrading locks.
|
||||
([#2407](https://github.com/nix-rust/nix/pull/2407))
|
||||
|
||||
### Changed
|
||||
|
||||
- Change the `ForkptyResult` type to the following repr so that the
|
||||
uninitialized
|
||||
`master` field won't be accessed in the child process:
|
||||
|
||||
```rs
|
||||
pub enum ForkptyResult {
|
||||
Parent {
|
||||
child: Pid,
|
||||
master: OwnedFd,
|
||||
},
|
||||
Child,
|
||||
}
|
||||
``` ([#2315](https://github.com/nix-rust/nix/pull/2315))
|
||||
- Updated `cfg_aliases` dependency from version 0.1 to 0.2
|
||||
([#2322](https://github.com/nix-rust/nix/pull/2322))
|
||||
- Change the signature of `ptrace::write` and `ptrace::write_user` to make them
|
||||
safe ([#2324](https://github.com/nix-rust/nix/pull/2324))
|
||||
- Allow use of `SignalFd` through shared reference
|
||||
|
||||
Like with many other file descriptors, concurrent use of signalfds is safe.
|
||||
Changing the signal mask of and reading signals from a signalfd can now be
|
||||
done
|
||||
with the `SignalFd` API even if other references to it exist.
|
||||
([#2367](https://github.com/nix-rust/nix/pull/2367))
|
||||
- Changed tee, splice and vmsplice RawFd arguments to AsFd.
|
||||
([#2387](https://github.com/nix-rust/nix/pull/2387))
|
||||
- Added I/O safety to the sys/aio module. Most functions that previously
|
||||
accepted a `AsRawFd` argument now accept an `AsFd` instead.
|
||||
([#2401](https://github.com/nix-rust/nix/pull/2401))
|
||||
- `RecvMsg::cmsgs()` now returns a `Result`, and checks that cmsgs were not
|
||||
truncated. ([#2413](https://github.com/nix-rust/nix/pull/2413))
|
||||
|
||||
### Fixed
|
||||
|
||||
- No longer panics when the `fanotify` queue overflows.
|
||||
([#2399](https://github.com/nix-rust/nix/pull/2399))
|
||||
- Fixed ControlMessageOwned::UdpGroSegments wrapped type from u16 to i32 to
|
||||
reflect the used kernel's one.
|
||||
([#2406](https://github.com/nix-rust/nix/pull/2406))
|
||||
|
||||
|
||||
## [0.28.0] - 2024-02-24
|
||||
|
||||
|
||||
### Added
|
||||
|
||||
- Added `mkdtemp` wrapper ([#1297](https://github.com/nix-rust/nix/pull/1297))
|
||||
- Add associated constants `UTIME_OMIT` `UTIME_NOW` for `TimeSpec`
|
||||
([#1879](https://github.com/nix-rust/nix/pull/1879))
|
||||
- Added `EventFd` type. ([#1945](https://github.com/nix-rust/nix/pull/1945))
|
||||
- - Added `impl From<Signal> for SigSet`.
|
||||
- Added `impl std::ops::BitOr for SigSet`.
|
||||
- Added `impl std::ops::BitOr for Signal`.
|
||||
- Added `impl std::ops::BitOr<Signal> for SigSet`
|
||||
|
||||
([#1959](https://github.com/nix-rust/nix/pull/1959))
|
||||
- Added `TlsGetRecordType` control message type and corresponding enum for
|
||||
linux ([#2065](https://github.com/nix-rust/nix/pull/2065))
|
||||
- Added `Ipv6HopLimit` to `::nix::sys::socket::ControlMessage` for Linux,
|
||||
MacOS, FreeBSD, DragonflyBSD, Android, iOS and Haiku.
|
||||
([#2074](https://github.com/nix-rust/nix/pull/2074))
|
||||
- Added `Icmp` and `IcmpV6` to `SockProtocol`
|
||||
([#2103](https://github.com/nix-rust/nix/pull/2103))
|
||||
- Added rfork support for FreeBSD in `unistd`
|
||||
([#2121](https://github.com/nix-rust/nix/pull/2121))
|
||||
- Added `MapFlags::map_hugetlb_with_size_log2` method for Linux targets
|
||||
([#2125](https://github.com/nix-rust/nix/pull/2125))
|
||||
- Added `mmap_anonymous` function
|
||||
([#2127](https://github.com/nix-rust/nix/pull/2127))
|
||||
- Added `mips32r6` and `mips64r6` support for signal, ioctl and ptrace
|
||||
([#2138](https://github.com/nix-rust/nix/pull/2138))
|
||||
- Added `F_GETPATH` FcntlFlags entry on Apple/NetBSD/DragonflyBSD for
|
||||
`::nix::fcntl`. ([#2142](https://github.com/nix-rust/nix/pull/2142))
|
||||
- Added `F_KINFO` FcntlFlags entry on FreeBSD for `::nix::fcntl`.
|
||||
([#2152](https://github.com/nix-rust/nix/pull/2152))
|
||||
- Added `F_GETPATH_NOFIRMLINK` and `F_BARRIERFSYNC` FcntlFlags entry
|
||||
on Apple for `::nix::fcntl`.
|
||||
([#2155](https://github.com/nix-rust/nix/pull/2155))
|
||||
- Added newtype `Flock` to automatically unlock a held flock upon drop.
|
||||
Added `Flockable` trait to represent valid types for `Flock`.
|
||||
([#2170](https://github.com/nix-rust/nix/pull/2170))
|
||||
- Added `SetSockOpt` impls to enable Linux Kernel TLS on a TCP socket and to
|
||||
import TLS parameters. ([#2175](https://github.com/nix-rust/nix/pull/2175))
|
||||
- - Added the `::nix::sys::socket::SocketTimestamp` enum for configuring the
|
||||
`TsClock` (a.k.a `SO_TS_CLOCK`) sockopt
|
||||
- Added FreeBSD's `ScmRealtime` and `ScmMonotonic` as new options in
|
||||
`::nix::sys::socket::ControlMessageOwned`
|
||||
|
||||
([#2187](https://github.com/nix-rust/nix/pull/2187))
|
||||
- Added new fanotify API: wrappers for `fanotify_init` and `fanotify_mark`
|
||||
([#2194](https://github.com/nix-rust/nix/pull/2194))
|
||||
- Added `SpecialCharacterindices` support for haiku.
|
||||
([#2195](https://github.com/nix-rust/nix/pull/2195))
|
||||
- Added `sys::sendfile` support for solaris/illumos.
|
||||
([#2198](https://github.com/nix-rust/nix/pull/2198))
|
||||
- impl Display for InterfaceFlags
|
||||
([#2206](https://github.com/nix-rust/nix/pull/2206))
|
||||
- Added `sendfilev` in sys::sendfile for solarish
|
||||
([#2207](https://github.com/nix-rust/nix/pull/2207))
|
||||
- Added `fctrl::SealFlag::F_SEAL_FUTURE_WRITE`
|
||||
([#2213](https://github.com/nix-rust/nix/pull/2213))
|
||||
- Added `Ipv6MulticastHops` as socket option to set and read.
|
||||
([#2234](https://github.com/nix-rust/nix/pull/2234))
|
||||
- Enable `ControlMessageOwned::Ipv4RecvIf` and
|
||||
`ControlMessageOwned::Ipv4RecvDstAddr` for DragonFlyBSD
|
||||
([#2240](https://github.com/nix-rust/nix/pull/2240))
|
||||
- `ClockId::set_time()` and `time::clock_settime()` are now enabled on macOS
|
||||
([#2241](https://github.com/nix-rust/nix/pull/2241))
|
||||
- Added `IpBindAddressNoPort` sockopt to support `IP_BIND_ADDRESS_NO_PORT`
|
||||
available on linux. ([#2244](https://github.com/nix-rust/nix/pull/2244))
|
||||
- Enable `MapFlags::map_hugetlb_with_size_log2` method for Android/Fuchsia
|
||||
([#2245](https://github.com/nix-rust/nix/pull/2245))
|
||||
- Added `TcpFastOpenConnect` sockopt to support `TCP_FASTOPEN_CONNECT`
|
||||
available on linux. ([#2247](https://github.com/nix-rust/nix/pull/2247))
|
||||
- Add `reboot(2)` for OpenBSD/NetBSD
|
||||
([#2251](https://github.com/nix-rust/nix/pull/2251))
|
||||
- Added new `MemFdCreateFlag` constants to `sys::memfd` on Linux and Android
|
||||
related to hugetlbfs support.
|
||||
([#2252](https://github.com/nix-rust/nix/pull/2252))
|
||||
- Expose the inner fd of `Kqueue` through:
|
||||
|
||||
* impl AsFd for Kqueue
|
||||
* impl From\<Kqueue\> for OwnedFd
|
||||
|
||||
([#2258](https://github.com/nix-rust/nix/pull/2258))
|
||||
- Added `sys::eventfd` support on FreeBSD
|
||||
([#2259](https://github.com/nix-rust/nix/pull/2259))
|
||||
- Added `MmapFlags::MAP_FIXED` constant in `sys::mman` for netbsd and openbsd
|
||||
([#2260](https://github.com/nix-rust/nix/pull/2260))
|
||||
- Added the `SO_LISTENQLIMIT` sockopt.
|
||||
([#2263](https://github.com/nix-rust/nix/pull/2263))
|
||||
- Enable the `AT_EMPTY_PATH` flag for the `fchownat()` function
|
||||
([#2267](https://github.com/nix-rust/nix/pull/2267))
|
||||
- Add `AtFlags::AT_EMPTY_PATH` for FreeBSD and Hurd
|
||||
([#2270](https://github.com/nix-rust/nix/pull/2270))
|
||||
- Enable `OFlag::O_DIRECTORY for Solarish
|
||||
([#2275](https://github.com/nix-rust/nix/pull/2275))
|
||||
- Added the `Backlog` wrapper type for the `listen` call.
|
||||
([#2276](https://github.com/nix-rust/nix/pull/2276))
|
||||
- Add `clock_nanosleep()` ([#2277](https://github.com/nix-rust/nix/pull/2277))
|
||||
- Enabled `O_DIRECT` in `fcntl::OFlags` for solarish
|
||||
([#2278](https://github.com/nix-rust/nix/pull/2278))
|
||||
- Added a new API sigsuspend.
|
||||
([#2279](https://github.com/nix-rust/nix/pull/2279))
|
||||
- - Added `errno::Errno::set` function
|
||||
- Added `errno::Errno::set_raw` function
|
||||
- Added `errno::Errno::last_raw` function
|
||||
- Added `errno::Errno::from_raw` function
|
||||
|
||||
([#2283](https://github.com/nix-rust/nix/pull/2283))
|
||||
- Enable the `AT_EMPTY_PATH` flag for the `linkat()` function
|
||||
([#2284](https://github.com/nix-rust/nix/pull/2284))
|
||||
- Enable unistd::{sync, syncfs} for Android
|
||||
([#2296](https://github.com/nix-rust/nix/pull/2296))
|
||||
|
||||
### Changed
|
||||
|
||||
- `poll` now takes `PollTimeout` replacing `libc::c_int`.
|
||||
([#1876](https://github.com/nix-rust/nix/pull/1876))
|
||||
- Deprecated `sys::eventfd::eventfd`.
|
||||
([#1945](https://github.com/nix-rust/nix/pull/1945))
|
||||
- `mmap`, `mmap_anonymous`, `munmap`, `mremap`, `madvise`, `msync`, `mprotect`,
|
||||
`munlock` and `mlock` updated to use `NonNull`.
|
||||
([#2000](https://github.com/nix-rust/nix/pull/2000))
|
||||
- `mmap` function now accepts `F` instead of `Option<F>`
|
||||
([#2127](https://github.com/nix-rust/nix/pull/2127))
|
||||
- `PollFd::new` now takes a `BorrowedFd` argument, with relaxed lifetime
|
||||
requirements relative to the previous version.
|
||||
([#2134](https://github.com/nix-rust/nix/pull/2134))
|
||||
- `FdSet::{insert, remove, contains}` now take `BorrowedFd` arguments, and have
|
||||
relaxed lifetime requirements relative to 0.27.1.
|
||||
([#2136](https://github.com/nix-rust/nix/pull/2136))
|
||||
- The following APIs now take an implementation of `AsFd` rather than a
|
||||
`RawFd`:
|
||||
|
||||
- `unistd::tcgetpgrp`
|
||||
- `unistd::tcsetpgrp`
|
||||
- `unistd::fpathconf`
|
||||
- `unistd::ttyname`
|
||||
- `unistd::getpeereid` ([#2137](https://github.com/nix-rust/nix/pull/2137))
|
||||
- Changed `openat()` and `Dir::openat()`, now take optional `dirfd`s
|
||||
([#2139](https://github.com/nix-rust/nix/pull/2139))
|
||||
- The MSRV is now 1.69 ([#2144](https://github.com/nix-rust/nix/pull/2144))
|
||||
- Changed function `SockaddrIn::ip()` to return `net::Ipv4Addr` and refactored
|
||||
`SocketAddrV6::ip()` to be `const`
|
||||
([#2151](https://github.com/nix-rust/nix/pull/2151))
|
||||
- The following APIs now take optional `dirfd`s:
|
||||
|
||||
- `readlinkat()`
|
||||
- `fstatat()`
|
||||
- `mknodat()`
|
||||
- `mkdirat()`
|
||||
- `execveat()`
|
||||
|
||||
([#2157](https://github.com/nix-rust/nix/pull/2157))
|
||||
- `Epoll::wait` now takes `EpollTimeout` replacing `isize`.
|
||||
([#2202](https://github.com/nix-rust/nix/pull/2202))
|
||||
- - Deprecated `errno::errno()` function (use `Errno::last_raw()`)
|
||||
- Deprecated `errno::from_i32()` function (use `Errno::from_raw()`)
|
||||
- Deprecated `errno::Errno::from_i32()` function (use `Errno::from_raw()`)
|
||||
|
||||
([#2283](https://github.com/nix-rust/nix/pull/2283))
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix `SigSet` incorrect implementation of `Eq`, `PartialEq` and `Hash`
|
||||
([#1946](https://github.com/nix-rust/nix/pull/1946))
|
||||
- Fixed `::sys::socket::sockopt::IpMulticastTtl` by fixing the value of optlen
|
||||
passed to `libc::setsockopt` and added tests.
|
||||
([#2072](https://github.com/nix-rust/nix/pull/2072))
|
||||
- Fixed the function signature of `recvmmsg`, potentially causing UB
|
||||
([#2119](https://github.com/nix-rust/nix/pull/2119))
|
||||
- Fix `SignalFd::set_mask`. In 0.27.0 it would actually close the file
|
||||
descriptor. ([#2141](https://github.com/nix-rust/nix/pull/2141))
|
||||
- Fixed UnixAddr::new for haiku, it did not record the `sun_len` value as
|
||||
needed.
|
||||
Fixed `sys::socket::addr::from_raw_parts` and
|
||||
`sys::socket::Sockaddrlike::len` build for solaris.
|
||||
([#2242](https://github.com/nix-rust/nix/pull/2242))
|
||||
- Fixed solaris build globally.
|
||||
([#2248](https://github.com/nix-rust/nix/pull/2248))
|
||||
- Changed the `dup3` wrapper to perform a real call to `dup3` instead of
|
||||
emulating it via `dup2` and `fcntl` to get rid of race condition
|
||||
([#2268](https://github.com/nix-rust/nix/pull/2268))
|
||||
- Fixed `::unistd::Group::members` using read_unaligned to avoid crash on
|
||||
misaligned pointers ([#2311](https://github.com/nix-rust/nix/pull/2311))
|
||||
|
||||
### Removed
|
||||
|
||||
- The `FchownatFlags` type has been deprecated, please use `AtFlags` instead.
|
||||
([#2267](https://github.com/nix-rust/nix/pull/2267))
|
||||
- Removed the `dup3` wrapper on macOS, which was emulated via `dup2` and
|
||||
`fcntl` and could cause a race condition. The `dup3` system call is not
|
||||
supported on macOS. ([#2268](https://github.com/nix-rust/nix/pull/2268))
|
||||
- The `LinkatFlags` type has been deprecated, please use `AtFlags` instead.
|
||||
([#2284](https://github.com/nix-rust/nix/pull/2284))
|
||||
|
||||
|
||||
## [0.27.1] - 2023-08-28
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed generating the documentation on docs.rs.
|
||||
([#2111](https://github.com/nix-rust/nix/pull/2111))
|
||||
|
||||
## [0.27.0] - 2023-08-28
|
||||
### Added
|
||||
- Added `AT_EACCESS` to `AtFlags` on all platforms but android
|
||||
([#1995](https://github.com/nix-rust/nix/pull/1995))
|
||||
- Add `PF_ROUTE` to `SockType` on macOS, iOS, all of the BSDs, Fuchsia, Haiku, Illumos.
|
||||
([#1867](https://github.com/nix-rust/nix/pull/1867))
|
||||
- Added `nix::ucontext` module on `aarch64-unknown-linux-gnu`.
|
||||
(#[1662](https://github.com/nix-rust/nix/pull/1662))
|
||||
- Added `CanRaw` to `SockProtocol` and `CanBcm` as a separate `SocProtocol` constant.
|
||||
([#1912](https://github.com/nix-rust/nix/pull/1912))
|
||||
- Added `Generic` and `NFLOG` to `SockProtocol`.
|
||||
([#2092](https://github.com/nix-rust/nix/pull/2092))
|
||||
- Added `mq_timedreceive` to `::nix::mqueue`.
|
||||
([#1966])(https://github.com/nix-rust/nix/pull/1966)
|
||||
- Added `LocalPeerPid` to `nix::sys::socket::sockopt` for macOS. ([#1967](https://github.com/nix-rust/nix/pull/1967))
|
||||
- Added `TFD_TIMER_CANCEL_ON_SET` to `::nix::sys::time::TimerSetTimeFlags` on Linux and Android.
|
||||
([#2040](https://github.com/nix-rust/nix/pull/2040))
|
||||
- Added `SOF_TIMESTAMPING_OPT_ID` and `SOF_TIMESTAMPING_OPT_TSONLY` to `nix::sys::socket::TimestampingFlag`.
|
||||
([#2048](https://github.com/nix-rust/nix/pull/2048))
|
||||
- Enabled socket timestamping options on Android. ([#2077](https://github.com/nix-rust/nix/pull/2077))
|
||||
- Added vsock support for macOS ([#2056](https://github.com/nix-rust/nix/pull/2056))
|
||||
- Added `SO_SETFIB` and `SO_USER_COOKIE` to `nix::sys::socket::sockopt` for FreeBSD.
|
||||
([#2085](https://github.com/nix-rust/nix/pull/2085))
|
||||
- Added `SO_RTABLE` for OpenBSD and `SO_ACCEPTFILTER` for FreeBSD/NetBSD to `nix::sys::socket::sockopt`.
|
||||
([#2085](https://github.com/nix-rust/nix/pull/2085))
|
||||
- Added `MSG_WAITFORONE` to `MsgFlags` on Android, Fuchsia, Linux, NetBSD,
|
||||
FreeBSD, OpenBSD, and Solaris.
|
||||
([#2014](https://github.com/nix-rust/nix/pull/2014))
|
||||
- Added `SO_TS_CLOCK` for FreeBSD to `nix::sys::socket::sockopt`.
|
||||
([#2093](https://github.com/nix-rust/nix/pull/2093))
|
||||
- Added support for prctl in Linux.
|
||||
(#[1550](https://github.com/nix-rust/nix/pull/1550))
|
||||
- `nix::socket` and `nix::select` are now available on Redox.
|
||||
([#2012](https://github.com/nix-rust/nix/pull/2012))
|
||||
- Implemented AsFd, AsRawFd, FromRawFd, and IntoRawFd for `mqueue::MqdT`.
|
||||
([#2097](https://github.com/nix-rust/nix/pull/2097))
|
||||
- Add the ability to set `kevent_flags` on `SigEvent`.
|
||||
([#1731](https://github.com/nix-rust/nix/pull/1731))
|
||||
|
||||
### Changed
|
||||
|
||||
- All Cargo features have been removed from the default set. Users will need to
|
||||
specify which features they depend on in their Cargo.toml.
|
||||
([#2091](https://github.com/nix-rust/nix/pull/2091))
|
||||
- Implemented I/O safety for many, but not all, of Nix's APIs. Many public
|
||||
functions argument and return types have changed:
|
||||
| Original Type | New Type |
|
||||
| ------------- | --------------------- |
|
||||
| AsRawFd | AsFd |
|
||||
| RawFd | BorrowedFd or OwnedFd |
|
||||
|
||||
(#[1906](https://github.com/nix-rust/nix/pull/1906))
|
||||
- Use I/O safety with `copy_file_range`, and expose it on FreeBSD.
|
||||
(#[1906](https://github.com/nix-rust/nix/pull/1906))
|
||||
- The MSRV is now 1.65
|
||||
([#1862](https://github.com/nix-rust/nix/pull/1862))
|
||||
([#2104](https://github.com/nix-rust/nix/pull/2104))
|
||||
- The epoll interface now uses a type.
|
||||
([#1882](https://github.com/nix-rust/nix/pull/1882))
|
||||
- With I/O-safe type applied in `pty::OpenptyResult` and `pty::ForkptyResult`,
|
||||
users no longer need to manually close the file descriptors in these types.
|
||||
([#1921](https://github.com/nix-rust/nix/pull/1921))
|
||||
- Refactored `name` parameter of `mq_open` and `mq_unlink` to be generic over
|
||||
`NixPath`.
|
||||
([#2102](https://github.com/nix-rust/nix/pull/2102)).
|
||||
- Made `clone` unsafe, like `fork`.
|
||||
([#1993](https://github.com/nix-rust/nix/pull/1993))
|
||||
|
||||
### Removed
|
||||
|
||||
- `sys::event::{kevent, kevent_ts}` are deprecated in favor of
|
||||
`sys::kevent::Kqueue::kevent`, and `sys::event::kqueue` is deprecated in
|
||||
favor of `sys::kevent::Kqueue::new`.
|
||||
([#1943](https://github.com/nix-rust/nix/pull/1943))
|
||||
- Removed deprecated IoVec API.
|
||||
([#1855](https://github.com/nix-rust/nix/pull/1855))
|
||||
- Removed deprecated net APIs.
|
||||
([#1861](https://github.com/nix-rust/nix/pull/1861))
|
||||
- `nix::sys::signalfd::signalfd` is deprecated. Use
|
||||
`nix::sys::signalfd::SignalFd` instead.
|
||||
([#1938](https://github.com/nix-rust/nix/pull/1938))
|
||||
- Removed `SigEvent` support on Fuchsia, where it was unsound.
|
||||
([#2079](https://github.com/nix-rust/nix/pull/2079))
|
||||
- Removed `flock` from `::nix::fcntl` on Solaris.
|
||||
([#2082](https://github.com/nix-rust/nix/pull/2082))
|
||||
|
||||
## [0.26.3] - 2023-08-27
|
||||
|
||||
### Fixed
|
||||
- Fix: send `ETH_P_ALL` in htons format
|
||||
- Fix: send `ETH_P_ALL` in htons format
|
||||
([#1925](https://github.com/nix-rust/nix/pull/1925))
|
||||
- Fix: `recvmsg` now sets the length of the received `sockaddr_un` field
|
||||
correctly on Linux platforms. ([#2041](https://github.com/nix-rust/nix/pull/2041))
|
||||
@@ -27,8 +556,11 @@ This project adheres to [Semantic Versioning](https://semver.org/).
|
||||
([#2095](https://github.com/nix-rust/nix/pull/2095))
|
||||
|
||||
## [0.26.2] - 2023-01-18
|
||||
|
||||
### Fixed
|
||||
- Fix `SockaddrIn6` bug that was swapping flowinfo and scope_id byte ordering.
|
||||
|
||||
- Fix `SockaddrIn6` bug that was swapping `flowinfo` and `scope_id` byte
|
||||
ordering.
|
||||
([#1964](https://github.com/nix-rust/nix/pull/1964))
|
||||
|
||||
## [0.26.1] - 2022-11-29
|
||||
@@ -99,7 +631,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
|
||||
([#1824](https://github.com/nix-rust/nix/pull/1824))
|
||||
- Workaround XNU bug causing netmasks returned by `getifaddrs` to misbehave.
|
||||
([#1788](https://github.com/nix-rust/nix/pull/1788))
|
||||
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed deprecated error constants and conversions.
|
||||
@@ -232,7 +764,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
|
||||
(#[1563](https://github.com/nix-rust/nix/pull/1563))
|
||||
- Added `process_vm_readv` and `process_vm_writev` on Android.
|
||||
(#[1557](https://github.com/nix-rust/nix/pull/1557))
|
||||
- Added `nix::uncontext` module on s390x.
|
||||
- Added `nix::ucontext` module on s390x.
|
||||
(#[1662](https://github.com/nix-rust/nix/pull/1662))
|
||||
- Implemented `Extend`, `FromIterator`, and `IntoIterator` for `SigSet` and
|
||||
added `SigSet::iter` and `SigSetIter`.
|
||||
|
||||
+37
-26
@@ -61,11 +61,32 @@ 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].
|
||||
you fix a bug, please add an appropriate note, every note should be a new markdown
|
||||
file under the [changelog directory][cl] stating the change made by your pull request,
|
||||
the filename should be in the following format:
|
||||
|
||||
[cl]: https://github.com/nix-rust/nix/blob/master/CHANGELOG.md
|
||||
[kacl]: https://github.com/olivierlacan/keep-a-changelog/tree/18adb5f5be7a898d046f6a4acb93e39dcf40c4ad
|
||||
```
|
||||
<PULL_REQUEST_ID>.<TYPE>.md
|
||||
```
|
||||
|
||||
These are 4 `TYPE`s available:
|
||||
|
||||
1. `added`
|
||||
2. `changed`
|
||||
3. `fixed`
|
||||
4. `removed`
|
||||
|
||||
Let's say you have added a new API to nix, then a change log like this should
|
||||
be added (assume it is PR #0)
|
||||
|
||||
```md
|
||||
# file: 0.added.md
|
||||
Added a new API xxx
|
||||
```
|
||||
|
||||
And having multiple change logs for one PR is allowed.
|
||||
|
||||
[cl]: https://github.com/nix-rust/nix/tree/master/changelog
|
||||
[pr-docs]: https://help.github.com/articles/using-pull-requests/
|
||||
|
||||
## Testing
|
||||
@@ -75,36 +96,26 @@ 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].
|
||||
environment. We also have continuous integration set up on [Cirrus-CI][cirrus-ci]
|
||||
and GitHub Action, which might find some issues on other platforms. The CI will
|
||||
run once you open a pull request.
|
||||
|
||||
[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
|
||||
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!
|
||||
possible! Other tests cannot be run under QEMU, which is used for some
|
||||
architectures. To skip them, add a `#[cfg_attr(qemu, ignore)]` attribute to
|
||||
the test.
|
||||
|
||||
## 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/
|
||||
## GitHub Merge Queues
|
||||
|
||||
We use GitHub merge queues to ensure that subtle merge conflicts won't result
|
||||
in failing code. If you add or remove a CI job, remember to adjust the
|
||||
required status checks in the repository's branch protection rules!
|
||||
|
||||
## API conventions
|
||||
|
||||
|
||||
+72
-4
@@ -17,8 +17,15 @@ We follow the conventions laid out in [Keep A CHANGELOG][kacl].
|
||||
|
||||
## libc constants, functions and structs
|
||||
|
||||
We do not define integer constants ourselves, but use or reexport them from the
|
||||
[libc crate][libc].
|
||||
We do not define ffi functions or their associated constants and types ourselves,
|
||||
but use or reexport them from the [libc crate][libc], if your PR uses something
|
||||
that does not exist in the libc crate, you should add it to libc first. Once
|
||||
your libc PR gets merged, you can adjust our `libc` dependency to include that
|
||||
libc change. Use a git dependency if necessary.
|
||||
|
||||
```toml
|
||||
libc = { git = "https://github.com/rust-lang/libc", rev = "the commit includes your libc PR", ... }
|
||||
```
|
||||
|
||||
We use the functions exported from [libc][libc] instead of writing our own
|
||||
`extern` declarations.
|
||||
@@ -37,6 +44,16 @@ impl SigSet {
|
||||
|
||||
When creating newtypes, we use Rust's `CamelCase` type naming convention.
|
||||
|
||||
## cfg gates
|
||||
|
||||
When creating operating-system-specific functionality, we gate it by
|
||||
`#[cfg(target_os = ...)]`. If **MORE THAN ONE operating system** is affected, we
|
||||
prefer to use the cfg aliases defined in build.rs, like `#[cfg(bsd)]`.
|
||||
|
||||
Please **DO NOT** use cfg aliases for **ONLY ONE** system as [they are bad][mismatched_target_os].
|
||||
|
||||
[mismatched_target_os]: https://rust-lang.github.io/rust-clippy/master/index.html#/mismatched_target_os
|
||||
|
||||
## Bitflags
|
||||
|
||||
Many C functions have flags parameters that are combined from constants using
|
||||
@@ -57,9 +74,9 @@ libc_bitflags!{
|
||||
PROT_READ;
|
||||
PROT_WRITE;
|
||||
PROT_EXEC;
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
PROT_GROWSDOWN;
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
PROT_GROWSUP;
|
||||
}
|
||||
}
|
||||
@@ -84,3 +101,54 @@ the variable.
|
||||
[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
|
||||
|
||||
## Pointer type casting
|
||||
|
||||
We prefer [`cast()`], [`cast_mut()`] and [`cast_const()`] to cast pointer types
|
||||
over the `as` keyword because it is much more difficult to accidentally change
|
||||
type or mutability that way.
|
||||
|
||||
[`cast()`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.cast
|
||||
[`cast_mut()`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.cast_mut
|
||||
[`cast_const()`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.cast_const
|
||||
|
||||
## Remove/deprecate an interface
|
||||
|
||||
In Nix, if we want to remove something, we don't do it immediately, instead, we
|
||||
deprecate it for at least one release before removing it.
|
||||
|
||||
To deprecate an interface, put the following attribute on the top of it:
|
||||
|
||||
```
|
||||
#[deprecated(since = "<Version>", note = "<Note to our user>")]
|
||||
```
|
||||
|
||||
`<Version>` is the version where this interface will be deprecated, in most
|
||||
cases, it will be the version of the next release. And a user-friendly note
|
||||
should be added. Normally, there should be a new interface that will replace
|
||||
the old one, so a note should be something like: "`<New Interface>` should be
|
||||
used instead".
|
||||
|
||||
## Where to put a test
|
||||
|
||||
If you want to add a test for a feature that is in `xxx.rs`, then the test should
|
||||
be put in the corresponding `test_xxx.rs` file unless you cannot do this, e.g.,
|
||||
the test involves private stuff and thus cannot be added outside of Nix, then
|
||||
it is allowed to leave the test in `xxx.rs`.
|
||||
|
||||
## Syscall/libc function error handling
|
||||
|
||||
Most syscall and libc functions return an [`ErrnoSentinel`][trait] value on error,
|
||||
we has a nice utility function [`Errno::result()`][util] to convert it to the
|
||||
Rusty `Result<T, Errno>` type, e.g., here is how `dup(2)` uses it:
|
||||
|
||||
```rs
|
||||
pub fn dup(oldfd: RawFd) -> Result<RawFd> {
|
||||
let res = unsafe { libc::dup(oldfd) };
|
||||
|
||||
Errno::result(res)
|
||||
}
|
||||
```
|
||||
|
||||
[trait]: https://docs.rs/nix/latest/nix/errno/trait.ErrnoSentinel.html
|
||||
[util]: https://docs.rs/nix/latest/nix/errno/enum.Errno.html#method.result
|
||||
|
||||
+25
-28
@@ -1,16 +1,17 @@
|
||||
[package]
|
||||
name = "nix"
|
||||
description = "Rust friendly bindings to *nix APIs"
|
||||
edition = "2018"
|
||||
version = "0.26.4"
|
||||
rust-version = "1.56"
|
||||
edition = "2021"
|
||||
version = "0.30.1"
|
||||
rust-version = "1.69"
|
||||
authors = ["The nix-rust Project Developers"]
|
||||
repository = "https://github.com/nix-rust/nix"
|
||||
license = "MIT"
|
||||
categories = ["os::unix-apis"]
|
||||
include = ["src/**/*", "test/**/*", "LICENSE", "README.md", "CHANGELOG.md"]
|
||||
include = ["build.rs", "src/**/*", "test/**/*", "LICENSE", "README.md", "CHANGELOG.md"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
targets = [
|
||||
"x86_64-unknown-linux-gnu",
|
||||
@@ -21,34 +22,27 @@ targets = [
|
||||
"x86_64-unknown-openbsd",
|
||||
"x86_64-unknown-netbsd",
|
||||
"x86_64-unknown-dragonfly",
|
||||
"x86_64-fuchsia",
|
||||
"x86_64-unknown-fuchsia",
|
||||
"x86_64-unknown-redox",
|
||||
"x86_64-unknown-illumos"
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
libc = { version = "0.2.137", features = [ "extra_traits" ] }
|
||||
bitflags = "1.1"
|
||||
libc = { version = "0.2.171", features = ["extra_traits"] }
|
||||
bitflags = "2.3.3"
|
||||
cfg-if = "1.0"
|
||||
pin-utils = { version = "0.1.0", optional = true }
|
||||
|
||||
[target.'cfg(not(target_os = "redox"))'.dependencies]
|
||||
memoffset = { version = "0.7", optional = true }
|
||||
memoffset = { version = "0.9", optional = true }
|
||||
|
||||
[features]
|
||||
default = [
|
||||
"acct", "aio", "dir", "env", "event", "feature", "fs",
|
||||
"hostname", "inotify", "ioctl", "kmod", "mman", "mount", "mqueue",
|
||||
"net", "personality", "poll", "process", "pthread", "ptrace", "quota",
|
||||
"reboot", "resource", "sched", "signal", "socket", "term", "time",
|
||||
"ucontext", "uio", "user", "zerocopy",
|
||||
]
|
||||
default = []
|
||||
|
||||
acct = []
|
||||
aio = ["pin-utils"]
|
||||
dir = ["fs"]
|
||||
env = []
|
||||
event = []
|
||||
event = ["poll"]
|
||||
fanotify = []
|
||||
feature = []
|
||||
fs = []
|
||||
hostname = []
|
||||
@@ -70,6 +64,7 @@ resource = []
|
||||
sched = ["process"]
|
||||
signal = ["process"]
|
||||
socket = ["memoffset"]
|
||||
syslog = []
|
||||
term = []
|
||||
time = []
|
||||
ucontext = ["signal"]
|
||||
@@ -79,11 +74,15 @@ zerocopy = ["fs", "uio"]
|
||||
|
||||
[dev-dependencies]
|
||||
assert-impl = "0.1"
|
||||
lazy_static = "1.4"
|
||||
parking_lot = "0.12"
|
||||
rand = "0.8"
|
||||
tempfile = "3.3"
|
||||
rand = "0.9"
|
||||
tempfile = "3.7.1"
|
||||
semver = "1.0.7"
|
||||
nix = { path = ".", features = ["acct", "aio", "dir", "env", "event", "fanotify",
|
||||
"feature", "fs", "hostname", "inotify", "ioctl", "kmod", "mman", "mount", "mqueue",
|
||||
"net", "personality", "poll", "pthread", "ptrace", "quota", "process", "reboot",
|
||||
"resource", "sched", "signal", "socket", "syslog", "term", "time", "ucontext", "uio",
|
||||
"user", "zerocopy"] }
|
||||
|
||||
[target.'cfg(any(target_os = "android", target_os = "linux"))'.dev-dependencies]
|
||||
caps = "0.5.3"
|
||||
@@ -91,6 +90,9 @@ caps = "0.5.3"
|
||||
[target.'cfg(target_os = "freebsd")'.dev-dependencies]
|
||||
sysctl = "0.4"
|
||||
|
||||
[build-dependencies]
|
||||
cfg_aliases = "0.2.1"
|
||||
|
||||
[[test]]
|
||||
name = "test"
|
||||
path = "test/test.rs"
|
||||
@@ -104,10 +106,5 @@ name = "test-clearenv"
|
||||
path = "test/test_clearenv.rs"
|
||||
|
||||
[[test]]
|
||||
name = "test-mount"
|
||||
path = "test/test_mount.rs"
|
||||
harness = false
|
||||
|
||||
[[test]]
|
||||
name = "test-ptymaster-drop"
|
||||
path = "test/test_ptymaster_drop.rs"
|
||||
name = "test-prctl"
|
||||
path = "test/sys/test_prctl.rs"
|
||||
|
||||
@@ -3,3 +3,6 @@ passthrough = [
|
||||
"RUSTFLAGS",
|
||||
"RUST_TEST_THREADS"
|
||||
]
|
||||
|
||||
[target.loongarch64-unknown-linux-gnu]
|
||||
image = "ghcr.io/cross-rs/loongarch64-unknown-linux-gnu:edge"
|
||||
|
||||
+4
-3
@@ -3,14 +3,15 @@
|
||||
"Name": "nix",
|
||||
"License": "MIT",
|
||||
"License File": "LICENSE",
|
||||
"Version Number": "0.26.4",
|
||||
"Version Number": "0.30.1",
|
||||
"Owner": "fangting12@huawei.com",
|
||||
"Upstream URL": "https://github.com/nix-rust/nix",
|
||||
"Description": "A Rust library that provides support for interacting with Unix-like operating systems.",
|
||||
"Dependencies": [
|
||||
"Static Assertions",
|
||||
"libc",
|
||||
"bitflags"
|
||||
"memoffset",
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"pin-utils"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
[](https://cirrus-ci.com/github/nix-rust/nix)
|
||||
[](https://crates.io/crates/nix)
|
||||
|
||||
[Documentation (Releases)](https://docs.rs/nix/)
|
||||
[](https://docs.rs/nix)
|
||||

|
||||
[](https://www.rust-lang.org)
|
||||
|
||||
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
|
||||
@@ -30,7 +31,7 @@ pub fn gethostname() -> Result<OsString>;
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
nix target support consists of two tiers. While nix attempts to support all
|
||||
nix target support consists of three tiers. While nix attempts to support all
|
||||
platforms supported by [libc](https://github.com/rust-lang/libc), only some
|
||||
platforms are actively supported due to either technical or manpower
|
||||
limitations. Support for platforms is split into three tiers:
|
||||
@@ -41,55 +42,75 @@ limitations. Support for platforms is split into three tiers:
|
||||
blocks the inclusion of new code. Tests may be run, but failures
|
||||
in tests don't block the inclusion of new code.
|
||||
* Tier 3 - Builds for this target are run in CI. Failures during the build
|
||||
*do not* block the inclusion of new code. Testing may be run, but
|
||||
failures in tests don't block the inclusion of new code.
|
||||
*do not* necessarily block the inclusion of new code. That is, at
|
||||
our discretion a Tier 3 target may be dropped at any time, if it
|
||||
would otherwise block development.
|
||||
|
||||
Platforms not listed are supported on a best-effort basis, relying on our users
|
||||
to report any problems.
|
||||
|
||||
The following targets are supported by `nix`:
|
||||
|
||||
Tier 1:
|
||||
* aarch64-apple-darwin
|
||||
* aarch64-unknown-linux-gnu
|
||||
* arm-unknown-linux-gnueabi
|
||||
* armv7-unknown-linux-gnueabihf
|
||||
* i686-unknown-freebsd
|
||||
* i686-unknown-linux-gnu
|
||||
* i686-unknown-linux-musl
|
||||
* mips-unknown-linux-gnu
|
||||
* mips64-unknown-linux-gnuabi64
|
||||
* mips64el-unknown-linux-gnuabi64
|
||||
* mipsel-unknown-linux-gnu
|
||||
* powerpc64le-unknown-linux-gnu
|
||||
* x86_64-unknown-freebsd
|
||||
* x86_64-unknown-linux-gnu
|
||||
* x86_64-unknown-linux-musl
|
||||
|
||||
Tier 2:
|
||||
* aarch64-apple-ios
|
||||
* aarch64-linux-android
|
||||
* arm-linux-androideabi
|
||||
* arm-unknown-linux-musleabi
|
||||
* armv7-linux-androideabi
|
||||
* i686-linux-android
|
||||
* powerpc-unknown-linux-gnu
|
||||
* s390x-unknown-linux-gnu
|
||||
* x86_64-apple-ios
|
||||
* x86_64-linux-android
|
||||
* x86_64-apple-darwin
|
||||
* x86_64-unknown-illumos
|
||||
* x86_64-unknown-netbsd
|
||||
|
||||
Tier 3:
|
||||
* armv7-unknown-linux-uclibceabihf
|
||||
* x86_64-fuchsia
|
||||
* x86_64-unknown-dragonfly
|
||||
* x86_64-unknown-haiku
|
||||
* x86_64-unknown-linux-gnux32
|
||||
* x86_64-unknown-openbsd
|
||||
* x86_64-unknown-redox
|
||||
<table>
|
||||
<tr>
|
||||
<th>Tier 1</th>
|
||||
<th>Tier 2</th>
|
||||
<th>Tier 3</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<ul>
|
||||
<li>aarch64-apple-darwin</li>
|
||||
<li>aarch64-unknown-linux-gnu</li>
|
||||
<li>arm-unknown-linux-gnueabi</li>
|
||||
<li>armv7-unknown-linux-gnueabihf</li>
|
||||
<li>i686-unknown-freebsd</li>
|
||||
<li>i686-unknown-linux-gnu</li>
|
||||
<li>i686-unknown-linux-musl</li>
|
||||
<li>mips-unknown-linux-gnu</li>
|
||||
<li>mips64-unknown-linux-gnuabi64</li>
|
||||
<li>mips64el-unknown-linux-gnuabi64</li>
|
||||
<li>mipsel-unknown-linux-gnu</li>
|
||||
<li>powerpc64le-unknown-linux-gnu</li>
|
||||
<li>x86_64-unknown-freebsd</li>
|
||||
<li>x86_64-unknown-linux-gnu</li>
|
||||
<li>x86_64-unknown-linux-musl</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>aarch64-apple-ios</li>
|
||||
<li>aarch64-linux-android</li>
|
||||
<li>aarch64-unknown-linux-ohos</li>
|
||||
<li>arm-linux-androideabi</li>
|
||||
<li>arm-unknown-linux-musleabi</li>
|
||||
<li>armv7-linux-androideabi</li>
|
||||
<li>armv7-unknown-linux-ohos</li>
|
||||
<li>i686-linux-android</li>
|
||||
<li>loongarch64-unknown-linux-gnu</li>
|
||||
<li>s390x-unknown-linux-gnu</li>
|
||||
<li>x86_64-linux-android</li>
|
||||
<li>x86_64-unknown-illumos</li>
|
||||
<li>x86_64-unknown-linux-ohos</li>
|
||||
<li>x86_64-unknown-netbsd</li>
|
||||
</td>
|
||||
<td>
|
||||
<li>armv7-unknown-linux-uclibceabihf</li>
|
||||
<li>powerpc64-unknown-linux-gnu</li>
|
||||
<li>x86_64-unknown-fuchsia</li>
|
||||
<li>x86_64-unknown-dragonfly</li>
|
||||
<li>x86_64-unknown-haiku</li>
|
||||
<li>x86_64-unknown-linux-gnux32</li>
|
||||
<li>x86_64-unknown-openbsd</li>
|
||||
<li>x86_64-unknown-redox</li>
|
||||
<li>i686-unknown-hurd-gnu</li>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Minimum Supported Rust Version (MSRV)
|
||||
|
||||
nix is supported on Rust 1.56.1 and higher. Its MSRV will not be
|
||||
nix is supported on Rust 1.69 and higher. Its MSRV will not be
|
||||
changed in the future without bumping the major or minor version.
|
||||
|
||||
## Contributing
|
||||
@@ -97,7 +118,7 @@ changed in the future without bumping the major or minor version.
|
||||
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
|
||||
Feel free to join us in [the nix-rust/nix](https://discord.com/invite/rkBeJUsmyd) channel on Discord to
|
||||
discuss `nix` development.
|
||||
|
||||
## License
|
||||
|
||||
+54
-7
@@ -4,16 +4,63 @@ 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
|
||||
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.
|
||||
> NOTE: the following procedure should be done directly against the master
|
||||
> branch of the repo.
|
||||
|
||||
- Clone the `nix-rust/nix` repository with your preferred way, and `cd` to it:
|
||||
|
||||
```sh
|
||||
$ git clone https://github.com/nix-rust/nix.git
|
||||
$ cd nix
|
||||
```
|
||||
|
||||
- If we are using `libc` from git, replace it with a usable release from crates.io.
|
||||
|
||||
```diff
|
||||
[dependencies]
|
||||
-libc = { git = "https://github.com/rust-lang/libc", rev = "<Revision>", features = ["extra_traits"] }
|
||||
+libc = { version = "<Version>", features = ["extra_traits"] }
|
||||
```
|
||||
|
||||
- Update the version number in `Cargo.toml`
|
||||
- Generate `CHANGELOG.md` for this release by
|
||||
|
||||
```sh
|
||||
$ towncrier build --version=<VERSION> --yes
|
||||
Loading template...
|
||||
Finding news fragments...
|
||||
Rendering news fragments...
|
||||
Writing to newsfile...
|
||||
Staging newsfile...
|
||||
Removing the following files:
|
||||
nix/changelog/xxxx.xxxx.md
|
||||
nix/changelog/xxxx.xxxx.md
|
||||
...
|
||||
nix/changelog/xxxx.xxxx.md
|
||||
Removing news fragments...
|
||||
Done!
|
||||
```
|
||||
|
||||
- Push the changes made by the above steps to the master branch
|
||||
|
||||
- Ensure you have a crates.io token
|
||||
1. With the `publish-update` scope
|
||||
2. Can be used for crate `nix`
|
||||
3. It is set via `cargo login`
|
||||
|
||||
If not, create a new token [here](https://crates.io/settings/tokens), and set
|
||||
it.
|
||||
|
||||
- Confirm that everything's ready for a release by running
|
||||
`cargo release <patch|minor|major>`
|
||||
- Create the release with `cargo release -x <patch|minor|major>`
|
||||
- Push the created tag to GitHub.
|
||||
`cargo release <VERSION>`
|
||||
- Create the release with `cargo release -x <VERSION>`, this step will publish
|
||||
the version to crates.io and push the new version tag to GitHub.
|
||||
|
||||
- Congratulations on a new Nix release!
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
status = [
|
||||
"Android aarch64",
|
||||
"Android arm",
|
||||
"Android armv7",
|
||||
"Android i686",
|
||||
"Android x86_64",
|
||||
"DragonFly BSD x86_64",
|
||||
"FreeBSD 12 amd64 & i686",
|
||||
"FreeBSD 14 amd64 & i686",
|
||||
"Fuchsia x86_64",
|
||||
"Linux MIPS",
|
||||
"Linux MIPS64 el",
|
||||
"Linux MIPS64",
|
||||
"Linux aarch64",
|
||||
"Linux arm gnueabi",
|
||||
"Linux arm-musleabi",
|
||||
"Linux armv7 gnueabihf",
|
||||
"Linux armv7 uclibceabihf",
|
||||
"Linux i686 musl",
|
||||
"Linux i686",
|
||||
"Linux mipsel",
|
||||
"Linux powerpc",
|
||||
"Linux powerpc64",
|
||||
"Linux powerpc64le",
|
||||
"Linux s390x",
|
||||
"Linux x32",
|
||||
"Linux x86_64 musl",
|
||||
"Linux x86_64",
|
||||
"macOS aarch64",
|
||||
"macOS x86_64",
|
||||
"Minver",
|
||||
"NetBSD x86_64",
|
||||
"OpenBSD x86_64",
|
||||
"Redox x86_64",
|
||||
"Rust Stable",
|
||||
"Rust Formatter",
|
||||
"iOS aarch64",
|
||||
"iOS x86_64",
|
||||
"Illumos",
|
||||
"Haiku x86_64",
|
||||
]
|
||||
|
||||
# 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
|
||||
@@ -0,0 +1,35 @@
|
||||
use cfg_aliases::cfg_aliases;
|
||||
|
||||
fn main() {
|
||||
cfg_aliases! {
|
||||
android: { target_os = "android" },
|
||||
dragonfly: { target_os = "dragonfly" },
|
||||
ios: { target_os = "ios" },
|
||||
freebsd: { target_os = "freebsd" },
|
||||
illumos: { target_os = "illumos" },
|
||||
linux: { target_os = "linux" },
|
||||
macos: { target_os = "macos" },
|
||||
netbsd: { target_os = "netbsd" },
|
||||
openbsd: { target_os = "openbsd" },
|
||||
solaris: { target_os = "solaris" },
|
||||
watchos: { target_os = "watchos" },
|
||||
tvos: { target_os = "tvos" },
|
||||
visionos: { target_os = "visionos" },
|
||||
|
||||
|
||||
// cfg aliases we would like to use
|
||||
apple_targets: { any(ios, macos, watchos, tvos, visionos) },
|
||||
bsd: { any(freebsd, dragonfly, netbsd, openbsd, apple_targets) },
|
||||
bsd_without_apple: { any(freebsd, dragonfly, netbsd, openbsd) },
|
||||
linux_android: { any(android, linux) },
|
||||
freebsdlike: { any(dragonfly, freebsd) },
|
||||
netbsdlike: { any(netbsd, openbsd) },
|
||||
solarish: { any(illumos, solaris) },
|
||||
}
|
||||
|
||||
// Below are custom cfg values set during some CI steps.
|
||||
println!("cargo:rustc-check-cfg=cfg(fbsd14)");
|
||||
println!("cargo:rustc-check-cfg=cfg(qemu)");
|
||||
// Cygwin target, added in 1.86
|
||||
println!("cargo:rustc-check-cfg=cfg(target_os, values(\"cygwin\"))");
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
Do not remove this file. This is used to keep the `changelog` dir around after
|
||||
generating new changelog file.
|
||||
|
||||
Without this, `towncrier` would remove the changelog files as well as the
|
||||
directory if it is empty.
|
||||
@@ -0,0 +1,55 @@
|
||||
//! Print all interfaces and interface addresses on the system, in a format
|
||||
//! similar to ifconfig(8).
|
||||
#![cfg(feature = "net")]
|
||||
#[cfg(any(bsd, linux_android, target_os = "illumos"))]
|
||||
fn main() {
|
||||
use nix::ifaddrs::getifaddrs;
|
||||
use nix::sys::socket::{SockaddrLike, SockaddrStorage};
|
||||
|
||||
let addrs = getifaddrs().unwrap();
|
||||
let mut ifname = None;
|
||||
for addr in addrs {
|
||||
if ifname.as_ref() != Some(&addr.interface_name) {
|
||||
if ifname.is_some() {
|
||||
println!();
|
||||
}
|
||||
ifname = Some(addr.interface_name.clone());
|
||||
println!(
|
||||
"{}: flags={:x}<{}>",
|
||||
addr.interface_name,
|
||||
addr.flags.bits(),
|
||||
addr.flags
|
||||
);
|
||||
}
|
||||
if let Some(dl) = addr.address.as_ref().unwrap().as_link_addr() {
|
||||
if dl.addr().is_none() {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let family = addr
|
||||
.address
|
||||
.as_ref()
|
||||
.and_then(SockaddrStorage::family)
|
||||
.map(|af| format!("{af:?}"))
|
||||
.unwrap_or("".to_owned());
|
||||
match (
|
||||
&addr.address,
|
||||
&addr.netmask,
|
||||
&addr.broadcast,
|
||||
&addr.destination,
|
||||
) {
|
||||
(Some(a), Some(nm), Some(b), None) => {
|
||||
println!("\t{family} {a} netmask {nm} broadcast {b}")
|
||||
}
|
||||
(Some(a), Some(nm), None, None) => {
|
||||
println!("\t{family} {a} netmask {nm}")
|
||||
}
|
||||
(Some(a), None, None, None) => println!("\t{family} {a}"),
|
||||
(Some(a), None, None, Some(d)) => println!("\t{family} {a} -> {d}"),
|
||||
x => todo!("{x:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(bsd, linux_android, target_os = "illumos")))]
|
||||
fn main() {}
|
||||
@@ -0,0 +1,8 @@
|
||||
# If no sub-command is given, simply list all the available options
|
||||
_default:
|
||||
just --list
|
||||
|
||||
# Build the doc
|
||||
doc *args='':
|
||||
RUSTDOCFLAGS='--cfg docsrs' cargo +nightly doc --all-features --no-deps {{args}}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
pre-release-replacements = [
|
||||
{ file="CHANGELOG.md", search="Unreleased", replace="{{version}}" },
|
||||
{ file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}" }
|
||||
]
|
||||
+90
-41
@@ -3,7 +3,7 @@
|
||||
use crate::errno::Errno;
|
||||
use crate::fcntl::{self, OFlag};
|
||||
use crate::sys;
|
||||
use crate::{Error, NixPath, Result};
|
||||
use crate::{NixPath, Result};
|
||||
use cfg_if::cfg_if;
|
||||
use std::ffi;
|
||||
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
|
||||
@@ -17,17 +17,38 @@ 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.
|
||||
/// This is a lower-level interface than [`std::fs::ReadDir`]. Notable differences:
|
||||
/// * can be opened from a file descriptor (as returned by [`openat`][openat],
|
||||
/// perhaps before knowing if the path represents a file or directory).
|
||||
/// * implements [`AsFd`][AsFd], so it can be passed to [`fstat`][fstat],
|
||||
/// [`openat`][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
|
||||
/// * returns entries' names as a [`CStr`][cstr] (no allocation or conversion beyond whatever libc
|
||||
/// does).
|
||||
///
|
||||
/// [AsFd]: std::os::fd::AsFd
|
||||
/// [fstat]: crate::sys::stat::fstat
|
||||
/// [openat]: crate::fcntl::openat
|
||||
/// [cstr]: std::ffi::CStr
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Traverse the current directory, and print entries' names:
|
||||
///
|
||||
/// ```
|
||||
/// use nix::dir::Dir;
|
||||
/// use nix::fcntl::OFlag;
|
||||
/// use nix::sys::stat::Mode;
|
||||
///
|
||||
/// let mut cwd = Dir::open(".", OFlag::O_RDONLY | OFlag::O_CLOEXEC, Mode::empty()).unwrap();
|
||||
/// for res_entry in cwd.iter() {
|
||||
/// let entry = res_entry.unwrap();
|
||||
/// println!("File name: {}", entry.file_name().to_string_lossy());
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug, Eq, Hash, PartialEq)]
|
||||
pub struct Dir(ptr::NonNull<libc::DIR>);
|
||||
|
||||
@@ -43,8 +64,8 @@ impl Dir {
|
||||
}
|
||||
|
||||
/// Opens the given path as with `fcntl::openat`.
|
||||
pub fn openat<P: ?Sized + NixPath>(
|
||||
dirfd: RawFd,
|
||||
pub fn openat<Fd: std::os::fd::AsFd, P: ?Sized + NixPath>(
|
||||
dirfd: Fd,
|
||||
path: &P,
|
||||
oflag: OFlag,
|
||||
mode: sys::stat::Mode,
|
||||
@@ -54,21 +75,46 @@ impl Dir {
|
||||
}
|
||||
|
||||
/// Converts from a descriptor-based object, closing the descriptor on success or failure.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is only safe if `fd` is an owned file descriptor.
|
||||
#[inline]
|
||||
pub fn from<F: IntoRawFd>(fd: F) -> Result<Self> {
|
||||
Dir::from_fd(fd.into_raw_fd())
|
||||
#[deprecated(
|
||||
since = "0.30.0",
|
||||
note = "Deprecate this since it is not I/O-safe, use from_fd instead."
|
||||
)]
|
||||
pub unsafe fn from<F: IntoRawFd>(fd: F) -> Result<Self> {
|
||||
use std::os::fd::FromRawFd;
|
||||
use std::os::fd::OwnedFd;
|
||||
|
||||
// SAFETY:
|
||||
//
|
||||
// This is indeed unsafe is `fd` it not an owned fd.
|
||||
let owned_fd = unsafe { OwnedFd::from_raw_fd(fd.into_raw_fd()) };
|
||||
Dir::from_fd(owned_fd)
|
||||
}
|
||||
|
||||
/// Converts from a file descriptor, closing it on success or failure.
|
||||
/// Converts from a file descriptor, closing it on failure.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// `ENOTDIR` would be returned if `fd` does not refer to a directory:
|
||||
///
|
||||
/// ```should_panic
|
||||
/// use std::os::fd::OwnedFd;
|
||||
/// use nix::dir::Dir;
|
||||
///
|
||||
/// let temp_file = tempfile::tempfile().unwrap();
|
||||
/// let temp_file_fd: OwnedFd = temp_file.into();
|
||||
/// let never = Dir::from_fd(temp_file_fd).unwrap();
|
||||
/// ```
|
||||
#[doc(alias("fdopendir"))]
|
||||
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
|
||||
},
|
||||
)?;
|
||||
pub fn from_fd(fd: std::os::fd::OwnedFd) -> Result<Self> {
|
||||
// take the ownership as the constructed `Dir` is now the owner
|
||||
let raw_fd = fd.into_raw_fd();
|
||||
let d = ptr::NonNull::new(unsafe { libc::fdopendir(raw_fd) })
|
||||
.ok_or(Errno::last())?;
|
||||
Ok(Dir(d))
|
||||
}
|
||||
|
||||
@@ -86,6 +132,18 @@ impl Dir {
|
||||
// `Dir` is safe to pass from one thread to another, as it's not reference-counted.
|
||||
unsafe impl Send for Dir {}
|
||||
|
||||
impl std::os::fd::AsFd for Dir {
|
||||
fn as_fd(&self) -> std::os::fd::BorrowedFd {
|
||||
let raw_fd = self.as_raw_fd();
|
||||
|
||||
// SAFETY:
|
||||
//
|
||||
// `raw_fd` should be open and valid for the lifetime of the returned
|
||||
// `BorrowedFd` as it is extracted from `&self`.
|
||||
unsafe { std::os::fd::BorrowedFd::borrow_raw(raw_fd) }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Dir {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
unsafe { libc::dirfd(self.0.as_ptr()) }
|
||||
@@ -132,7 +190,7 @@ fn next(dir: &mut Dir) -> Option<Result<Entry>> {
|
||||
#[derive(Debug, Eq, Hash, PartialEq)]
|
||||
pub struct Iter<'d>(&'d mut Dir);
|
||||
|
||||
impl<'d> Iterator for Iter<'d> {
|
||||
impl Iterator for Iter<'_> {
|
||||
type Item = Result<Entry>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
@@ -140,7 +198,7 @@ impl<'d> Iterator for Iter<'d> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> Drop for Iter<'d> {
|
||||
impl Drop for Iter<'_> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { libc::rewinddir((self.0).0.as_ptr()) }
|
||||
}
|
||||
@@ -224,16 +282,15 @@ impl Entry {
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
pub fn ino(&self) -> u64 {
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "android",
|
||||
if #[cfg(any(target_os = "aix",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_os = "haiku",
|
||||
target_os = "illumos",
|
||||
target_os = "ios",
|
||||
target_os = "l4re",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "solaris"))] {
|
||||
target_os = "hurd",
|
||||
target_os = "cygwin",
|
||||
solarish,
|
||||
linux_android,
|
||||
apple_targets))] {
|
||||
self.0.d_ino as u64
|
||||
} else {
|
||||
u64::from(self.0.d_fileno)
|
||||
@@ -243,7 +300,7 @@ impl Entry {
|
||||
|
||||
/// Returns the bare file name of this directory entry without any other leading path component.
|
||||
pub fn file_name(&self) -> &ffi::CStr {
|
||||
unsafe { ::std::ffi::CStr::from_ptr(self.0.d_name.as_ptr()) }
|
||||
unsafe { ffi::CStr::from_ptr(self.0.d_name.as_ptr()) }
|
||||
}
|
||||
|
||||
/// Returns the type of this directory entry, if known.
|
||||
@@ -252,11 +309,7 @@ impl Entry {
|
||||
/// notably, some Linux filesystems don't implement this. The caller should use `stat` or
|
||||
/// `fstat` if this returns `None`.
|
||||
pub fn file_type(&self) -> Option<Type> {
|
||||
#[cfg(not(any(
|
||||
target_os = "illumos",
|
||||
target_os = "solaris",
|
||||
target_os = "haiku"
|
||||
)))]
|
||||
#[cfg(not(any(solarish, target_os = "aix", target_os = "haiku")))]
|
||||
match self.0.d_type {
|
||||
libc::DT_FIFO => Some(Type::Fifo),
|
||||
libc::DT_CHR => Some(Type::CharacterDevice),
|
||||
@@ -269,11 +322,7 @@ impl Entry {
|
||||
}
|
||||
|
||||
// illumos, Solaris, and Haiku systems do not have the d_type member at all:
|
||||
#[cfg(any(
|
||||
target_os = "illumos",
|
||||
target_os = "solaris",
|
||||
target_os = "haiku"
|
||||
))]
|
||||
#[cfg(any(solarish, target_os = "aix", target_os = "haiku"))]
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
+3
-4
@@ -40,13 +40,12 @@ impl std::error::Error for ClearEnvError {}
|
||||
/// thread safety must still be upheld.
|
||||
pub unsafe fn clearenv() -> std::result::Result<(), ClearEnvError> {
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "fuchsia",
|
||||
if #[cfg(any(linux_android,
|
||||
target_os = "fuchsia",
|
||||
target_os = "wasi",
|
||||
target_env = "uclibc",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten"))] {
|
||||
let ret = libc::clearenv();
|
||||
let ret = unsafe { libc::clearenv() };
|
||||
} else {
|
||||
use std::env;
|
||||
for (name, _) in env::vars_os() {
|
||||
|
||||
+1243
-517
File diff suppressed because it is too large
Load Diff
+1005
-268
File diff suppressed because it is too large
Load Diff
+16
-15
@@ -1,11 +1,12 @@
|
||||
//! Feature tests for OS functionality
|
||||
pub use self::os::*;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(any(linux_android, target_os = "emscripten"))]
|
||||
mod os {
|
||||
use crate::sys::utsname::uname;
|
||||
use crate::Result;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
// Features:
|
||||
// * atomic cloexec on socket: 2.6.27
|
||||
@@ -72,15 +73,15 @@ mod os {
|
||||
}
|
||||
|
||||
fn kernel_version() -> Result<usize> {
|
||||
static mut KERNEL_VERS: usize = 0;
|
||||
static KERNEL_VERS: AtomicUsize = AtomicUsize::new(0);
|
||||
let mut kernel_vers = KERNEL_VERS.load(Ordering::Relaxed);
|
||||
|
||||
unsafe {
|
||||
if KERNEL_VERS == 0 {
|
||||
KERNEL_VERS = parse_kernel_version()?;
|
||||
}
|
||||
|
||||
Ok(KERNEL_VERS)
|
||||
if kernel_vers == 0 {
|
||||
kernel_vers = parse_kernel_version()?;
|
||||
KERNEL_VERS.store(kernel_vers, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
Ok(kernel_vers)
|
||||
}
|
||||
|
||||
/// Check if the OS supports atomic close-on-exec for sockets
|
||||
@@ -91,18 +92,18 @@ mod os {
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_parsing_kernel_version() {
|
||||
fn test_parsing_kernel_version() {
|
||||
assert!(kernel_version().unwrap() > 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly", // Since ???
|
||||
target_os = "freebsd", // Since 10.0
|
||||
freebsdlike, // FreeBSD since 10.0 DragonFlyBSD since ???
|
||||
netbsdlike, // NetBSD since 6.0 OpenBSD since 5.7
|
||||
target_os = "hurd", // Since glibc 2.28
|
||||
target_os = "illumos", // Since ???
|
||||
target_os = "netbsd", // Since 6.0
|
||||
target_os = "openbsd", // Since 5.7
|
||||
target_os = "redox", // Since 1-july-2020
|
||||
target_os = "cygwin",
|
||||
))]
|
||||
mod os {
|
||||
/// Check if the OS supports atomic close-on-exec for sockets
|
||||
@@ -112,8 +113,8 @@ mod os {
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "aix",
|
||||
apple_targets,
|
||||
target_os = "fuchsia",
|
||||
target_os = "haiku",
|
||||
target_os = "solaris"
|
||||
|
||||
+22
-18
@@ -4,7 +4,7 @@
|
||||
//! of interfaces and their associated addresses.
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
#[cfg(apple_targets)]
|
||||
use std::convert::TryFrom;
|
||||
use std::ffi;
|
||||
use std::iter::Iterator;
|
||||
@@ -33,7 +33,7 @@ pub struct InterfaceAddress {
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux"))] {
|
||||
if #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))] {
|
||||
fn get_ifu_from_sockaddr(info: &libc::ifaddrs) -> *const libc::sockaddr {
|
||||
info.ifa_ifu
|
||||
}
|
||||
@@ -53,7 +53,7 @@ cfg_if! {
|
||||
/// ss_len field to sizeof(sockaddr_storage). This is supposedly valid as all
|
||||
/// members of the sockaddr_storage are "ok" with being zeroed out (there are
|
||||
/// no pointers).
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
#[cfg(apple_targets)]
|
||||
unsafe fn workaround_xnu_bug(info: &libc::ifaddrs) -> Option<SockaddrStorage> {
|
||||
let src_sock = info.ifa_netmask;
|
||||
if src_sock.is_null() {
|
||||
@@ -62,22 +62,24 @@ unsafe fn workaround_xnu_bug(info: &libc::ifaddrs) -> Option<SockaddrStorage> {
|
||||
|
||||
let mut dst_sock = mem::MaybeUninit::<libc::sockaddr_storage>::zeroed();
|
||||
|
||||
// memcpy only sa_len bytes, assume the rest is zero
|
||||
std::ptr::copy_nonoverlapping(
|
||||
src_sock as *const u8,
|
||||
dst_sock.as_mut_ptr() as *mut u8,
|
||||
(*src_sock).sa_len.into(),
|
||||
);
|
||||
let dst_sock = unsafe {
|
||||
// memcpy only sa_len bytes, assume the rest is zero
|
||||
std::ptr::copy_nonoverlapping(
|
||||
src_sock as *const u8,
|
||||
dst_sock.as_mut_ptr().cast(),
|
||||
(*src_sock).sa_len.into(),
|
||||
);
|
||||
|
||||
// Initialize ss_len to sizeof(libc::sockaddr_storage).
|
||||
(*dst_sock.as_mut_ptr()).ss_len =
|
||||
u8::try_from(mem::size_of::<libc::sockaddr_storage>()).unwrap();
|
||||
let dst_sock = dst_sock.assume_init();
|
||||
// Initialize ss_len to sizeof(libc::sockaddr_storage).
|
||||
(*dst_sock.as_mut_ptr()).ss_len =
|
||||
u8::try_from(mem::size_of::<libc::sockaddr_storage>()).unwrap();
|
||||
dst_sock.assume_init()
|
||||
};
|
||||
|
||||
let dst_sock_ptr =
|
||||
&dst_sock as *const libc::sockaddr_storage as *const libc::sockaddr;
|
||||
|
||||
SockaddrStorage::from_raw(dst_sock_ptr, None)
|
||||
unsafe { SockaddrStorage::from_raw(dst_sock_ptr, None) }
|
||||
}
|
||||
|
||||
impl InterfaceAddress {
|
||||
@@ -85,14 +87,16 @@ impl InterfaceAddress {
|
||||
fn from_libc_ifaddrs(info: &libc::ifaddrs) -> InterfaceAddress {
|
||||
let ifname = unsafe { ffi::CStr::from_ptr(info.ifa_name) };
|
||||
let address = unsafe { SockaddrStorage::from_raw(info.ifa_addr, None) };
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
#[cfg(apple_targets)]
|
||||
let netmask = unsafe { workaround_xnu_bug(info) };
|
||||
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
|
||||
#[cfg(not(apple_targets))]
|
||||
let netmask =
|
||||
unsafe { SockaddrStorage::from_raw(info.ifa_netmask, None) };
|
||||
let mut addr = InterfaceAddress {
|
||||
interface_name: ifname.to_string_lossy().to_string(),
|
||||
flags: InterfaceFlags::from_bits_truncate(info.ifa_flags as i32),
|
||||
interface_name: ifname.to_string_lossy().into_owned(),
|
||||
flags: InterfaceFlags::from_bits_truncate(
|
||||
info.ifa_flags as IflagsType,
|
||||
),
|
||||
address,
|
||||
netmask,
|
||||
broadcast: None,
|
||||
|
||||
+8
-4
@@ -3,7 +3,7 @@
|
||||
//! For more details see
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::os::unix::io::{AsFd, AsRawFd};
|
||||
|
||||
use crate::errno::Errno;
|
||||
use crate::Result;
|
||||
@@ -79,15 +79,15 @@ libc_bitflags!(
|
||||
/// ```
|
||||
///
|
||||
/// See [`man init_module(2)`](https://man7.org/linux/man-pages/man2/init_module.2.html) for more information.
|
||||
pub fn finit_module<T: AsRawFd>(
|
||||
fd: &T,
|
||||
pub fn finit_module<Fd: AsFd>(
|
||||
fd: Fd,
|
||||
param_values: &CStr,
|
||||
flags: ModuleInitFlags,
|
||||
) -> Result<()> {
|
||||
let res = unsafe {
|
||||
libc::syscall(
|
||||
libc::SYS_finit_module,
|
||||
fd.as_raw_fd(),
|
||||
fd.as_fd().as_raw_fd(),
|
||||
param_values.as_ptr(),
|
||||
flags.bits(),
|
||||
)
|
||||
@@ -102,7 +102,11 @@ libc_bitflags!(
|
||||
/// See [`man delete_module(2)`](https://man7.org/linux/man-pages/man2/delete_module.2.html)
|
||||
/// for a detailed description how these flags work.
|
||||
pub struct DeleteModuleFlags: libc::c_int {
|
||||
/// `delete_module` will return immediately, with an error, if the module has a nonzero
|
||||
/// reference count.
|
||||
O_NONBLOCK;
|
||||
/// `delete_module` will unload the module immediately, regardless of whether it has a
|
||||
/// nonzero reference count.
|
||||
O_TRUNC;
|
||||
}
|
||||
);
|
||||
|
||||
+105
-26
@@ -12,11 +12,12 @@
|
||||
//! * `dir` - Stuff relating to directory iteration
|
||||
//! * `env` - Manipulate environment variables
|
||||
//! * `event` - Event-driven APIs, like `kqueue` and `epoll`
|
||||
//! * `fanotify` - Linux's `fanotify` filesystem events monitoring API
|
||||
//! * `feature` - Query characteristics of the OS at runtime
|
||||
//! * `fs` - File system functionality
|
||||
//! * `hostname` - Get and set the system's hostname
|
||||
//! * `inotify` - Linux's `inotify` file system notification API
|
||||
//! * `ioctl` - The `ioctl` syscall, and wrappers for my specific instances
|
||||
//! * `ioctl` - The `ioctl` syscall, and wrappers for many specific instances
|
||||
//! * `kmod` - Load and unload kernel modules
|
||||
//! * `mman` - Stuff relating to memory management
|
||||
//! * `mount` - Mount and unmount file systems
|
||||
@@ -33,6 +34,7 @@
|
||||
//! * `sched` - Manipulate process's scheduling
|
||||
//! * `socket` - Sockets, whether for networking or local use
|
||||
//! * `signal` - Send and receive signals to processes
|
||||
//! * `syslog` - System logging
|
||||
//! * `term` - Terminal control APIs
|
||||
//! * `time` - Query the operating system's clocks
|
||||
//! * `ucontext` - User thread context
|
||||
@@ -41,20 +43,65 @@
|
||||
//! * `zerocopy` - APIs like `sendfile` and `copy_file_range`
|
||||
#![crate_name = "nix"]
|
||||
#![cfg(unix)]
|
||||
#![cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![cfg_attr(test, deny(warnings))]
|
||||
// A clear document is a good document no matter if it has a summary in its
|
||||
// first paragraph or not.
|
||||
#![allow(clippy::too_long_first_doc_paragraph)]
|
||||
#![recursion_limit = "500"]
|
||||
#![deny(unused)]
|
||||
#![deny(unexpected_cfgs)]
|
||||
#![allow(unused_macros)]
|
||||
#![cfg_attr(not(feature = "default"), allow(unused_imports))]
|
||||
#![cfg_attr(
|
||||
not(all(
|
||||
feature = "acct",
|
||||
feature = "aio",
|
||||
feature = "dir",
|
||||
feature = "env",
|
||||
feature = "event",
|
||||
feature = "fanotify",
|
||||
feature = "feature",
|
||||
feature = "fs",
|
||||
feature = "hostname",
|
||||
feature = "inotify",
|
||||
feature = "ioctl",
|
||||
feature = "kmod",
|
||||
feature = "mman",
|
||||
feature = "mount",
|
||||
feature = "mqueue",
|
||||
feature = "net",
|
||||
feature = "personality",
|
||||
feature = "poll",
|
||||
feature = "process",
|
||||
feature = "pthread",
|
||||
feature = "ptrace",
|
||||
feature = "quota",
|
||||
feature = "reboot",
|
||||
feature = "resource",
|
||||
feature = "sched",
|
||||
feature = "socket",
|
||||
feature = "signal",
|
||||
feature = "syslog",
|
||||
feature = "term",
|
||||
feature = "time",
|
||||
feature = "ucontext",
|
||||
feature = "uio",
|
||||
feature = "user",
|
||||
feature = "zerocopy",
|
||||
)),
|
||||
allow(unused_imports)
|
||||
)]
|
||||
#![deny(unstable_features)]
|
||||
#![deny(missing_copy_implementations)]
|
||||
#![deny(missing_debug_implementations)]
|
||||
#![warn(missing_docs)]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![deny(clippy::cast_ptr_alignment)]
|
||||
#![allow(clippy::bad_bit_mask)]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
// I found the change suggested by this rules could hurt code readability. I cannot
|
||||
// remeber every type's default value, in such cases, it forces me to open
|
||||
// the std doc to insepct the Default value, which is unnecessary with
|
||||
// `.unwrap_or(value)`.
|
||||
#![allow(clippy::unwrap_or_default)]
|
||||
|
||||
// Re-exported external crates
|
||||
pub use libc;
|
||||
@@ -81,30 +128,22 @@ feature! {
|
||||
#[deny(missing_docs)]
|
||||
pub mod features;
|
||||
}
|
||||
#[allow(missing_docs)]
|
||||
pub mod fcntl;
|
||||
feature! {
|
||||
#![feature = "net"]
|
||||
|
||||
#[cfg(any(target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "illumos",
|
||||
target_os = "openbsd"))]
|
||||
#[cfg(any(linux_android,
|
||||
bsd,
|
||||
solarish))]
|
||||
#[deny(missing_docs)]
|
||||
pub mod ifaddrs;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[deny(missing_docs)]
|
||||
pub mod net;
|
||||
}
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
feature! {
|
||||
#![feature = "kmod"]
|
||||
#[allow(missing_docs)]
|
||||
pub mod kmod;
|
||||
}
|
||||
feature! {
|
||||
@@ -112,9 +151,8 @@ feature! {
|
||||
pub mod mount;
|
||||
}
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux",
|
||||
freebsdlike,
|
||||
all(target_os = "linux", not(target_env = "ohos")),
|
||||
target_os = "netbsd"
|
||||
))]
|
||||
feature! {
|
||||
@@ -138,23 +176,46 @@ feature! {
|
||||
pub mod sys;
|
||||
feature! {
|
||||
#![feature = "time"]
|
||||
#[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 = "s390x", target_arch = "x86", target_arch = "x86_64")
|
||||
any(
|
||||
target_arch = "aarch64",
|
||||
target_arch = "s390x",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64"
|
||||
)
|
||||
))]
|
||||
feature! {
|
||||
#![feature = "ucontext"]
|
||||
#[allow(missing_docs)]
|
||||
pub mod ucontext;
|
||||
}
|
||||
#[allow(missing_docs)]
|
||||
pub mod unistd;
|
||||
|
||||
#[cfg(any(feature = "poll", feature = "event"))]
|
||||
mod poll_timeout;
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "haiku",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
apple_targets
|
||||
))]
|
||||
feature! {
|
||||
#![feature = "process"]
|
||||
pub mod spawn;
|
||||
}
|
||||
|
||||
feature! {
|
||||
#![feature = "syslog"]
|
||||
pub mod syslog;
|
||||
}
|
||||
|
||||
use std::ffi::{CStr, CString, OsStr};
|
||||
use std::mem::MaybeUninit;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
@@ -175,7 +236,7 @@ pub type Result<T> = result::Result<T, Errno>;
|
||||
/// * `Eq`
|
||||
/// * Small size
|
||||
/// * Represents all of the system's errnos, instead of just the most common
|
||||
/// ones.
|
||||
/// ones.
|
||||
pub type Error = Errno;
|
||||
|
||||
/// Common trait used to represent file system paths by many Nix functions.
|
||||
@@ -259,7 +320,7 @@ impl NixPath for [u8] {
|
||||
F: FnOnce(&CStr) -> T,
|
||||
{
|
||||
// The real PATH_MAX is typically 4096, but it's statistically unlikely to have a path
|
||||
// longer than ~300 bytes. See the the PR description to get stats for your own machine.
|
||||
// longer than ~300 bytes. See the PR description to get stats for your own machine.
|
||||
// https://github.com/nix-rust/nix/pull/1656
|
||||
//
|
||||
// By being smaller than a memory page, we also avoid the compiler inserting a probe frame:
|
||||
@@ -271,7 +332,7 @@ impl NixPath for [u8] {
|
||||
}
|
||||
|
||||
let mut buf = MaybeUninit::<[u8; MAX_STACK_ALLOCATION]>::uninit();
|
||||
let buf_ptr = buf.as_mut_ptr() as *mut u8;
|
||||
let buf_ptr = buf.as_mut_ptr().cast();
|
||||
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(self.as_ptr(), buf_ptr, self.len());
|
||||
@@ -332,3 +393,21 @@ impl NixPath for PathBuf {
|
||||
self.as_os_str().with_nix_path(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Like `NixPath::with_nix_path()`, but allow the `path` argument to be optional.
|
||||
///
|
||||
/// A NULL pointer will be provided if `path.is_none()`.
|
||||
#[cfg(any(
|
||||
all(apple_targets, feature = "mount"),
|
||||
all(linux_android, any(feature = "mount", feature = "fanotify"))
|
||||
))]
|
||||
pub(crate) fn with_opt_nix_path<P, T, F>(path: Option<&P>, f: F) -> Result<T>
|
||||
where
|
||||
P: ?Sized + NixPath,
|
||||
F: FnOnce(*const libc::c_char) -> T,
|
||||
{
|
||||
match path {
|
||||
Some(path) => path.with_nix_path(|p_str| f(p_str.as_ptr())),
|
||||
None => Ok(f(ptr::null())),
|
||||
}
|
||||
}
|
||||
|
||||
+8
-5
@@ -27,9 +27,9 @@ macro_rules! feature {
|
||||
/// /// PROT_WRITE enables write protect
|
||||
/// PROT_WRITE;
|
||||
/// PROT_EXEC;
|
||||
/// #[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
/// #[cfg(linux_android)]
|
||||
/// PROT_GROWSDOWN;
|
||||
/// #[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
/// #[cfg(linux_android)]
|
||||
/// PROT_GROWSUP;
|
||||
/// }
|
||||
/// }
|
||||
@@ -63,6 +63,8 @@ macro_rules! libc_bitflags {
|
||||
}
|
||||
) => {
|
||||
::bitflags::bitflags! {
|
||||
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
#[repr(transparent)]
|
||||
$(#[$outer])*
|
||||
pub struct $BitFlags: $T {
|
||||
$(
|
||||
@@ -87,15 +89,14 @@ macro_rules! libc_bitflags {
|
||||
/// PROT_READ,
|
||||
/// PROT_WRITE,
|
||||
/// PROT_EXEC,
|
||||
/// #[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
/// #[cfg(linux_android)]
|
||||
/// PROT_GROWSDOWN,
|
||||
/// #[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
/// #[cfg(linux_android)]
|
||||
/// PROT_GROWSUP,
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
// Some targets don't use all rules.
|
||||
#[allow(unknown_lints)]
|
||||
#[allow(unused_macro_rules)]
|
||||
macro_rules! libc_enum {
|
||||
// Exit rule.
|
||||
@@ -133,6 +134,8 @@ macro_rules! libc_enum {
|
||||
impl ::std::convert::TryFrom<$repr> for $BitFlags {
|
||||
type Error = $crate::Error;
|
||||
#[allow(unused_doc_comments)]
|
||||
#[allow(deprecated)]
|
||||
#[allow(unused_attributes)]
|
||||
fn try_from(x: $repr) -> $crate::Result<Self> {
|
||||
match x {
|
||||
$($try_froms)*
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
use crate::{Errno, NixPath, Result};
|
||||
use libc::c_int;
|
||||
|
||||
libc_bitflags!(
|
||||
/// Used with [`mount()`] and [`unmount()`].
|
||||
pub struct MntFlags: c_int {
|
||||
/// Do not interpret special files on the filesystem.
|
||||
MNT_NODEV;
|
||||
/// Enable data protection on the filesystem if the filesystem is configured for it.
|
||||
MNT_CPROTECT;
|
||||
/// file system is quarantined
|
||||
MNT_QUARANTINE;
|
||||
/// filesystem is stored locally
|
||||
MNT_LOCAL;
|
||||
/// quotas are enabled on filesystem
|
||||
MNT_QUOTA;
|
||||
/// identifies the root filesystem
|
||||
MNT_ROOTFS;
|
||||
/// file system is not appropriate path to user data
|
||||
MNT_DONTBROWSE;
|
||||
/// VFS will ignore ownership information on filesystem objects
|
||||
MNT_IGNORE_OWNERSHIP;
|
||||
/// filesystem was mounted by automounter
|
||||
MNT_AUTOMOUNTED;
|
||||
/// filesystem is journaled
|
||||
MNT_JOURNALED;
|
||||
/// Don't allow user extended attributes
|
||||
MNT_NOUSERXATTR;
|
||||
/// filesystem should defer writes
|
||||
MNT_DEFWRITE;
|
||||
/// don't block unmount if not responding
|
||||
MNT_NOBLOCK;
|
||||
/// file system is exported
|
||||
MNT_EXPORTED;
|
||||
/// file system written asynchronously
|
||||
MNT_ASYNC;
|
||||
/// Force a read-write mount even if the file system appears to be
|
||||
/// unclean.
|
||||
MNT_FORCE;
|
||||
/// MAC support for objects.
|
||||
MNT_MULTILABEL;
|
||||
/// 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;
|
||||
/// 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.
|
||||
MNT_SNAPSHOT;
|
||||
/// All I/O to the file system should be done synchronously.
|
||||
MNT_SYNCHRONOUS;
|
||||
/// Union with underlying fs.
|
||||
MNT_UNION;
|
||||
/// Indicates that the mount command is being applied to an already
|
||||
/// mounted file system.
|
||||
MNT_UPDATE;
|
||||
}
|
||||
);
|
||||
|
||||
/// Mount a file system.
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `source` - Specifies the file system. e.g. `/dev/sd0`.
|
||||
/// - `target` - Specifies the destination. e.g. `/mnt`.
|
||||
/// - `flags` - Optional flags controlling the mount.
|
||||
/// - `data` - Optional file system specific data.
|
||||
///
|
||||
/// # see also
|
||||
/// [`mount`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mount.2.html)
|
||||
pub fn mount<
|
||||
P1: ?Sized + NixPath,
|
||||
P2: ?Sized + NixPath,
|
||||
P3: ?Sized + NixPath,
|
||||
>(
|
||||
source: &P1,
|
||||
target: &P2,
|
||||
flags: MntFlags,
|
||||
data: Option<&P3>,
|
||||
) -> Result<()> {
|
||||
let res = source.with_nix_path(|s| {
|
||||
target.with_nix_path(|t| {
|
||||
crate::with_opt_nix_path(data, |d| unsafe {
|
||||
libc::mount(
|
||||
s.as_ptr(),
|
||||
t.as_ptr(),
|
||||
flags.bits(),
|
||||
d.cast_mut().cast(),
|
||||
)
|
||||
})
|
||||
})
|
||||
})???;
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
/// Umount the file system mounted at `target`.
|
||||
pub fn unmount<P>(target: &P, flags: MntFlags) -> Result<()>
|
||||
where
|
||||
P: ?Sized + NixPath,
|
||||
{
|
||||
let res = target.with_nix_path(|cstr| unsafe {
|
||||
libc::unmount(cstr.as_ptr(), flags.bits())
|
||||
})?;
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
@@ -17,36 +17,29 @@ libc_bitflags!(
|
||||
pub struct MntFlags: c_int {
|
||||
/// ACL support enabled.
|
||||
#[cfg(any(target_os = "netbsd", target_os = "freebsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MNT_ACLS;
|
||||
/// All I/O to the file system should be done asynchronously.
|
||||
MNT_ASYNC;
|
||||
/// dir should instead be a file system ID encoded as “FSID:val0:val1”.
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MNT_BYFSID;
|
||||
/// Force a read-write mount even if the file system appears to be
|
||||
/// unclean.
|
||||
MNT_FORCE;
|
||||
/// GEOM journal support enabled.
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MNT_GJOURNAL;
|
||||
/// MAC support for objects.
|
||||
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
MNT_MULTILABEL;
|
||||
/// Disable read clustering.
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
MNT_NOCLUSTERR;
|
||||
/// Disable write clustering.
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
MNT_NOCLUSTERW;
|
||||
/// Enable NFS version 4 ACLs.
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MNT_NFS4ACLS;
|
||||
/// Do not update access times.
|
||||
MNT_NOATIME;
|
||||
@@ -55,8 +48,7 @@ libc_bitflags!(
|
||||
/// Do not honor setuid or setgid bits on files when executing them.
|
||||
MNT_NOSUID;
|
||||
/// Do not follow symlinks.
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
MNT_NOSYMFOLLOW;
|
||||
/// Mount read-only.
|
||||
MNT_RDONLY;
|
||||
@@ -66,39 +58,28 @@ libc_bitflags!(
|
||||
/// Create a snapshot of the file system.
|
||||
///
|
||||
/// See [mksnap_ffs(8)](https://www.freebsd.org/cgi/man.cgi?query=mksnap_ffs)
|
||||
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
MNT_SNAPSHOT;
|
||||
/// Using soft updates.
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(freebsdlike, netbsdlike))]
|
||||
MNT_SOFTDEP;
|
||||
/// Directories with the SUID bit set chown new files to their own
|
||||
/// owner.
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
MNT_SUIDDIR;
|
||||
/// All I/O to the file system should be done synchronously.
|
||||
MNT_SYNCHRONOUS;
|
||||
/// Union with underlying fs.
|
||||
#[cfg(any(
|
||||
target_os = "macos",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd"
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MNT_UNION;
|
||||
/// Indicates that the mount command is being applied to an already
|
||||
/// mounted file system.
|
||||
MNT_UPDATE;
|
||||
/// Check vnode use counts.
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MNT_NONBUSY;
|
||||
}
|
||||
);
|
||||
@@ -198,7 +179,6 @@ pub type NmountResult = std::result::Result<(), NmountError>;
|
||||
/// * [`nmount(2)`](https://www.freebsd.org/cgi/man.cgi?query=nmount)
|
||||
/// * [`nullfs(5)`](https://www.freebsd.org/cgi/man.cgi?query=nullfs)
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Nmount<'a> {
|
||||
// n.b. notgull: In reality, this is a list that contains
|
||||
@@ -210,12 +190,11 @@ pub struct Nmount<'a> {
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
impl<'a> Nmount<'a> {
|
||||
/// Helper function to push a slice onto the `iov` array.
|
||||
fn push_slice(&mut self, val: &'a [u8], is_owned: bool) {
|
||||
self.iov.push(libc::iovec {
|
||||
iov_base: val.as_ptr() as *mut _,
|
||||
iov_base: val.as_ptr().cast_mut().cast(),
|
||||
iov_len: val.len(),
|
||||
});
|
||||
self.is_owned.push(is_owned);
|
||||
@@ -386,23 +365,20 @@ impl<'a> Nmount<'a> {
|
||||
// SAFETY: we are pushing a mutable iovec here, so we can't use
|
||||
// the above method
|
||||
self.iov.push(libc::iovec {
|
||||
iov_base: errmsg.as_mut_ptr() as *mut c_void,
|
||||
iov_base: errmsg.as_mut_ptr().cast(),
|
||||
iov_len: errmsg.len(),
|
||||
});
|
||||
|
||||
let niov = self.iov.len() as c_uint;
|
||||
let iovp = self.iov.as_mut_ptr();
|
||||
let res = unsafe { libc::nmount(iovp, niov, flags.bits) };
|
||||
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())
|
||||
}
|
||||
let errmsg = if errmsg[0] == 0 {
|
||||
None
|
||||
} else {
|
||||
CStr::from_bytes_until_nul(&errmsg[..]).ok()
|
||||
};
|
||||
Err(NmountError::new(error, errmsg))
|
||||
}
|
||||
@@ -411,7 +387,7 @@ impl<'a> Nmount<'a> {
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
impl<'a> Drop for Nmount<'a> {
|
||||
impl Drop for Nmount<'_> {
|
||||
fn drop(&mut self) {
|
||||
for (iov, is_owned) in self.iov.iter().zip(self.is_owned.iter()) {
|
||||
if *is_owned {
|
||||
@@ -446,7 +422,7 @@ where
|
||||
P: ?Sized + NixPath,
|
||||
{
|
||||
let res = mountpoint.with_nix_path(|cstr| unsafe {
|
||||
libc::unmount(cstr.as_ptr(), flags.bits)
|
||||
libc::unmount(cstr.as_ptr(), flags.bits())
|
||||
})?;
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
+54
-17
@@ -1,9 +1,9 @@
|
||||
#![allow(missing_docs)]
|
||||
use crate::errno::Errno;
|
||||
use crate::{NixPath, Result};
|
||||
use libc::{self, c_int, c_ulong};
|
||||
|
||||
libc_bitflags!(
|
||||
/// Used with [`mount`].
|
||||
pub struct MsFlags: c_ulong {
|
||||
/// Mount read-only
|
||||
MS_RDONLY;
|
||||
@@ -27,36 +27,80 @@ libc_bitflags!(
|
||||
MS_NODIRATIME;
|
||||
/// Linux 2.4.0 - Bind directory at different place
|
||||
MS_BIND;
|
||||
/// Move an existing mount to a new location
|
||||
MS_MOVE;
|
||||
/// Used to create a recursive bind mount.
|
||||
MS_REC;
|
||||
/// Suppress the display of certain kernel warning messages.
|
||||
MS_SILENT;
|
||||
/// VFS does not apply the umask
|
||||
MS_POSIXACL;
|
||||
/// The resulting mount cannot subsequently be bind mounted.
|
||||
MS_UNBINDABLE;
|
||||
/// Make this mount point private.
|
||||
MS_PRIVATE;
|
||||
/// If this is a shared mount point that is a member of a peer group
|
||||
/// that contains other members, convert it to a slave mount.
|
||||
MS_SLAVE;
|
||||
/// Make this mount point shared.
|
||||
MS_SHARED;
|
||||
/// When a file on this filesystem is accessed, update the file's
|
||||
/// last access time (atime) only if the current value of atime is
|
||||
/// less than or equal to the file's last modification time (mtime) or
|
||||
/// last status change time (ctime).
|
||||
MS_RELATIME;
|
||||
/// Mount request came from within the kernel
|
||||
#[deprecated(since = "0.27.0", note = "Should only be used in-kernel")]
|
||||
MS_KERNMOUNT;
|
||||
/// Update inode I_version field
|
||||
MS_I_VERSION;
|
||||
/// Always update the last access time (atime) when files on this
|
||||
/// filesystem are accessed.
|
||||
MS_STRICTATIME;
|
||||
/// Reduce on-disk updates of inode timestamps (atime, mtime, ctime) by
|
||||
/// maintaining these changes only in memory.
|
||||
MS_LAZYTIME;
|
||||
#[deprecated(since = "0.27.0", note = "Should only be used in-kernel")]
|
||||
#[allow(missing_docs)] // Not documented in Linux
|
||||
MS_ACTIVE;
|
||||
#[deprecated(since = "0.27.0", note = "Should only be used in-kernel")]
|
||||
#[allow(missing_docs)] // Not documented in Linux
|
||||
MS_NOUSER;
|
||||
#[allow(missing_docs)] // Not documented in Linux; possibly kernel-only
|
||||
MS_RMT_MASK;
|
||||
#[allow(missing_docs)] // Not documented in Linux; possibly kernel-only
|
||||
MS_MGC_VAL;
|
||||
#[allow(missing_docs)] // Not documented in Linux; possibly kernel-only
|
||||
MS_MGC_MSK;
|
||||
}
|
||||
);
|
||||
|
||||
libc_bitflags!(
|
||||
/// Used with [`umount2].
|
||||
pub struct MntFlags: c_int {
|
||||
/// Attempt to unmount even if still in use, aborting pending requests.
|
||||
MNT_FORCE;
|
||||
/// Lazy unmount. Disconnect the file system immediately, but don't
|
||||
/// actually unmount it until it ceases to be busy.
|
||||
MNT_DETACH;
|
||||
/// Mark the mount point as expired.
|
||||
MNT_EXPIRE;
|
||||
/// Don't dereference `target` if it is a symlink.
|
||||
UMOUNT_NOFOLLOW;
|
||||
}
|
||||
);
|
||||
|
||||
/// Mount a file system.
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `source` - Specifies the file system. e.g. `/dev/sd0`.
|
||||
/// - `target` - Specifies the destination. e.g. `/mnt`.
|
||||
/// - `fstype` - The file system type, e.g. `ext4`.
|
||||
/// - `flags` - Optional flags controlling the mount.
|
||||
/// - `data` - Optional file system specific data.
|
||||
///
|
||||
/// # See Also
|
||||
/// [`mount`](https://man7.org/linux/man-pages/man2/mount.2.html)
|
||||
pub fn mount<
|
||||
P1: ?Sized + NixPath,
|
||||
P2: ?Sized + NixPath,
|
||||
@@ -69,26 +113,15 @@ pub fn mount<
|
||||
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| {
|
||||
let res = crate::with_opt_nix_path(source, |s| {
|
||||
target.with_nix_path(|t| {
|
||||
with_opt_nix_path(fstype, |ty| {
|
||||
with_opt_nix_path(data, |d| unsafe {
|
||||
crate::with_opt_nix_path(fstype, |ty| {
|
||||
crate::with_opt_nix_path(data, |d| unsafe {
|
||||
libc::mount(
|
||||
s,
|
||||
t.as_ptr(),
|
||||
ty,
|
||||
flags.bits,
|
||||
flags.bits(),
|
||||
d as *const libc::c_void,
|
||||
)
|
||||
})
|
||||
@@ -99,6 +132,7 @@ pub fn mount<
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
/// Unmount the file system mounted at `target`.
|
||||
pub fn umount<P: ?Sized + NixPath>(target: &P) -> Result<()> {
|
||||
let res =
|
||||
target.with_nix_path(|cstr| unsafe { libc::umount(cstr.as_ptr()) })?;
|
||||
@@ -106,9 +140,12 @@ pub fn umount<P: ?Sized + NixPath>(target: &P) -> Result<()> {
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
/// Unmount the file system mounted at `target`.
|
||||
///
|
||||
/// See also [`umount`](https://man7.org/linux/man-pages/man2/umount.2.html)
|
||||
pub fn umount2<P: ?Sized + NixPath>(target: &P, flags: MntFlags) -> Result<()> {
|
||||
let res = target.with_nix_path(|cstr| unsafe {
|
||||
libc::umount2(cstr.as_ptr(), flags.bits)
|
||||
libc::umount2(cstr.as_ptr(), flags.bits())
|
||||
})?;
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
|
||||
+12
-20
@@ -1,26 +1,18 @@
|
||||
//! Mount file systems
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
mod linux;
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
pub use self::linux::*;
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
mod bsd;
|
||||
#[cfg(bsd_without_apple)]
|
||||
mod bsd_without_apple;
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
pub use self::bsd::*;
|
||||
#[cfg(bsd_without_apple)]
|
||||
pub use self::bsd_without_apple::*;
|
||||
|
||||
#[cfg(apple_targets)]
|
||||
mod apple;
|
||||
|
||||
#[cfg(apple_targets)]
|
||||
pub use self::apple::*;
|
||||
|
||||
+104
-27
@@ -9,16 +9,16 @@
|
||||
//! use nix::sys::stat::Mode;
|
||||
//!
|
||||
//! const MSG_SIZE: mq_attr_member_t = 32;
|
||||
//! let mq_name= CString::new("/a_nix_test_queue").unwrap();
|
||||
//! let mq_name= "/a_nix_test_queue";
|
||||
//!
|
||||
//! let oflag0 = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
|
||||
//! let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
|
||||
//! let mqd0 = mq_open(&mq_name, oflag0, mode, None).unwrap();
|
||||
//! let mqd0 = mq_open(mq_name, oflag0, mode, None).unwrap();
|
||||
//! let msg_to_send = b"msg_1";
|
||||
//! mq_send(&mqd0, msg_to_send, 1).unwrap();
|
||||
//!
|
||||
//! let oflag1 = MQ_OFlag::O_CREAT | MQ_OFlag::O_RDONLY;
|
||||
//! let mqd1 = mq_open(&mq_name, oflag1, mode, None).unwrap();
|
||||
//! let mqd1 = mq_open(mq_name, oflag1, mode, None).unwrap();
|
||||
//! let mut buf = [0u8; 32];
|
||||
//! let mut prio = 0u32;
|
||||
//! let len = mq_receive(&mqd1, &mut buf, &mut prio).unwrap();
|
||||
@@ -31,12 +31,20 @@
|
||||
//! [Further reading and details on the C API](https://man7.org/linux/man-pages/man7/mq_overview.7.html)
|
||||
|
||||
use crate::errno::Errno;
|
||||
use crate::NixPath;
|
||||
use crate::Result;
|
||||
|
||||
use crate::sys::stat::Mode;
|
||||
use libc::{self, c_char, mqd_t, size_t};
|
||||
use std::ffi::CStr;
|
||||
use libc::{self, mqd_t, size_t};
|
||||
use std::mem;
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "dragonfly"
|
||||
))]
|
||||
use std::os::unix::io::{
|
||||
AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd,
|
||||
};
|
||||
|
||||
libc_bitflags! {
|
||||
/// Used with [`mq_open`].
|
||||
@@ -80,11 +88,9 @@ pub struct MqdT(mqd_t);
|
||||
// See https://sourceware.org/bugzilla/show_bug.cgi?id=21279
|
||||
/// Size of a message queue attribute member
|
||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub type mq_attr_member_t = i64;
|
||||
/// Size of a message queue attribute member
|
||||
#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub type mq_attr_member_t = libc::c_long;
|
||||
|
||||
impl MqAttr {
|
||||
@@ -139,33 +145,41 @@ impl MqAttr {
|
||||
/// Open a message queue
|
||||
///
|
||||
/// See also [`mq_open(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_open.html)
|
||||
// The mode.bits cast is only lossless on some OSes
|
||||
// The mode.bits() cast is only lossless on some OSes
|
||||
#[allow(clippy::cast_lossless)]
|
||||
pub fn mq_open(
|
||||
name: &CStr,
|
||||
pub fn mq_open<P>(
|
||||
name: &P,
|
||||
oflag: MQ_OFlag,
|
||||
mode: Mode,
|
||||
attr: Option<&MqAttr>,
|
||||
) -> Result<MqdT> {
|
||||
let res = match attr {
|
||||
) -> Result<MqdT>
|
||||
where
|
||||
P: ?Sized + NixPath,
|
||||
{
|
||||
let res = name.with_nix_path(|cstr| match attr {
|
||||
Some(mq_attr) => unsafe {
|
||||
libc::mq_open(
|
||||
name.as_ptr(),
|
||||
cstr.as_ptr(),
|
||||
oflag.bits(),
|
||||
mode.bits() as libc::c_int,
|
||||
&mq_attr.mq_attr as *const libc::mq_attr,
|
||||
)
|
||||
},
|
||||
None => unsafe { libc::mq_open(name.as_ptr(), oflag.bits()) },
|
||||
};
|
||||
None => unsafe { libc::mq_open(cstr.as_ptr(), oflag.bits()) },
|
||||
})?;
|
||||
|
||||
Errno::result(res).map(MqdT)
|
||||
}
|
||||
|
||||
/// Remove a message queue
|
||||
///
|
||||
/// See also [`mq_unlink(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_unlink.html)
|
||||
pub fn mq_unlink(name: &CStr) -> Result<()> {
|
||||
let res = unsafe { libc::mq_unlink(name.as_ptr()) };
|
||||
pub fn mq_unlink<P>(name: &P) -> Result<()>
|
||||
where
|
||||
P: ?Sized + NixPath,
|
||||
{
|
||||
let res =
|
||||
name.with_nix_path(|cstr| unsafe { libc::mq_unlink(cstr.as_ptr()) })?;
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
@@ -189,7 +203,7 @@ pub fn mq_receive(
|
||||
let res = unsafe {
|
||||
libc::mq_receive(
|
||||
mqdes.0,
|
||||
message.as_mut_ptr() as *mut c_char,
|
||||
message.as_mut_ptr().cast(),
|
||||
len,
|
||||
msg_prio as *mut u32,
|
||||
)
|
||||
@@ -197,17 +211,38 @@ pub fn mq_receive(
|
||||
Errno::result(res).map(|r| r as usize)
|
||||
}
|
||||
|
||||
feature! {
|
||||
#![feature = "time"]
|
||||
use crate::sys::time::TimeSpec;
|
||||
/// Receive a message from a message queue with a timeout
|
||||
///
|
||||
/// See also ['mq_timedreceive(2)'](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_receive.html)
|
||||
pub fn mq_timedreceive(
|
||||
mqdes: &MqdT,
|
||||
message: &mut [u8],
|
||||
msg_prio: &mut u32,
|
||||
abstime: &TimeSpec,
|
||||
) -> Result<usize> {
|
||||
let len = message.len() as size_t;
|
||||
let res = unsafe {
|
||||
libc::mq_timedreceive(
|
||||
mqdes.0,
|
||||
message.as_mut_ptr().cast(),
|
||||
len,
|
||||
msg_prio as *mut u32,
|
||||
abstime.as_ref(),
|
||||
)
|
||||
};
|
||||
Errno::result(res).map(|r| r as usize)
|
||||
}
|
||||
}
|
||||
|
||||
/// Send a message to a message queue
|
||||
///
|
||||
/// See also [`mq_send(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html)
|
||||
pub fn mq_send(mqdes: &MqdT, message: &[u8], msq_prio: u32) -> Result<()> {
|
||||
let res = unsafe {
|
||||
libc::mq_send(
|
||||
mqdes.0,
|
||||
message.as_ptr() as *const c_char,
|
||||
message.len(),
|
||||
msq_prio,
|
||||
)
|
||||
libc::mq_send(mqdes.0, message.as_ptr().cast(), message.len(), msq_prio)
|
||||
};
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
@@ -225,9 +260,11 @@ pub fn mq_getattr(mqd: &MqdT) -> Result<MqAttr> {
|
||||
})
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// 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: &MqdT, newattr: &MqAttr) -> Result<MqAttr> {
|
||||
@@ -274,3 +311,43 @@ pub fn mq_remove_nonblock(mqd: &MqdT) -> Result<MqAttr> {
|
||||
);
|
||||
mq_setattr(mqd, &newattr)
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "netbsd", target_os = "dragonfly"))]
|
||||
impl AsFd for MqdT {
|
||||
/// Borrow the underlying message queue descriptor.
|
||||
fn as_fd(&self) -> BorrowedFd {
|
||||
// SAFETY: [MqdT] will only contain a valid fd by construction.
|
||||
unsafe { BorrowedFd::borrow_raw(self.0) }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "netbsd", target_os = "dragonfly"))]
|
||||
impl AsRawFd for MqdT {
|
||||
/// Return the underlying message queue descriptor.
|
||||
///
|
||||
/// Returned descriptor is a "shallow copy" of the descriptor, so it refers
|
||||
/// to the same underlying kernel object as `self`.
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "netbsd", target_os = "dragonfly"))]
|
||||
impl FromRawFd for MqdT {
|
||||
/// Construct an [MqdT] from [RawFd].
|
||||
///
|
||||
/// # Safety
|
||||
/// The `fd` given must be a valid and open file descriptor for a message
|
||||
/// queue.
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> MqdT {
|
||||
MqdT(fd)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "netbsd", target_os = "dragonfly"))]
|
||||
impl IntoRawFd for MqdT {
|
||||
/// Consume this [MqdT] and return a [RawFd].
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
+143
-208
@@ -3,10 +3,18 @@
|
||||
//! Uses Linux and/or POSIX functions to resolve interface names like "eth0"
|
||||
//! or "socan1" into device numbers.
|
||||
|
||||
use crate::{Error, NixPath, Result};
|
||||
use libc::c_uint;
|
||||
use std::{ffi::{CStr, CString}, fmt};
|
||||
use crate::{errno::Errno, Error, NixPath, Result};
|
||||
use libc::{c_uint, IF_NAMESIZE};
|
||||
|
||||
/// Resolve an interface into a interface number.
|
||||
#[cfg(not(solarish))]
|
||||
/// type alias for InterfaceFlags
|
||||
pub type IflagsType = libc::c_int;
|
||||
#[cfg(solarish)]
|
||||
/// type alias for InterfaceFlags
|
||||
pub type IflagsType = libc::c_longlong;
|
||||
|
||||
/// Resolve an interface into an 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()) })?;
|
||||
@@ -18,324 +26,254 @@ pub fn if_nametoindex<P: ?Sized + NixPath>(name: &P) -> Result<c_uint> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve an interface number into an interface.
|
||||
pub fn if_indextoname(index: c_uint) -> Result<CString> {
|
||||
// We need to allocate this anyway, so doing it directly is faster.
|
||||
let mut buf = vec![0u8; IF_NAMESIZE];
|
||||
|
||||
let return_buf = unsafe {
|
||||
libc::if_indextoname(index, buf.as_mut_ptr().cast())
|
||||
};
|
||||
|
||||
Errno::result(return_buf.cast())?;
|
||||
Ok(CStr::from_bytes_until_nul(buf.as_slice()).unwrap().to_owned())
|
||||
}
|
||||
|
||||
libc_bitflags!(
|
||||
/// Standard interface flags, used by `getifaddrs`
|
||||
pub struct InterfaceFlags: libc::c_int {
|
||||
pub struct InterfaceFlags: IflagsType {
|
||||
|
||||
/// Interface is running. (see
|
||||
/// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
|
||||
IFF_UP;
|
||||
IFF_UP as IflagsType;
|
||||
/// Valid broadcast address set. (see
|
||||
/// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
|
||||
IFF_BROADCAST;
|
||||
IFF_BROADCAST as IflagsType;
|
||||
/// Internal debugging flag. (see
|
||||
/// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
|
||||
#[cfg(not(target_os = "haiku"))]
|
||||
IFF_DEBUG;
|
||||
#[cfg(not(any(target_os = "haiku", target_os = "cygwin")))]
|
||||
IFF_DEBUG as IflagsType;
|
||||
/// Interface is a loopback interface. (see
|
||||
/// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
|
||||
IFF_LOOPBACK;
|
||||
IFF_LOOPBACK as IflagsType;
|
||||
/// Interface is a point-to-point link. (see
|
||||
/// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
|
||||
IFF_POINTOPOINT;
|
||||
IFF_POINTOPOINT as IflagsType;
|
||||
/// Avoid use of trailers. (see
|
||||
/// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(
|
||||
linux_android,
|
||||
solarish,
|
||||
apple_targets,
|
||||
target_os = "fuchsia",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "illumos",
|
||||
target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_NOTRAILERS;
|
||||
target_os = "cygwin"))]
|
||||
IFF_NOTRAILERS as IflagsType;
|
||||
/// Interface manages own routes.
|
||||
#[cfg(any(target_os = "dragonfly"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_SMART;
|
||||
IFF_SMART as IflagsType;
|
||||
/// Resources allocated. (see
|
||||
/// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
|
||||
#[cfg(any(target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
#[cfg(any(
|
||||
linux_android,
|
||||
bsd,
|
||||
solarish,
|
||||
target_os = "fuchsia",
|
||||
target_os = "illumos",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_RUNNING;
|
||||
target_os = "cygwin"))]
|
||||
IFF_RUNNING as IflagsType;
|
||||
/// No arp protocol, L2 destination address not set. (see
|
||||
/// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
|
||||
IFF_NOARP;
|
||||
IFF_NOARP as IflagsType;
|
||||
/// Interface is in promiscuous mode. (see
|
||||
/// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
|
||||
IFF_PROMISC;
|
||||
IFF_PROMISC as IflagsType;
|
||||
/// Receive all multicast packets. (see
|
||||
/// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
|
||||
IFF_ALLMULTI;
|
||||
#[cfg(not(target_os = "cygwin"))]
|
||||
IFF_ALLMULTI as IflagsType;
|
||||
/// Master of a load balancing bundle. (see
|
||||
/// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
|
||||
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(linux_android, target_os = "fuchsia"))]
|
||||
IFF_MASTER;
|
||||
/// transmission in progress, tx hardware queue is full
|
||||
#[cfg(any(target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "ios"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(target_os = "freebsd", apple_targets, netbsdlike))]
|
||||
IFF_OACTIVE;
|
||||
/// Protocol code on board.
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_INTELLIGENT;
|
||||
#[cfg(solarish)]
|
||||
IFF_INTELLIGENT as IflagsType;
|
||||
/// Slave of a load balancing bundle. (see
|
||||
/// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
|
||||
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(linux_android, target_os = "fuchsia"))]
|
||||
IFF_SLAVE;
|
||||
/// Can't hear own transmissions.
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(bsd)]
|
||||
IFF_SIMPLEX;
|
||||
/// Supports multicast. (see
|
||||
/// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
|
||||
IFF_MULTICAST;
|
||||
IFF_MULTICAST as IflagsType;
|
||||
/// Per link layer defined bit.
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "ios"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(bsd)]
|
||||
IFF_LINK0;
|
||||
/// Multicast using broadcast.
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_MULTI_BCAST;
|
||||
#[cfg(solarish)]
|
||||
IFF_MULTI_BCAST as IflagsType;
|
||||
/// Is able to select media type via ifmap. (see
|
||||
/// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
|
||||
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(linux_android, target_os = "fuchsia"))]
|
||||
IFF_PORTSEL;
|
||||
/// Per link layer defined bit.
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "ios"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(bsd)]
|
||||
IFF_LINK1;
|
||||
/// Non-unique address.
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_UNNUMBERED;
|
||||
#[cfg(solarish)]
|
||||
IFF_UNNUMBERED as IflagsType;
|
||||
/// Auto media selection active. (see
|
||||
/// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
|
||||
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(linux_android, target_os = "fuchsia"))]
|
||||
IFF_AUTOMEDIA;
|
||||
/// Per link layer defined bit.
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "ios"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(bsd)]
|
||||
IFF_LINK2;
|
||||
/// Use alternate physical connection.
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "ios"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(freebsdlike, apple_targets))]
|
||||
IFF_ALTPHYS;
|
||||
/// DHCP controls interface.
|
||||
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_DHCPRUNNING;
|
||||
#[cfg(solarish)]
|
||||
IFF_DHCPRUNNING as IflagsType;
|
||||
/// The addresses are lost when the interface goes down. (see
|
||||
/// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
|
||||
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(linux_android, target_os = "fuchsia"))]
|
||||
IFF_DYNAMIC;
|
||||
/// Do not advertise.
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_PRIVATE;
|
||||
#[cfg(solarish)]
|
||||
IFF_PRIVATE as IflagsType;
|
||||
/// Driver signals L1 up. Volatile.
|
||||
#[cfg(any(target_os = "fuchsia", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(target_os = "fuchsia", target_os = "linux", target_os = "cygwin"))]
|
||||
IFF_LOWER_UP;
|
||||
/// Interface is in polling mode.
|
||||
#[cfg(any(target_os = "dragonfly"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_POLLING_COMPAT;
|
||||
/// Unconfigurable using ioctl(2).
|
||||
#[cfg(any(target_os = "freebsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_CANTCONFIG;
|
||||
/// Do not transmit packets.
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_NOXMIT;
|
||||
#[cfg(solarish)]
|
||||
IFF_NOXMIT as IflagsType;
|
||||
/// Driver signals dormant. Volatile.
|
||||
#[cfg(any(target_os = "fuchsia", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(target_os = "fuchsia", target_os = "linux", target_os = "cygwin"))]
|
||||
IFF_DORMANT;
|
||||
/// User-requested promisc mode.
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
IFF_PPROMISC;
|
||||
/// Just on-link subnet.
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_NOLOCAL;
|
||||
#[cfg(solarish)]
|
||||
IFF_NOLOCAL as IflagsType;
|
||||
/// Echo sent packets. Volatile.
|
||||
#[cfg(any(target_os = "fuchsia", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_ECHO;
|
||||
/// User-requested monitor mode.
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
IFF_MONITOR;
|
||||
/// Address is deprecated.
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_DEPRECATED;
|
||||
#[cfg(solarish)]
|
||||
IFF_DEPRECATED as IflagsType;
|
||||
/// Static ARP.
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
IFF_STATICARP;
|
||||
/// Address from stateless addrconf.
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_ADDRCONF;
|
||||
#[cfg(solarish)]
|
||||
IFF_ADDRCONF as IflagsType;
|
||||
/// Interface is in polling mode.
|
||||
#[cfg(any(target_os = "dragonfly"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_NPOLLING;
|
||||
/// Router on interface.
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_ROUTER;
|
||||
#[cfg(solarish)]
|
||||
IFF_ROUTER as IflagsType;
|
||||
/// Interface is in polling mode.
|
||||
#[cfg(any(target_os = "dragonfly"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_IDIRECT;
|
||||
/// Interface is winding down
|
||||
#[cfg(any(target_os = "freebsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_DYING;
|
||||
/// No NUD on interface.
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_NONUD;
|
||||
#[cfg(solarish)]
|
||||
IFF_NONUD as IflagsType;
|
||||
/// Interface is being renamed
|
||||
#[cfg(any(target_os = "freebsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_RENAMING;
|
||||
/// Anycast address.
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_ANYCAST;
|
||||
#[cfg(solarish)]
|
||||
IFF_ANYCAST as IflagsType;
|
||||
/// Don't exchange routing info.
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_NORTEXCH;
|
||||
#[cfg(solarish)]
|
||||
IFF_NORTEXCH as IflagsType;
|
||||
/// Do not provide packet information
|
||||
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_NO_PI as libc::c_int;
|
||||
#[cfg(any(linux_android, target_os = "fuchsia"))]
|
||||
IFF_NO_PI as IflagsType;
|
||||
/// TUN device (no Ethernet headers)
|
||||
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_TUN as libc::c_int;
|
||||
#[cfg(any(linux_android, target_os = "fuchsia"))]
|
||||
IFF_TUN as IflagsType;
|
||||
/// TAP device
|
||||
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_TAP as libc::c_int;
|
||||
#[cfg(any(linux_android, target_os = "fuchsia"))]
|
||||
IFF_TAP as IflagsType;
|
||||
/// IPv4 interface.
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_IPV4;
|
||||
#[cfg(solarish)]
|
||||
IFF_IPV4 as IflagsType;
|
||||
/// IPv6 interface.
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_IPV6;
|
||||
#[cfg(solarish)]
|
||||
IFF_IPV6 as IflagsType;
|
||||
/// in.mpathd test address
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_NOFAILOVER;
|
||||
#[cfg(solarish)]
|
||||
IFF_NOFAILOVER as IflagsType;
|
||||
/// Interface has failed
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_FAILED;
|
||||
#[cfg(solarish)]
|
||||
IFF_FAILED as IflagsType;
|
||||
/// Interface is a hot-spare
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_STANDBY;
|
||||
#[cfg(solarish)]
|
||||
IFF_STANDBY as IflagsType;
|
||||
/// Functioning but not used
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_INACTIVE;
|
||||
#[cfg(solarish)]
|
||||
IFF_INACTIVE as IflagsType;
|
||||
/// Interface is offline
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_OFFLINE;
|
||||
#[cfg(target_os = "solaris")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_COS_ENABLED;
|
||||
/// Prefer as source addr.
|
||||
#[cfg(target_os = "solaris")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_PREFERRED;
|
||||
#[cfg(solarish)]
|
||||
IFF_OFFLINE as IflagsType;
|
||||
/// Has CoS marking supported
|
||||
#[cfg(solarish)]
|
||||
IFF_COS_ENABLED as IflagsType;
|
||||
/// Prefer as source addr
|
||||
#[cfg(solarish)]
|
||||
IFF_PREFERRED as IflagsType;
|
||||
/// RFC3041
|
||||
#[cfg(target_os = "solaris")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_TEMPORARY;
|
||||
/// MTU set with SIOCSLIFMTU
|
||||
#[cfg(target_os = "solaris")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_FIXEDMTU;
|
||||
/// Cannot send / receive packets
|
||||
#[cfg(target_os = "solaris")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_VIRTUAL;
|
||||
#[cfg(solarish)]
|
||||
IFF_TEMPORARY as IflagsType;
|
||||
/// MTU set
|
||||
#[cfg(solarish)]
|
||||
IFF_FIXEDMTU as IflagsType;
|
||||
/// Cannot send/receive packets
|
||||
#[cfg(solarish)]
|
||||
IFF_VIRTUAL as IflagsType;
|
||||
/// Local address in use
|
||||
#[cfg(target_os = "solaris")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_DUPLICATE;
|
||||
#[cfg(solarish)]
|
||||
IFF_DUPLICATE as IflagsType;
|
||||
/// IPMP IP interface
|
||||
#[cfg(target_os = "solaris")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IFF_IPMP;
|
||||
#[cfg(solarish)]
|
||||
IFF_IPMP as IflagsType;
|
||||
}
|
||||
);
|
||||
|
||||
impl fmt::Display for InterfaceFlags {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
bitflags::parser::to_writer(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
bsd,
|
||||
target_os = "fuchsia",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
solarish,
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
mod if_nameindex {
|
||||
use super::*;
|
||||
|
||||
@@ -372,6 +310,7 @@ mod if_nameindex {
|
||||
}
|
||||
|
||||
/// A list of the network interfaces available on this system. Obtained from [`if_nameindex()`].
|
||||
#[repr(transparent)]
|
||||
pub struct Interfaces {
|
||||
ptr: NonNull<libc::if_nameindex>,
|
||||
}
|
||||
@@ -387,7 +326,7 @@ mod if_nameindex {
|
||||
/// null-terminated, so calling this calculates the length. If random access isn't needed,
|
||||
/// [`Interfaces::iter()`] should be used instead.
|
||||
pub fn to_slice(&self) -> &[Interface] {
|
||||
let ifs = self.ptr.as_ptr() as *const Interface;
|
||||
let ifs = self.ptr.as_ptr().cast();
|
||||
let len = self.iter().count();
|
||||
unsafe { std::slice::from_raw_parts(ifs, len) }
|
||||
}
|
||||
@@ -457,13 +396,9 @@ mod if_nameindex {
|
||||
}
|
||||
}
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
bsd,
|
||||
target_os = "fuchsia",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
solarish,
|
||||
))]
|
||||
pub use if_nameindex::*;
|
||||
|
||||
+101
-29
@@ -1,7 +1,8 @@
|
||||
//! Wait for events to trigger on specific file descriptors
|
||||
use std::os::unix::io::{AsRawFd, RawFd};
|
||||
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd};
|
||||
|
||||
use crate::errno::Errno;
|
||||
pub use crate::poll_timeout::{PollTimeout, PollTimeoutTryFromError};
|
||||
use crate::Result;
|
||||
|
||||
/// This is a wrapper around `libc::pollfd`.
|
||||
@@ -10,30 +11,54 @@ use crate::Result;
|
||||
/// [`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 occurred can be
|
||||
/// retrieved by calling [`revents()`](#method.revents) on the `PollFd`.
|
||||
/// After a call to `poll` or `ppoll`, the events that occurred can be retrieved by calling
|
||||
/// [`revents()`](#method.revents) on the `PollFd` object from the array passed to `poll`.
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct PollFd {
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct PollFd<'fd> {
|
||||
pollfd: libc::pollfd,
|
||||
_fd: std::marker::PhantomData<BorrowedFd<'fd>>,
|
||||
}
|
||||
|
||||
impl PollFd {
|
||||
impl<'fd> PollFd<'fd> {
|
||||
/// Creates a new `PollFd` specifying the events of interest
|
||||
/// for a given file descriptor.
|
||||
pub const fn new(fd: RawFd, events: PollFlags) -> PollFd {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```no_run
|
||||
/// # use std::os::unix::io::{AsFd, AsRawFd, FromRawFd};
|
||||
/// # use nix::{
|
||||
/// # poll::{PollTimeout, PollFd, PollFlags, poll},
|
||||
/// # unistd::{pipe, read}
|
||||
/// # };
|
||||
/// let (r, w) = pipe().unwrap();
|
||||
/// let pfd = PollFd::new(r.as_fd(), PollFlags::POLLIN);
|
||||
/// ```
|
||||
/// These are placed in an array and passed to [`poll`] or [`ppoll`](fn.ppoll.html).
|
||||
// Unlike I/O functions, constructors like this must take `BorrowedFd`
|
||||
// instead of AsFd or &AsFd. Otherwise, an `OwnedFd` argument would be
|
||||
// dropped at the end of the method, leaving the structure referencing a
|
||||
// closed file descriptor. For example:
|
||||
//
|
||||
// ```rust
|
||||
// let (r, _) = pipe().unwrap();
|
||||
// let pollfd = PollFd::new(r, flag); // Drops the OwnedFd
|
||||
// // Do something with `pollfd`, which uses the CLOSED fd.
|
||||
// ```
|
||||
pub fn new(fd: BorrowedFd<'fd>, events: PollFlags) -> PollFd<'fd> {
|
||||
PollFd {
|
||||
pollfd: libc::pollfd {
|
||||
fd,
|
||||
fd: fd.as_raw_fd(),
|
||||
events: events.bits(),
|
||||
revents: PollFlags::empty().bits(),
|
||||
},
|
||||
_fd: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the events that occurred 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> {
|
||||
pub fn revents(&self) -> Option<PollFlags> {
|
||||
PollFlags::from_bits(self.pollfd.revents)
|
||||
}
|
||||
|
||||
@@ -43,7 +68,7 @@ impl PollFd {
|
||||
/// Equivalent to `x.revents()? != PollFlags::empty()`.
|
||||
///
|
||||
/// This is marginally more efficient than [`PollFd::all`].
|
||||
pub fn any(self) -> Option<bool> {
|
||||
pub fn any(&self) -> Option<bool> {
|
||||
Some(self.revents()? != PollFlags::empty())
|
||||
}
|
||||
|
||||
@@ -53,12 +78,12 @@ impl PollFd {
|
||||
/// Equivalent to `x.revents()? & x.events() == x.events()`.
|
||||
///
|
||||
/// This is marginally less efficient than [`PollFd::any`].
|
||||
pub fn all(self) -> Option<bool> {
|
||||
pub fn all(&self) -> Option<bool> {
|
||||
Some(self.revents()? & self.events() == self.events())
|
||||
}
|
||||
|
||||
/// The events of interest for this `PollFd`.
|
||||
pub fn events(self) -> PollFlags {
|
||||
pub fn events(&self) -> PollFlags {
|
||||
PollFlags::from_bits(self.pollfd.events).unwrap()
|
||||
}
|
||||
|
||||
@@ -68,9 +93,29 @@ impl PollFd {
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for PollFd {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.pollfd.fd
|
||||
impl AsFd for PollFd<'_> {
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
// Safety:
|
||||
//
|
||||
// BorrowedFd::borrow_raw(RawFd) requires that the raw fd being passed
|
||||
// must remain open for the duration of the returned BorrowedFd, this is
|
||||
// guaranteed as the returned BorrowedFd has the lifetime parameter same
|
||||
// as `self`:
|
||||
// "fn as_fd<'self>(&'self self) -> BorrowedFd<'self>"
|
||||
// which means that `self` (PollFd) is guaranteed to outlive the returned
|
||||
// BorrowedFd. (Lifetime: PollFd > BorrowedFd)
|
||||
//
|
||||
// And the lifetime parameter of PollFd::new(fd, ...) ensures that `fd`
|
||||
// (an owned file descriptor) must outlive the returned PollFd:
|
||||
// "pub fn new<Fd: AsFd>(fd: &'fd Fd, events: PollFlags) -> PollFd<'fd>"
|
||||
// (Lifetime: Owned fd > PollFd)
|
||||
//
|
||||
// With two above relationships, we can conclude that the `Owned file
|
||||
// descriptor` will outlive the returned BorrowedFd,
|
||||
// (Lifetime: Owned fd > BorrowedFd)
|
||||
// i.e., the raw fd being passed will remain valid for the lifetime of
|
||||
// the returned BorrowedFd.
|
||||
unsafe { BorrowedFd::borrow_raw(self.pollfd.fd) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,19 +142,15 @@ libc_bitflags! {
|
||||
POLLOUT;
|
||||
/// Equivalent to [`POLLIN`](constant.POLLIN.html)
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
POLLRDNORM;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
/// Equivalent to [`POLLOUT`](constant.POLLOUT.html)
|
||||
POLLWRNORM;
|
||||
/// Priority band data can be read (generally unused on Linux).
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
POLLRDBAND;
|
||||
/// Priority data may be written.
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
POLLWRBAND;
|
||||
/// Error condition (only returned in
|
||||
/// [`PollFd::revents`](struct.PollFd.html#method.revents);
|
||||
@@ -148,16 +189,47 @@ libc_bitflags! {
|
||||
///
|
||||
/// Note that the timeout interval will be rounded up to the system clock
|
||||
/// granularity, and kernel scheduling delays mean that the blocking
|
||||
/// interval may overrun by a small amount. Specifying a negative value
|
||||
/// in timeout means an infinite timeout. Specifying a timeout of zero
|
||||
/// causes `poll()` to return immediately, even if no file descriptors are
|
||||
/// ready.
|
||||
pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result<libc::c_int> {
|
||||
/// interval may overrun by a small amount. Specifying a [`PollTimeout::NONE`]
|
||||
/// in timeout means an infinite timeout. Specifying a timeout of
|
||||
/// [`PollTimeout::ZERO`] causes `poll()` to return immediately, even if no file
|
||||
/// descriptors are ready.
|
||||
///
|
||||
/// The return value contains the number of `fds` which have selected events ([`PollFd::revents`]).
|
||||
///
|
||||
/// # Examples
|
||||
/// ```no_run
|
||||
/// # use std::os::unix::io::{AsFd, AsRawFd, FromRawFd};
|
||||
/// # use nix::{
|
||||
/// # poll::{PollTimeout, PollFd, PollFlags, poll},
|
||||
/// # unistd::{pipe, read}
|
||||
/// # };
|
||||
/// let (r0, w0) = pipe().unwrap();
|
||||
/// let (r1, w1) = pipe().unwrap();
|
||||
///
|
||||
/// let mut pollfds = [
|
||||
/// PollFd::new(r0.as_fd(), PollFlags::POLLIN),
|
||||
/// PollFd::new(r1.as_fd(), PollFlags::POLLIN),
|
||||
/// ];
|
||||
///
|
||||
/// let nready = poll(&mut pollfds, PollTimeout::NONE).unwrap();
|
||||
/// assert!(nready >= 1); // Since there is no timeout
|
||||
///
|
||||
/// let mut buf = [0u8; 80];
|
||||
/// if pollfds[0].any().unwrap_or_default() {
|
||||
/// read(&r0, &mut buf[..]);
|
||||
/// } else if pollfds[1].any().unwrap_or_default() {
|
||||
/// read(&r1, &mut buf[..]);
|
||||
/// }
|
||||
/// ```
|
||||
pub fn poll<T: Into<PollTimeout>>(
|
||||
fds: &mut [PollFd],
|
||||
timeout: T,
|
||||
) -> Result<libc::c_int> {
|
||||
let res = unsafe {
|
||||
libc::poll(
|
||||
fds.as_mut_ptr() as *mut libc::pollfd,
|
||||
fds.as_mut_ptr().cast(),
|
||||
fds.len() as libc::nfds_t,
|
||||
timeout,
|
||||
i32::from(timeout.into()),
|
||||
)
|
||||
};
|
||||
|
||||
@@ -170,14 +242,14 @@ feature! {
|
||||
/// 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
|
||||
/// `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`).
|
||||
/// If `sigmask` is `None`, then no signal mask manipulation is performed,
|
||||
/// so in that case `ppoll` differs from `poll` only in the precision of the
|
||||
/// timeout argument.
|
||||
///
|
||||
#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
|
||||
#[cfg(any(linux_android, freebsdlike))]
|
||||
pub fn ppoll(
|
||||
fds: &mut [PollFd],
|
||||
timeout: Option<crate::sys::time::TimeSpec>,
|
||||
@@ -187,7 +259,7 @@ pub fn ppoll(
|
||||
let timeout = timeout.as_ref().map_or(core::ptr::null(), |r| r.as_ref());
|
||||
let sigmask = sigmask.as_ref().map_or(core::ptr::null(), |r| r.as_ref());
|
||||
let res = unsafe {
|
||||
libc::ppoll(fds.as_mut_ptr() as *mut libc::pollfd,
|
||||
libc::ppoll(fds.as_mut_ptr().cast(),
|
||||
fds.len() as libc::nfds_t,
|
||||
timeout,
|
||||
sigmask)
|
||||
|
||||
@@ -0,0 +1,224 @@
|
||||
use std::time::Duration;
|
||||
|
||||
/// PollTimeout argument for polling.
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub struct PollTimeout(i32);
|
||||
|
||||
impl PollTimeout {
|
||||
/// Blocks indefinitely.
|
||||
///
|
||||
/// > Specifying a negative value in timeout means an infinite timeout.
|
||||
pub const NONE: Self = Self(-1);
|
||||
/// Returns immediately.
|
||||
///
|
||||
/// > Specifying a timeout of zero causes poll() to return immediately, even if no file
|
||||
/// > descriptors are ready.
|
||||
pub const ZERO: Self = Self(0);
|
||||
/// Blocks for at most [`i32::MAX`] milliseconds.
|
||||
pub const MAX: Self = Self(i32::MAX);
|
||||
/// Returns if `self` equals [`PollTimeout::NONE`].
|
||||
pub fn is_none(&self) -> bool {
|
||||
// > Specifying a negative value in timeout means an infinite timeout.
|
||||
*self <= Self::NONE
|
||||
}
|
||||
/// Returns if `self` does not equal [`PollTimeout::NONE`].
|
||||
pub fn is_some(&self) -> bool {
|
||||
!self.is_none()
|
||||
}
|
||||
/// Returns the timeout in milliseconds if there is some, otherwise returns `None`.
|
||||
pub fn as_millis(&self) -> Option<u32> {
|
||||
self.is_some().then_some(u32::try_from(self.0).unwrap())
|
||||
}
|
||||
/// Returns the timeout as a `Duration` if there is some, otherwise returns `None`.
|
||||
pub fn duration(&self) -> Option<Duration> {
|
||||
self.as_millis()
|
||||
.map(|x| Duration::from_millis(u64::from(x)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Error type for integer conversions into `PollTimeout`.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum PollTimeoutTryFromError {
|
||||
/// Passing a value less than -1 is invalid on some systems, see
|
||||
/// <https://man.freebsd.org/cgi/man.cgi?poll#end>.
|
||||
TooNegative,
|
||||
/// Passing a value greater than `i32::MAX` is invalid.
|
||||
TooPositive,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for PollTimeoutTryFromError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::TooNegative => write!(f, "Passed a negative timeout less than -1."),
|
||||
Self::TooPositive => write!(f, "Passed a positive timeout greater than `i32::MAX` milliseconds.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for PollTimeoutTryFromError {}
|
||||
|
||||
impl<T: Into<PollTimeout>> From<Option<T>> for PollTimeout {
|
||||
fn from(x: Option<T>) -> Self {
|
||||
x.map_or(Self::NONE, |x| x.into())
|
||||
}
|
||||
}
|
||||
impl TryFrom<Duration> for PollTimeout {
|
||||
type Error = PollTimeoutTryFromError;
|
||||
fn try_from(x: Duration) -> std::result::Result<Self, Self::Error> {
|
||||
Ok(Self(
|
||||
i32::try_from(x.as_millis())
|
||||
.map_err(|_| PollTimeoutTryFromError::TooPositive)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
impl TryFrom<u128> for PollTimeout {
|
||||
type Error = PollTimeoutTryFromError;
|
||||
fn try_from(x: u128) -> std::result::Result<Self, Self::Error> {
|
||||
Ok(Self(
|
||||
i32::try_from(x)
|
||||
.map_err(|_| PollTimeoutTryFromError::TooPositive)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
impl TryFrom<u64> for PollTimeout {
|
||||
type Error = PollTimeoutTryFromError;
|
||||
fn try_from(x: u64) -> std::result::Result<Self, Self::Error> {
|
||||
Ok(Self(
|
||||
i32::try_from(x)
|
||||
.map_err(|_| PollTimeoutTryFromError::TooPositive)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
impl TryFrom<u32> for PollTimeout {
|
||||
type Error = PollTimeoutTryFromError;
|
||||
fn try_from(x: u32) -> std::result::Result<Self, Self::Error> {
|
||||
Ok(Self(
|
||||
i32::try_from(x)
|
||||
.map_err(|_| PollTimeoutTryFromError::TooPositive)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
impl From<u16> for PollTimeout {
|
||||
fn from(x: u16) -> Self {
|
||||
Self(i32::from(x))
|
||||
}
|
||||
}
|
||||
impl From<u8> for PollTimeout {
|
||||
fn from(x: u8) -> Self {
|
||||
Self(i32::from(x))
|
||||
}
|
||||
}
|
||||
impl TryFrom<i128> for PollTimeout {
|
||||
type Error = PollTimeoutTryFromError;
|
||||
fn try_from(x: i128) -> std::result::Result<Self, Self::Error> {
|
||||
match x {
|
||||
..=-2 => Err(PollTimeoutTryFromError::TooNegative),
|
||||
-1.. => Ok(Self(
|
||||
i32::try_from(x)
|
||||
.map_err(|_| PollTimeoutTryFromError::TooPositive)?,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl TryFrom<i64> for PollTimeout {
|
||||
type Error = PollTimeoutTryFromError;
|
||||
fn try_from(x: i64) -> std::result::Result<Self, Self::Error> {
|
||||
match x {
|
||||
..=-2 => Err(PollTimeoutTryFromError::TooNegative),
|
||||
-1.. => Ok(Self(
|
||||
i32::try_from(x)
|
||||
.map_err(|_| PollTimeoutTryFromError::TooPositive)?,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl TryFrom<i32> for PollTimeout {
|
||||
type Error = PollTimeoutTryFromError;
|
||||
fn try_from(x: i32) -> std::result::Result<Self, Self::Error> {
|
||||
match x {
|
||||
..=-2 => Err(PollTimeoutTryFromError::TooNegative),
|
||||
-1.. => Ok(Self(x)),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl TryFrom<i16> for PollTimeout {
|
||||
type Error = PollTimeoutTryFromError;
|
||||
fn try_from(x: i16) -> std::result::Result<Self, Self::Error> {
|
||||
match x {
|
||||
..=-2 => Err(PollTimeoutTryFromError::TooNegative),
|
||||
-1.. => Ok(Self(i32::from(x))),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl TryFrom<i8> for PollTimeout {
|
||||
type Error = PollTimeoutTryFromError;
|
||||
fn try_from(x: i8) -> std::result::Result<Self, Self::Error> {
|
||||
match x {
|
||||
..=-2 => Err(PollTimeoutTryFromError::TooNegative),
|
||||
-1.. => Ok(Self(i32::from(x))),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl TryFrom<PollTimeout> for Duration {
|
||||
type Error = ();
|
||||
fn try_from(x: PollTimeout) -> std::result::Result<Self, ()> {
|
||||
x.duration().ok_or(())
|
||||
}
|
||||
}
|
||||
impl TryFrom<PollTimeout> for u128 {
|
||||
type Error = <Self as TryFrom<i32>>::Error;
|
||||
fn try_from(x: PollTimeout) -> std::result::Result<Self, Self::Error> {
|
||||
Self::try_from(x.0)
|
||||
}
|
||||
}
|
||||
impl TryFrom<PollTimeout> for u64 {
|
||||
type Error = <Self as TryFrom<i32>>::Error;
|
||||
fn try_from(x: PollTimeout) -> std::result::Result<Self, Self::Error> {
|
||||
Self::try_from(x.0)
|
||||
}
|
||||
}
|
||||
impl TryFrom<PollTimeout> for u32 {
|
||||
type Error = <Self as TryFrom<i32>>::Error;
|
||||
fn try_from(x: PollTimeout) -> std::result::Result<Self, Self::Error> {
|
||||
Self::try_from(x.0)
|
||||
}
|
||||
}
|
||||
impl TryFrom<PollTimeout> for u16 {
|
||||
type Error = <Self as TryFrom<i32>>::Error;
|
||||
fn try_from(x: PollTimeout) -> std::result::Result<Self, Self::Error> {
|
||||
Self::try_from(x.0)
|
||||
}
|
||||
}
|
||||
impl TryFrom<PollTimeout> for u8 {
|
||||
type Error = <Self as TryFrom<i32>>::Error;
|
||||
fn try_from(x: PollTimeout) -> std::result::Result<Self, Self::Error> {
|
||||
Self::try_from(x.0)
|
||||
}
|
||||
}
|
||||
impl From<PollTimeout> for i128 {
|
||||
fn from(x: PollTimeout) -> Self {
|
||||
Self::from(x.0)
|
||||
}
|
||||
}
|
||||
impl From<PollTimeout> for i64 {
|
||||
fn from(x: PollTimeout) -> Self {
|
||||
Self::from(x.0)
|
||||
}
|
||||
}
|
||||
impl From<PollTimeout> for i32 {
|
||||
fn from(x: PollTimeout) -> Self {
|
||||
x.0
|
||||
}
|
||||
}
|
||||
impl TryFrom<PollTimeout> for i16 {
|
||||
type Error = <Self as TryFrom<i32>>::Error;
|
||||
fn try_from(x: PollTimeout) -> std::result::Result<Self, Self::Error> {
|
||||
Self::try_from(x.0)
|
||||
}
|
||||
}
|
||||
impl TryFrom<PollTimeout> for i8 {
|
||||
type Error = <Self as TryFrom<i32>>::Error;
|
||||
fn try_from(x: PollTimeout) -> std::result::Result<Self, Self::Error> {
|
||||
Self::try_from(x.0)
|
||||
}
|
||||
}
|
||||
+89
-67
@@ -5,89 +5,98 @@ pub use libc::winsize as Winsize;
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::io;
|
||||
#[cfg(not(target_os = "aix"))]
|
||||
use std::mem;
|
||||
use std::os::unix::prelude::*;
|
||||
|
||||
use crate::errno::Errno;
|
||||
#[cfg(not(target_os = "aix"))]
|
||||
use crate::sys::termios::Termios;
|
||||
#[cfg(feature = "process")]
|
||||
use crate::unistd::{ForkResult, Pid};
|
||||
#[cfg(all(feature = "process", not(target_os = "aix")))]
|
||||
use crate::unistd::Pid;
|
||||
use crate::{fcntl, unistd, Result};
|
||||
|
||||
/// Representation of a master/slave pty pair
|
||||
///
|
||||
/// This is returned by `openpty`. Note that this type does *not* implement `Drop`, so the user
|
||||
/// must manually close the file descriptors.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
/// This is returned by [`openpty`].
|
||||
#[derive(Debug)]
|
||||
pub struct OpenptyResult {
|
||||
/// The master port in a virtual pty pair
|
||||
pub master: RawFd,
|
||||
pub master: OwnedFd,
|
||||
/// The slave port in a virtual pty pair
|
||||
pub slave: RawFd,
|
||||
pub slave: OwnedFd,
|
||||
}
|
||||
|
||||
feature! {
|
||||
#![feature = "process"]
|
||||
/// Representation of a master with a forked pty
|
||||
///
|
||||
/// This is returned by `forkpty`. Note that this type does *not* implement `Drop`, so the user
|
||||
/// must manually close the file descriptors.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct ForkptyResult {
|
||||
/// The master port in a virtual pty pair
|
||||
pub master: RawFd,
|
||||
/// Metadata about forked process
|
||||
pub fork_result: ForkResult,
|
||||
/// A successful result of [`forkpty()`].
|
||||
#[derive(Debug)]
|
||||
pub enum ForkptyResult {
|
||||
/// This is the parent process of the underlying fork.
|
||||
Parent {
|
||||
/// The PID of the fork's child process
|
||||
child: Pid,
|
||||
/// A file descriptor referring to master side of the pseudoterminal of
|
||||
/// the child process.
|
||||
master: OwnedFd,
|
||||
},
|
||||
/// This is the child process of the underlying fork.
|
||||
Child,
|
||||
}
|
||||
}
|
||||
|
||||
/// Representation of the Master device in a master/slave pty pair
|
||||
///
|
||||
/// While this datatype is a thin wrapper around `RawFd`, it enforces that the available PTY
|
||||
/// functions are given the correct file descriptor. Additionally this type implements `Drop`,
|
||||
/// so that when it's consumed or goes out of scope, it's automatically cleaned-up.
|
||||
#[derive(Debug, Eq, Hash, PartialEq)]
|
||||
pub struct PtyMaster(RawFd);
|
||||
/// While this datatype is a thin wrapper around `OwnedFd`, it enforces that the available PTY
|
||||
/// functions are given the correct file descriptor.
|
||||
#[derive(Debug)]
|
||||
pub struct PtyMaster(OwnedFd);
|
||||
|
||||
impl PtyMaster {
|
||||
/// Constructs a `PytMaster` wrapping an existing `OwnedFd`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `OwnedFd` is a valid `PtyMaster`.
|
||||
pub unsafe fn from_owned_fd(fd: OwnedFd) -> Self {
|
||||
Self(fd)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for PtyMaster {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsFd for PtyMaster {
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
self.0.as_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PtyMaster> for OwnedFd {
|
||||
fn from(value: PtyMaster) -> Self {
|
||||
value.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!");
|
||||
};
|
||||
fd.into_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl io::Read for PtyMaster {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
unistd::read(self.0, buf).map_err(io::Error::from)
|
||||
unistd::read(&self.0, buf).map_err(io::Error::from)
|
||||
}
|
||||
}
|
||||
|
||||
impl io::Write for PtyMaster {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
unistd::write(self.0, buf).map_err(io::Error::from)
|
||||
unistd::write(&self.0, buf).map_err(io::Error::from)
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
@@ -96,13 +105,13 @@ impl io::Write for PtyMaster {
|
||||
|
||||
impl io::Read for &PtyMaster {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
unistd::read(self.0, buf).map_err(io::Error::from)
|
||||
unistd::read(&self.0, buf).map_err(io::Error::from)
|
||||
}
|
||||
}
|
||||
|
||||
impl io::Write for &PtyMaster {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
unistd::write(self.0, buf).map_err(io::Error::from)
|
||||
unistd::write(&self.0, buf).map_err(io::Error::from)
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
@@ -164,7 +173,7 @@ pub fn posix_openpt(flags: fcntl::OFlag) -> Result<PtyMaster> {
|
||||
return Err(Errno::last());
|
||||
}
|
||||
|
||||
Ok(PtyMaster(fd))
|
||||
Ok(PtyMaster(unsafe { OwnedFd::from_raw_fd(fd) }))
|
||||
}
|
||||
|
||||
/// Get the name of the slave pseudoterminal (see
|
||||
@@ -185,12 +194,12 @@ pub fn posix_openpt(flags: fcntl::OFlag) -> Result<PtyMaster> {
|
||||
/// For a threadsafe and non-`unsafe` alternative on Linux, see `ptsname_r()`.
|
||||
#[inline]
|
||||
pub unsafe fn ptsname(fd: &PtyMaster) -> Result<String> {
|
||||
let name_ptr = libc::ptsname(fd.as_raw_fd());
|
||||
let name_ptr = unsafe { libc::ptsname(fd.as_raw_fd()) };
|
||||
if name_ptr.is_null() {
|
||||
return Err(Errno::last());
|
||||
}
|
||||
|
||||
let name = CStr::from_ptr(name_ptr);
|
||||
let name = unsafe { CStr::from_ptr(name_ptr) };
|
||||
Ok(name.to_string_lossy().into_owned())
|
||||
}
|
||||
|
||||
@@ -203,8 +212,7 @@ pub unsafe fn ptsname(fd: &PtyMaster) -> Result<String> {
|
||||
///
|
||||
/// This value is useful for opening the slave ptty once the master has already been opened with
|
||||
/// `posix_openpt()`.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
#[inline]
|
||||
pub fn ptsname_r(fd: &PtyMaster) -> Result<String> {
|
||||
let mut name_buf = Vec::<libc::c_char>::with_capacity(64);
|
||||
@@ -244,6 +252,7 @@ pub fn unlockpt(fd: &PtyMaster) -> Result<()> {
|
||||
/// the values in `winsize`. If `termios` is not `None`, the pseudoterminal's
|
||||
/// terminal settings of the slave will be set to the values in `termios`.
|
||||
#[inline]
|
||||
#[cfg(not(target_os = "aix"))]
|
||||
pub fn openpty<
|
||||
'a,
|
||||
'b,
|
||||
@@ -308,17 +317,15 @@ pub fn openpty<
|
||||
|
||||
unsafe {
|
||||
Ok(OpenptyResult {
|
||||
master: master.assume_init(),
|
||||
slave: slave.assume_init(),
|
||||
master: OwnedFd::from_raw_fd(master.assume_init()),
|
||||
slave: OwnedFd::from_raw_fd(slave.assume_init()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
feature! {
|
||||
#![feature = "process"]
|
||||
/// 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)).
|
||||
/// Create a new process operating in a pseudoterminal.
|
||||
///
|
||||
/// 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
|
||||
@@ -327,14 +334,20 @@ feature! {
|
||||
/// # 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.
|
||||
/// and `_exit` may be called by the child (the parent isn't restricted) until
|
||||
/// a call of `execve(2)`. 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
|
||||
///
|
||||
/// # Reference
|
||||
///
|
||||
/// * [FreeBSD](https://man.freebsd.org/cgi/man.cgi?query=forkpty)
|
||||
/// * [Linux](https://man7.org/linux/man-pages/man3/forkpty.3.html)
|
||||
#[cfg(not(target_os = "aix"))]
|
||||
pub unsafe fn forkpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>>>(
|
||||
winsize: T,
|
||||
termios: U,
|
||||
@@ -356,16 +369,25 @@ pub unsafe fn forkpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b T
|
||||
.map(|ws| ws as *const Winsize as *mut _)
|
||||
.unwrap_or(ptr::null_mut());
|
||||
|
||||
let res = libc::forkpty(master.as_mut_ptr(), ptr::null_mut(), term, win);
|
||||
let res = unsafe { libc::forkpty(master.as_mut_ptr(), ptr::null_mut(), term, win) };
|
||||
|
||||
let fork_result = Errno::result(res).map(|res| match res {
|
||||
0 => ForkResult::Child,
|
||||
res => ForkResult::Parent { child: Pid::from_raw(res) },
|
||||
})?;
|
||||
let success_ret = Errno::result(res)?;
|
||||
let forkpty_result = match success_ret {
|
||||
// In the child process
|
||||
0 => ForkptyResult::Child,
|
||||
// In the parent process
|
||||
child_pid => {
|
||||
// SAFETY:
|
||||
// 1. The master buffer is guaranteed to be initialized in the parent process
|
||||
// 2. OwnedFd::from_raw_fd won't panic as the fd is a valid file descriptor
|
||||
let master = unsafe { OwnedFd::from_raw_fd( master.assume_init() ) };
|
||||
ForkptyResult::Parent {
|
||||
master,
|
||||
child: Pid::from_raw(child_pid),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(ForkptyResult {
|
||||
master: master.assume_init(),
|
||||
fork_result,
|
||||
})
|
||||
Ok(forkpty_result)
|
||||
}
|
||||
}
|
||||
|
||||
+23
-21
@@ -4,11 +4,10 @@
|
||||
//! [sched.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sched.h.html)
|
||||
use crate::{Errno, Result};
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
pub use self::sched_linux_like::*;
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
mod sched_linux_like {
|
||||
use crate::errno::Errno;
|
||||
use crate::unistd::Pid;
|
||||
@@ -16,7 +15,7 @@ mod sched_linux_like {
|
||||
use libc::{self, c_int, c_void};
|
||||
use std::mem;
|
||||
use std::option::Option;
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::os::unix::io::{AsFd, AsRawFd};
|
||||
|
||||
// For some functions taking with a parameter of type CloneFlags,
|
||||
// only a subset of these flags have an effect.
|
||||
@@ -95,7 +94,17 @@ mod sched_linux_like {
|
||||
/// address need not be the highest address of the region. Nix will take
|
||||
/// care of that requirement. The user only needs to provide a reference to
|
||||
/// a normally allocated buffer.
|
||||
pub fn clone(
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Because `clone` creates a child process with its stack located in
|
||||
/// `stack` without specifying the size of the stack, special care must be
|
||||
/// taken to ensure that the child process does not overflow the provided
|
||||
/// stack space.
|
||||
///
|
||||
/// See [`fork`](crate::unistd::fork) for additional safety concerns related
|
||||
/// to executing child processes.
|
||||
pub unsafe fn clone(
|
||||
mut cb: CloneCb,
|
||||
stack: &mut [u8],
|
||||
flags: CloneFlags,
|
||||
@@ -106,12 +115,15 @@ mod sched_linux_like {
|
||||
(*cb)() as c_int
|
||||
}
|
||||
|
||||
let combined = flags.bits() | signal.unwrap_or(0);
|
||||
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(
|
||||
mem::transmute::<
|
||||
extern "C" fn(*mut Box<dyn FnMut() -> isize>) -> i32,
|
||||
extern "C" fn(*mut libc::c_void) -> i32,
|
||||
>(
|
||||
callback
|
||||
as extern "C" fn(*mut Box<dyn FnMut() -> isize>) -> i32,
|
||||
),
|
||||
@@ -136,27 +148,17 @@ mod sched_linux_like {
|
||||
/// reassociate thread with a namespace
|
||||
///
|
||||
/// See also [setns(2)](https://man7.org/linux/man-pages/man2/setns.2.html)
|
||||
pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> {
|
||||
let res = unsafe { libc::setns(fd, nstype.bits()) };
|
||||
pub fn setns<Fd: AsFd>(fd: Fd, nstype: CloneFlags) -> Result<()> {
|
||||
let res = unsafe { libc::setns(fd.as_fd().as_raw_fd(), nstype.bits()) };
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux"
|
||||
))]
|
||||
#[cfg(any(linux_android, freebsdlike))]
|
||||
pub use self::sched_affinity::*;
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux"
|
||||
))]
|
||||
#[cfg(any(linux_android, freebsdlike))]
|
||||
mod sched_affinity {
|
||||
use crate::errno::Errno;
|
||||
use crate::unistd::Pid;
|
||||
|
||||
+431
@@ -0,0 +1,431 @@
|
||||
//! Safe wrappers around posix_spawn* functions found in the libc "spawn.h" header.
|
||||
|
||||
use std::{ffi::CStr, mem, os::fd::RawFd};
|
||||
|
||||
#[cfg(any(feature = "fs", feature = "term"))]
|
||||
use crate::fcntl::OFlag;
|
||||
#[cfg(feature = "signal")]
|
||||
use crate::sys::signal::SigSet;
|
||||
#[cfg(feature = "fs")]
|
||||
use crate::sys::stat::Mode;
|
||||
use crate::{errno::Errno, unistd::Pid, NixPath, Result};
|
||||
|
||||
/// A spawn attributes object. See [posix_spawnattr_t](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_init.html).
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug)]
|
||||
pub struct PosixSpawnAttr {
|
||||
attr: libc::posix_spawnattr_t,
|
||||
}
|
||||
|
||||
impl PosixSpawnAttr {
|
||||
/// Initialize the spawn attributes object. See
|
||||
/// [posix_spawnattr_init](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_init.html).
|
||||
#[doc(alias("posix_spawnattr_init"))]
|
||||
pub fn init() -> Result<PosixSpawnAttr> {
|
||||
let mut attr = mem::MaybeUninit::uninit();
|
||||
let res = unsafe { libc::posix_spawnattr_init(attr.as_mut_ptr()) };
|
||||
|
||||
Errno::result(res)?;
|
||||
|
||||
let attr = unsafe { attr.assume_init() };
|
||||
Ok(PosixSpawnAttr { attr })
|
||||
}
|
||||
|
||||
/// Reinitialize the spawn attributes object.
|
||||
/// This is a wrapper around
|
||||
/// [posix_spawnattr_destroy](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_destroy.html)
|
||||
/// followed by
|
||||
/// [posix_spawnattr_init](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_init.html).
|
||||
#[doc(alias("posix_spawnattr_destroy"))]
|
||||
pub fn reinit(mut self) -> Result<PosixSpawnAttr> {
|
||||
let res = unsafe {
|
||||
libc::posix_spawnattr_destroy(
|
||||
&mut self.attr as *mut libc::posix_spawnattr_t,
|
||||
)
|
||||
};
|
||||
Errno::result(res)?;
|
||||
|
||||
let res = unsafe {
|
||||
libc::posix_spawnattr_init(
|
||||
&mut self.attr as *mut libc::posix_spawnattr_t,
|
||||
)
|
||||
};
|
||||
Errno::result(res)?;
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Set spawn flags. See
|
||||
/// [posix_spawnattr_setflags](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_setflags.html).
|
||||
#[doc(alias("posix_spawnattr_setflags"))]
|
||||
pub fn set_flags(&mut self, flags: PosixSpawnFlags) -> Result<()> {
|
||||
let res = unsafe {
|
||||
libc::posix_spawnattr_setflags(
|
||||
&mut self.attr as *mut libc::posix_spawnattr_t,
|
||||
flags.bits() as libc::c_short,
|
||||
)
|
||||
};
|
||||
Errno::result(res)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get spawn flags. See
|
||||
/// [posix_spawnattr_getflags](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_getflags.html).
|
||||
#[doc(alias("posix_spawnattr_getflags"))]
|
||||
pub fn flags(&self) -> Result<PosixSpawnFlags> {
|
||||
let mut flags: libc::c_short = 0;
|
||||
let res = unsafe {
|
||||
libc::posix_spawnattr_getflags(
|
||||
&self.attr as *const libc::posix_spawnattr_t,
|
||||
&mut flags,
|
||||
)
|
||||
};
|
||||
Errno::result(res)?;
|
||||
|
||||
Ok(PosixSpawnFlags::from_bits_truncate(flags.into()))
|
||||
}
|
||||
|
||||
/// Set spawn pgroup. See
|
||||
/// [posix_spawnattr_setpgroup](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_setpgroup.html).
|
||||
#[doc(alias("posix_spawnattr_setpgroup"))]
|
||||
pub fn set_pgroup(&mut self, pgroup: Pid) -> Result<()> {
|
||||
let res = unsafe {
|
||||
libc::posix_spawnattr_setpgroup(
|
||||
&mut self.attr as *mut libc::posix_spawnattr_t,
|
||||
pgroup.as_raw(),
|
||||
)
|
||||
};
|
||||
Errno::result(res)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get spawn pgroup. See
|
||||
/// [posix_spawnattr_getpgroup](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_getpgroup.html).
|
||||
#[doc(alias("posix_spawnattr_getpgroup"))]
|
||||
pub fn pgroup(&self) -> Result<Pid> {
|
||||
let mut pid: libc::pid_t = 0;
|
||||
|
||||
let res = unsafe {
|
||||
libc::posix_spawnattr_getpgroup(
|
||||
&self.attr as *const libc::posix_spawnattr_t,
|
||||
&mut pid,
|
||||
)
|
||||
};
|
||||
Errno::result(res)?;
|
||||
|
||||
Ok(Pid::from_raw(pid))
|
||||
}
|
||||
|
||||
feature! {
|
||||
#![feature = "signal"]
|
||||
/// Set spawn sigdefault. See
|
||||
/// [posix_spawnattr_setsigdefault](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_setsigdefault.html).
|
||||
#[doc(alias("posix_spawnattr_setsigdefault"))]
|
||||
pub fn set_sigdefault(&mut self, sigdefault: &SigSet) -> Result<()> {
|
||||
let res = unsafe {
|
||||
libc::posix_spawnattr_setsigdefault(
|
||||
&mut self.attr as *mut libc::posix_spawnattr_t,
|
||||
sigdefault.as_ref(),
|
||||
)
|
||||
};
|
||||
Errno::result(res)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get spawn sigdefault. See
|
||||
/// [posix_spawnattr_getsigdefault](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_getsigdefault.html).
|
||||
#[doc(alias("posix_spawnattr_getsigdefault"))]
|
||||
pub fn sigdefault(&self) -> Result<SigSet> {
|
||||
let mut sigset = mem::MaybeUninit::uninit();
|
||||
|
||||
let res = unsafe {
|
||||
libc::posix_spawnattr_getsigdefault(
|
||||
&self.attr as *const libc::posix_spawnattr_t,
|
||||
sigset.as_mut_ptr(),
|
||||
)
|
||||
};
|
||||
Errno::result(res)?;
|
||||
|
||||
let sigdefault =
|
||||
unsafe { SigSet::from_sigset_t_unchecked(sigset.assume_init()) };
|
||||
Ok(sigdefault)
|
||||
}
|
||||
|
||||
/// Set spawn sigmask. See
|
||||
/// [posix_spawnattr_setsigmask](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_setsigmask.html).
|
||||
#[doc(alias("posix_spawnattr_setsigmask"))]
|
||||
pub fn set_sigmask(&mut self, sigdefault: &SigSet) -> Result<()> {
|
||||
let res = unsafe {
|
||||
libc::posix_spawnattr_setsigmask(
|
||||
&mut self.attr as *mut libc::posix_spawnattr_t,
|
||||
sigdefault.as_ref(),
|
||||
)
|
||||
};
|
||||
Errno::result(res)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get spawn sigmask. See
|
||||
/// [posix_spawnattr_getsigmask](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_getsigmask.html).
|
||||
#[doc(alias("posix_spawnattr_getsigmask"))]
|
||||
pub fn sigmask(&self) -> Result<SigSet> {
|
||||
let mut sigset = mem::MaybeUninit::uninit();
|
||||
|
||||
let res = unsafe {
|
||||
libc::posix_spawnattr_getsigmask(
|
||||
&self.attr as *const libc::posix_spawnattr_t,
|
||||
sigset.as_mut_ptr(),
|
||||
)
|
||||
};
|
||||
Errno::result(res)?;
|
||||
|
||||
let sigdefault =
|
||||
unsafe { SigSet::from_sigset_t_unchecked(sigset.assume_init()) };
|
||||
Ok(sigdefault)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for PosixSpawnAttr {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
libc::posix_spawnattr_destroy(
|
||||
&mut self.attr as *mut libc::posix_spawnattr_t,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
libc_bitflags!(
|
||||
/// Process attributes to be changed in the new process image when invoking [`posix_spawn`]
|
||||
/// or [`posix_spawnp`]. See
|
||||
/// [posix_spawn](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawn.html).
|
||||
pub struct PosixSpawnFlags: libc::c_int {
|
||||
/// Reset effective user ID of the child process to parent's real user ID.
|
||||
POSIX_SPAWN_RESETIDS;
|
||||
/// Put the child in a process group specified by the spawn-pgroup attribute. See
|
||||
/// [posix_spawnattr_setpgroup](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_setpgroup.html).
|
||||
POSIX_SPAWN_SETPGROUP;
|
||||
/// Force set signals to default signal handling in child process. See
|
||||
/// [posix_spawnattr_setsigdefault](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_setsigdefault.html).
|
||||
#[cfg(feature = "signal")]
|
||||
POSIX_SPAWN_SETSIGDEF;
|
||||
/// Set signal mask of child process. See
|
||||
/// [posix_spawnattr_setsigmask](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_setsigmask.html).
|
||||
#[cfg(feature = "signal")]
|
||||
POSIX_SPAWN_SETSIGMASK;
|
||||
// TODO: Add support for the following two flags whenever support for
|
||||
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sched.h.html
|
||||
// is added to nix.
|
||||
// POSIX_SPAWN_SETSCHEDPARAM;
|
||||
// POSIX_SPAWN_SETSCHEDULER;
|
||||
}
|
||||
);
|
||||
|
||||
/// A spawn file actions object. See [posix_spawn_file_actions_t](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawn_file_actions_addclose.html).
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug)]
|
||||
pub struct PosixSpawnFileActions {
|
||||
fa: libc::posix_spawn_file_actions_t,
|
||||
}
|
||||
|
||||
impl PosixSpawnFileActions {
|
||||
/// Initialize the spawn file actions object. See
|
||||
/// [posix_spawn_file_actions_init](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawn_file_actions_init.html).
|
||||
#[doc(alias("posix_spawn_file_actions_init"))]
|
||||
pub fn init() -> Result<PosixSpawnFileActions> {
|
||||
let mut actions = mem::MaybeUninit::uninit();
|
||||
let res = unsafe {
|
||||
libc::posix_spawn_file_actions_init(actions.as_mut_ptr())
|
||||
};
|
||||
Errno::result(res)?;
|
||||
Ok(unsafe {
|
||||
PosixSpawnFileActions {
|
||||
fa: actions.assume_init(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Reinitialize the spawn file actions object.
|
||||
/// This is a wrapper around
|
||||
/// [posix_spawn_file_actions_destroy](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawn_file_actions_destroy.html).
|
||||
/// followed by
|
||||
/// [posix_spawn_file_actions_init](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawn_file_actions_init.html).
|
||||
#[doc(alias("posix_spawn_file_actions_destroy"))]
|
||||
pub fn reinit(mut self) -> Result<PosixSpawnFileActions> {
|
||||
let res = unsafe {
|
||||
libc::posix_spawn_file_actions_destroy(
|
||||
&mut self.fa as *mut libc::posix_spawn_file_actions_t,
|
||||
)
|
||||
};
|
||||
Errno::result(res)?;
|
||||
|
||||
let res = unsafe {
|
||||
libc::posix_spawn_file_actions_init(
|
||||
&mut self.fa as *mut libc::posix_spawn_file_actions_t,
|
||||
)
|
||||
};
|
||||
Errno::result(res)?;
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Add a [dup2](https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup2.html) action. See
|
||||
/// [posix_spawn_file_actions_adddup2](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawn_file_actions_adddup2.html).
|
||||
#[doc(alias("posix_spawn_file_actions_adddup2"))]
|
||||
pub fn add_dup2(&mut self, fd: RawFd, newfd: RawFd) -> Result<()> {
|
||||
let res = unsafe {
|
||||
libc::posix_spawn_file_actions_adddup2(
|
||||
&mut self.fa as *mut libc::posix_spawn_file_actions_t,
|
||||
fd,
|
||||
newfd,
|
||||
)
|
||||
};
|
||||
Errno::result(res)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
feature! {
|
||||
#![all(feature = "fs", feature = "term")]
|
||||
/// Add an open action. See
|
||||
/// [posix_spawn_file_actions_addopen](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawn_file_actions_addopen.html).
|
||||
#[doc(alias("posix_spawn_file_actions_addopen"))]
|
||||
pub fn add_open<P: ?Sized + NixPath>(
|
||||
&mut self,
|
||||
fd: RawFd,
|
||||
path: &P,
|
||||
oflag: OFlag,
|
||||
mode: Mode,
|
||||
) -> Result<()> {
|
||||
let res = path.with_nix_path(|cstr| unsafe {
|
||||
libc::posix_spawn_file_actions_addopen(
|
||||
&mut self.fa as *mut libc::posix_spawn_file_actions_t,
|
||||
fd,
|
||||
cstr.as_ptr(),
|
||||
oflag.bits(),
|
||||
mode.bits(),
|
||||
)
|
||||
})?;
|
||||
Errno::result(res)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a close action. See
|
||||
/// [posix_spawn_file_actions_addclose](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawn_file_actions_addclose.html).
|
||||
#[doc(alias("posix_spawn_file_actions_addclose"))]
|
||||
pub fn add_close(&mut self, fd: RawFd) -> Result<()> {
|
||||
let res = unsafe {
|
||||
libc::posix_spawn_file_actions_addclose(
|
||||
&mut self.fa as *mut libc::posix_spawn_file_actions_t,
|
||||
fd,
|
||||
)
|
||||
};
|
||||
Errno::result(res)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for PosixSpawnFileActions {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
libc::posix_spawn_file_actions_destroy(
|
||||
&mut self.fa as *mut libc::posix_spawn_file_actions_t,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The POSIX standard requires those `args` and `envp` to be of type `*const *mut [c_char]`,
|
||||
// but implementations won't modify them, making the `mut` type redundant. Considering this,
|
||||
// Nix does not expose this mutability, but we have to change the interface when calling the
|
||||
// underlying libc interfaces , this helper function does the conversion job.
|
||||
//
|
||||
// SAFETY:
|
||||
// It is safe to add the mutability in types as implementations won't mutable them.
|
||||
unsafe fn to_exec_array<S: AsRef<CStr>>(args: &[S]) -> Vec<*mut libc::c_char> {
|
||||
let mut v: Vec<*mut libc::c_char> = args
|
||||
.iter()
|
||||
.map(|s| s.as_ref().as_ptr().cast_mut())
|
||||
.collect();
|
||||
v.push(std::ptr::null_mut());
|
||||
v
|
||||
}
|
||||
|
||||
/// Create a new child process from the specified process image. See
|
||||
/// [posix_spawn](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawn.html).
|
||||
pub fn posix_spawn<P, SA, SE>(
|
||||
path: &P,
|
||||
file_actions: &PosixSpawnFileActions,
|
||||
attr: &PosixSpawnAttr,
|
||||
args: &[SA],
|
||||
envp: &[SE],
|
||||
) -> Result<Pid>
|
||||
where
|
||||
P: NixPath + ?Sized,
|
||||
SA: AsRef<CStr>,
|
||||
SE: AsRef<CStr>,
|
||||
{
|
||||
let mut pid = 0;
|
||||
|
||||
let ret = unsafe {
|
||||
let args_p = to_exec_array(args);
|
||||
let env_p = to_exec_array(envp);
|
||||
|
||||
path.with_nix_path(|c_str| {
|
||||
libc::posix_spawn(
|
||||
&mut pid as *mut libc::pid_t,
|
||||
c_str.as_ptr(),
|
||||
&file_actions.fa as *const libc::posix_spawn_file_actions_t,
|
||||
&attr.attr as *const libc::posix_spawnattr_t,
|
||||
args_p.as_ptr(),
|
||||
env_p.as_ptr(),
|
||||
)
|
||||
})?
|
||||
};
|
||||
|
||||
if ret != 0 {
|
||||
return Err(Errno::from_raw(ret));
|
||||
}
|
||||
|
||||
Ok(Pid::from_raw(pid))
|
||||
}
|
||||
|
||||
/// Create a new child process from the specified process image. See
|
||||
/// [posix_spawnp](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnp.html).
|
||||
pub fn posix_spawnp<SA: AsRef<CStr>, SE: AsRef<CStr>>(
|
||||
path: &CStr,
|
||||
file_actions: &PosixSpawnFileActions,
|
||||
attr: &PosixSpawnAttr,
|
||||
args: &[SA],
|
||||
envp: &[SE],
|
||||
) -> Result<Pid> {
|
||||
let mut pid = 0;
|
||||
|
||||
let ret = unsafe {
|
||||
let args_p = to_exec_array(args);
|
||||
let env_p = to_exec_array(envp);
|
||||
|
||||
libc::posix_spawnp(
|
||||
&mut pid as *mut libc::pid_t,
|
||||
path.as_ptr(),
|
||||
&file_actions.fa as *const libc::posix_spawn_file_actions_t,
|
||||
&attr.attr as *const libc::posix_spawnattr_t,
|
||||
args_p.as_ptr(),
|
||||
env_p.as_ptr(),
|
||||
)
|
||||
};
|
||||
|
||||
if ret != 0 {
|
||||
return Err(Errno::from_raw(ret));
|
||||
}
|
||||
|
||||
Ok(Pid::from_raw(pid))
|
||||
}
|
||||
+108
-152
@@ -30,12 +30,12 @@ use std::{
|
||||
fmt::{self, Debug},
|
||||
marker::{PhantomData, PhantomPinned},
|
||||
mem,
|
||||
os::unix::io::RawFd,
|
||||
os::unix::io::{AsFd, AsRawFd, BorrowedFd},
|
||||
pin::Pin,
|
||||
ptr, thread,
|
||||
};
|
||||
|
||||
use libc::{c_void, off_t};
|
||||
use libc::off_t;
|
||||
use pin_utils::unsafe_pinned;
|
||||
|
||||
use crate::{
|
||||
@@ -53,12 +53,10 @@ libc_enum! {
|
||||
/// do it like `fsync`
|
||||
O_SYNC,
|
||||
/// on supported operating systems only, do it like `fdatasync`
|
||||
#[cfg(any(target_os = "ios",
|
||||
#[cfg(any(apple_targets,
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
target_os = "freebsd",
|
||||
netbsdlike))]
|
||||
O_DSYNC
|
||||
}
|
||||
impl TryFrom<i32>
|
||||
@@ -105,7 +103,7 @@ unsafe impl Sync for LibcAiocb {}
|
||||
// provide polymorphism at the wrong level. Instead, the best place for
|
||||
// polymorphism is at the level of `Futures`.
|
||||
#[repr(C)]
|
||||
struct AioCb {
|
||||
struct AioCb<'a> {
|
||||
aiocb: LibcAiocb,
|
||||
/// Could this `AioCb` potentially have any in-kernel state?
|
||||
// It would be really nice to perform the in-progress check entirely at
|
||||
@@ -115,9 +113,10 @@ struct AioCb {
|
||||
// that there's no way to write an AioCb constructor that neither boxes
|
||||
// the object itself, nor moves it during return.
|
||||
in_progress: bool,
|
||||
_fd: PhantomData<BorrowedFd<'a>>,
|
||||
}
|
||||
|
||||
impl AioCb {
|
||||
impl<'a> AioCb<'a> {
|
||||
pin_utils::unsafe_unpinned!(aiocb: LibcAiocb);
|
||||
|
||||
fn aio_return(mut self: Pin<&mut Self>) -> Result<usize> {
|
||||
@@ -142,18 +141,23 @@ impl AioCb {
|
||||
}
|
||||
}
|
||||
|
||||
fn common_init(fd: RawFd, prio: i32, sigev_notify: SigevNotify) -> Self {
|
||||
fn common_init(
|
||||
fd: BorrowedFd<'a>,
|
||||
prio: i32,
|
||||
sigev_notify: SigevNotify,
|
||||
) -> Self {
|
||||
// Use mem::zeroed instead of explicitly zeroing each field, because the
|
||||
// number and name of reserved fields is OS-dependent. On some OSes,
|
||||
// some reserved fields are used the kernel for state, and must be
|
||||
// explicitly zeroed when allocated.
|
||||
let mut a = unsafe { mem::zeroed::<libc::aiocb>() };
|
||||
a.aio_fildes = fd;
|
||||
a.aio_fildes = fd.as_raw_fd();
|
||||
a.aio_reqprio = prio;
|
||||
a.aio_sigevent = SigEvent::new(sigev_notify).sigevent();
|
||||
AioCb {
|
||||
aiocb: LibcAiocb(a),
|
||||
in_progress: false,
|
||||
_fd: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,9 +165,9 @@ impl AioCb {
|
||||
let r = unsafe { libc::aio_error(&self.aiocb().0) };
|
||||
match r {
|
||||
0 => Ok(()),
|
||||
num if num > 0 => Err(Errno::from_i32(num)),
|
||||
num if num > 0 => Err(Errno::from_raw(num)),
|
||||
-1 => Err(Errno::last()),
|
||||
num => panic!("unknown aio_error return value {:?}", num),
|
||||
num => panic!("unknown aio_error return value {num:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,7 +193,7 @@ impl AioCb {
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for AioCb {
|
||||
impl Debug for AioCb<'_> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_struct("AioCb")
|
||||
.field("aiocb", &self.aiocb.0)
|
||||
@@ -198,7 +202,7 @@ impl Debug for AioCb {
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for AioCb {
|
||||
impl Drop for AioCb<'_> {
|
||||
/// If the `AioCb` has no remaining state in the kernel, just drop it.
|
||||
/// Otherwise, dropping constitutes a resource leak, which is an error
|
||||
fn drop(&mut self) {
|
||||
@@ -246,11 +250,11 @@ pub trait Aio {
|
||||
/// # use nix::sys::signal::SigevNotify;
|
||||
/// # use std::{thread, time};
|
||||
/// # use std::io::Write;
|
||||
/// # use std::os::unix::io::AsRawFd;
|
||||
/// # use std::os::unix::io::AsFd;
|
||||
/// # use tempfile::tempfile;
|
||||
/// let wbuf = b"CDEF";
|
||||
/// let mut f = tempfile().unwrap();
|
||||
/// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(),
|
||||
/// let mut aiocb = Box::pin(AioWrite::new(f.as_fd(),
|
||||
/// 2, //offset
|
||||
/// &wbuf[..],
|
||||
/// 0, //priority
|
||||
@@ -287,11 +291,11 @@ pub trait Aio {
|
||||
/// # use nix::sys::aio::*;
|
||||
/// # use nix::sys::signal::SigevNotify;
|
||||
/// # use std::{thread, time};
|
||||
/// # use std::os::unix::io::AsRawFd;
|
||||
/// # use std::os::unix::io::AsFd;
|
||||
/// # use tempfile::tempfile;
|
||||
/// const WBUF: &[u8] = b"abcdef123456";
|
||||
/// let mut f = tempfile().unwrap();
|
||||
/// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(),
|
||||
/// let mut aiocb = Box::pin(AioWrite::new(f.as_fd(),
|
||||
/// 2, //offset
|
||||
/// WBUF,
|
||||
/// 0, //priority
|
||||
@@ -309,7 +313,7 @@ pub trait Aio {
|
||||
fn error(self: Pin<&mut Self>) -> Result<()>;
|
||||
|
||||
/// Returns the underlying file descriptor associated with the operation.
|
||||
fn fd(&self) -> RawFd;
|
||||
fn fd(&self) -> BorrowedFd;
|
||||
|
||||
/// Does this operation currently have any in-kernel state?
|
||||
///
|
||||
@@ -324,10 +328,10 @@ pub trait Aio {
|
||||
/// # use nix::sys::aio::*;
|
||||
/// # use nix::sys::signal::SigevNotify::SigevNone;
|
||||
/// # use std::{thread, time};
|
||||
/// # use std::os::unix::io::AsRawFd;
|
||||
/// # use std::os::unix::io::AsFd;
|
||||
/// # use tempfile::tempfile;
|
||||
/// let f = tempfile().unwrap();
|
||||
/// let mut aiof = Box::pin(AioFsync::new(f.as_raw_fd(), AioFsyncMode::O_SYNC,
|
||||
/// let mut aiof = Box::pin(AioFsync::new(f.as_fd(), AioFsyncMode::O_SYNC,
|
||||
/// 0, SigevNone));
|
||||
/// assert!(!aiof.as_mut().in_progress());
|
||||
/// aiof.as_mut().submit().expect("aio_fsync failed early");
|
||||
@@ -367,8 +371,10 @@ macro_rules! aio_methods {
|
||||
self.aiocb().error()
|
||||
}
|
||||
|
||||
fn fd(&self) -> RawFd {
|
||||
self.aiocb.aiocb.0.aio_fildes
|
||||
fn fd(&self) -> BorrowedFd<'a> {
|
||||
// safe because self's lifetime is the same as the original file
|
||||
// descriptor.
|
||||
unsafe { BorrowedFd::borrow_raw(self.aiocb.aiocb.0.aio_fildes) }
|
||||
}
|
||||
|
||||
fn in_progress(&self) -> bool {
|
||||
@@ -416,10 +422,10 @@ macro_rules! aio_methods {
|
||||
/// # use nix::sys::aio::*;
|
||||
/// # use nix::sys::signal::SigevNotify::SigevNone;
|
||||
/// # use std::{thread, time};
|
||||
/// # use std::os::unix::io::AsRawFd;
|
||||
/// # use std::os::unix::io::AsFd;
|
||||
/// # use tempfile::tempfile;
|
||||
/// let f = tempfile().unwrap();
|
||||
/// let mut aiof = Box::pin(AioFsync::new(f.as_raw_fd(), AioFsyncMode::O_SYNC,
|
||||
/// let mut aiof = Box::pin(AioFsync::new(f.as_fd(), AioFsyncMode::O_SYNC,
|
||||
/// 0, SigevNone));
|
||||
/// aiof.as_mut().submit().expect("aio_fsync failed early");
|
||||
/// while (aiof.as_mut().error() == Err(Errno::EINPROGRESS)) {
|
||||
@@ -429,13 +435,13 @@ macro_rules! aio_methods {
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct AioFsync {
|
||||
aiocb: AioCb,
|
||||
pub struct AioFsync<'a> {
|
||||
aiocb: AioCb<'a>,
|
||||
_pin: PhantomPinned,
|
||||
}
|
||||
|
||||
impl AioFsync {
|
||||
unsafe_pinned!(aiocb: AioCb);
|
||||
impl<'a> AioFsync<'a> {
|
||||
unsafe_pinned!(aiocb: AioCb<'a>);
|
||||
|
||||
/// Returns the operation's fsync mode: data and metadata or data only?
|
||||
pub fn mode(&self) -> AioFsyncMode {
|
||||
@@ -449,12 +455,11 @@ impl AioFsync {
|
||||
/// * `fd`: File descriptor to sync.
|
||||
/// * `mode`: Whether to sync file metadata too, or just data.
|
||||
/// * `prio`: If POSIX Prioritized IO is supported, then the
|
||||
/// operation will be prioritized at the process's
|
||||
/// priority level minus `prio`.
|
||||
/// * `sigev_notify`: Determines how you will be notified of event
|
||||
/// completion.
|
||||
/// operation will be prioritized at the process's priority level minus
|
||||
/// `prio`.
|
||||
/// * `sigev_notify`: Determines how you will be notified of event completion.
|
||||
pub fn new(
|
||||
fd: RawFd,
|
||||
fd: BorrowedFd<'a>,
|
||||
mode: AioFsyncMode,
|
||||
prio: i32,
|
||||
sigev_notify: SigevNotify,
|
||||
@@ -472,7 +477,7 @@ impl AioFsync {
|
||||
}
|
||||
}
|
||||
|
||||
impl Aio for AioFsync {
|
||||
impl<'a> Aio for AioFsync<'a> {
|
||||
type Output = ();
|
||||
|
||||
aio_methods!();
|
||||
@@ -493,7 +498,7 @@ impl Aio for AioFsync {
|
||||
|
||||
// AioFsync does not need AsMut, since it can't be used with lio_listio
|
||||
|
||||
impl AsRef<libc::aiocb> for AioFsync {
|
||||
impl AsRef<libc::aiocb> for AioFsync<'_> {
|
||||
fn as_ref(&self) -> &libc::aiocb {
|
||||
&self.aiocb.aiocb.0
|
||||
}
|
||||
@@ -515,7 +520,7 @@ impl AsRef<libc::aiocb> for AioFsync {
|
||||
/// # use nix::sys::signal::SigevNotify;
|
||||
/// # use std::{thread, time};
|
||||
/// # use std::io::Write;
|
||||
/// # use std::os::unix::io::AsRawFd;
|
||||
/// # use std::os::unix::io::AsFd;
|
||||
/// # use tempfile::tempfile;
|
||||
/// const INITIAL: &[u8] = b"abcdef123456";
|
||||
/// const LEN: usize = 4;
|
||||
@@ -525,7 +530,7 @@ impl AsRef<libc::aiocb> for AioFsync {
|
||||
/// {
|
||||
/// let mut aior = Box::pin(
|
||||
/// AioRead::new(
|
||||
/// f.as_raw_fd(),
|
||||
/// f.as_fd(),
|
||||
/// 2, //offset
|
||||
/// &mut rbuf,
|
||||
/// 0, //priority
|
||||
@@ -543,13 +548,13 @@ impl AsRef<libc::aiocb> for AioFsync {
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct AioRead<'a> {
|
||||
aiocb: AioCb,
|
||||
aiocb: AioCb<'a>,
|
||||
_data: PhantomData<&'a [u8]>,
|
||||
_pin: PhantomPinned,
|
||||
}
|
||||
|
||||
impl<'a> AioRead<'a> {
|
||||
unsafe_pinned!(aiocb: AioCb);
|
||||
unsafe_pinned!(aiocb: AioCb<'a>);
|
||||
|
||||
/// Returns the requested length of the aio operation in bytes
|
||||
///
|
||||
@@ -567,13 +572,11 @@ impl<'a> AioRead<'a> {
|
||||
/// * `fd`: File descriptor to read from
|
||||
/// * `offs`: File offset
|
||||
/// * `buf`: A memory buffer. It must outlive the `AioRead`.
|
||||
/// * `prio`: If POSIX Prioritized IO is supported, then the
|
||||
/// operation will be prioritized at the process's
|
||||
/// priority level minus `prio`
|
||||
/// * `sigev_notify`: Determines how you will be notified of event
|
||||
/// completion.
|
||||
/// * `prio`: If POSIX Prioritized IO is supported, then the operation
|
||||
/// will be prioritized at the process's priority level minus `prio`
|
||||
/// * `sigev_notify`: Determines how you will be notified of event completion.
|
||||
pub fn new(
|
||||
fd: RawFd,
|
||||
fd: BorrowedFd<'a>,
|
||||
offs: off_t,
|
||||
buf: &'a mut [u8],
|
||||
prio: i32,
|
||||
@@ -581,7 +584,7 @@ impl<'a> AioRead<'a> {
|
||||
) -> Self {
|
||||
let mut aiocb = AioCb::common_init(fd, prio, sigev_notify);
|
||||
aiocb.aiocb.0.aio_nbytes = buf.len();
|
||||
aiocb.aiocb.0.aio_buf = buf.as_mut_ptr() as *mut c_void;
|
||||
aiocb.aiocb.0.aio_buf = buf.as_mut_ptr().cast();
|
||||
aiocb.aiocb.0.aio_lio_opcode = libc::LIO_READ;
|
||||
aiocb.aiocb.0.aio_offset = offs;
|
||||
AioRead {
|
||||
@@ -603,13 +606,13 @@ impl<'a> Aio for AioRead<'a> {
|
||||
aio_methods!(aio_read);
|
||||
}
|
||||
|
||||
impl<'a> AsMut<libc::aiocb> for AioRead<'a> {
|
||||
impl AsMut<libc::aiocb> for AioRead<'_> {
|
||||
fn as_mut(&mut self) -> &mut libc::aiocb {
|
||||
&mut self.aiocb.aiocb.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AsRef<libc::aiocb> for AioRead<'a> {
|
||||
impl AsRef<libc::aiocb> for AioRead<'_> {
|
||||
fn as_ref(&self) -> &libc::aiocb {
|
||||
&self.aiocb.aiocb.0
|
||||
}
|
||||
@@ -632,7 +635,7 @@ impl<'a> AsRef<libc::aiocb> for AioRead<'a> {
|
||||
/// # use nix::sys::signal::SigevNotify;
|
||||
/// # use std::{thread, time};
|
||||
/// # use std::io::{IoSliceMut, Write};
|
||||
/// # use std::os::unix::io::AsRawFd;
|
||||
/// # use std::os::unix::io::AsFd;
|
||||
/// # use tempfile::tempfile;
|
||||
/// const INITIAL: &[u8] = b"abcdef123456";
|
||||
/// let mut rbuf0 = vec![0; 4];
|
||||
@@ -644,7 +647,7 @@ impl<'a> AsRef<libc::aiocb> for AioRead<'a> {
|
||||
/// {
|
||||
/// let mut aior = Box::pin(
|
||||
/// AioReadv::new(
|
||||
/// f.as_raw_fd(),
|
||||
/// f.as_fd(),
|
||||
/// 2, //offset
|
||||
/// &mut rbufs,
|
||||
/// 0, //priority
|
||||
@@ -664,14 +667,14 @@ impl<'a> AsRef<libc::aiocb> for AioRead<'a> {
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct AioReadv<'a> {
|
||||
aiocb: AioCb,
|
||||
aiocb: AioCb<'a>,
|
||||
_data: PhantomData<&'a [&'a [u8]]>,
|
||||
_pin: PhantomPinned,
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
impl<'a> AioReadv<'a> {
|
||||
unsafe_pinned!(aiocb: AioCb);
|
||||
unsafe_pinned!(aiocb: AioCb<'a>);
|
||||
|
||||
/// Returns the number of buffers the operation will read into.
|
||||
pub fn iovlen(&self) -> usize {
|
||||
@@ -692,7 +695,7 @@ impl<'a> AioReadv<'a> {
|
||||
/// * `sigev_notify`: Determines how you will be notified of event
|
||||
/// completion.
|
||||
pub fn new(
|
||||
fd: RawFd,
|
||||
fd: BorrowedFd<'a>,
|
||||
offs: off_t,
|
||||
bufs: &mut [IoSliceMut<'a>],
|
||||
prio: i32,
|
||||
@@ -702,7 +705,7 @@ impl<'a> AioReadv<'a> {
|
||||
// In vectored mode, aio_nbytes stores the length of the iovec array,
|
||||
// not the byte count.
|
||||
aiocb.aiocb.0.aio_nbytes = bufs.len();
|
||||
aiocb.aiocb.0.aio_buf = bufs.as_mut_ptr() as *mut c_void;
|
||||
aiocb.aiocb.0.aio_buf = bufs.as_mut_ptr().cast();
|
||||
aiocb.aiocb.0.aio_lio_opcode = libc::LIO_READV;
|
||||
aiocb.aiocb.0.aio_offset = offs;
|
||||
AioReadv {
|
||||
@@ -726,14 +729,14 @@ impl<'a> Aio for AioReadv<'a> {
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
impl<'a> AsMut<libc::aiocb> for AioReadv<'a> {
|
||||
impl AsMut<libc::aiocb> for AioReadv<'_> {
|
||||
fn as_mut(&mut self) -> &mut libc::aiocb {
|
||||
&mut self.aiocb.aiocb.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
impl<'a> AsRef<libc::aiocb> for AioReadv<'a> {
|
||||
impl AsRef<libc::aiocb> for AioReadv<'_> {
|
||||
fn as_ref(&self) -> &libc::aiocb {
|
||||
&self.aiocb.aiocb.0
|
||||
}
|
||||
@@ -753,13 +756,13 @@ impl<'a> AsRef<libc::aiocb> for AioReadv<'a> {
|
||||
/// # use nix::sys::aio::*;
|
||||
/// # use nix::sys::signal::SigevNotify;
|
||||
/// # use std::{thread, time};
|
||||
/// # use std::os::unix::io::AsRawFd;
|
||||
/// # use std::os::unix::io::AsFd;
|
||||
/// # use tempfile::tempfile;
|
||||
/// const WBUF: &[u8] = b"abcdef123456";
|
||||
/// let mut f = tempfile().unwrap();
|
||||
/// let mut aiow = Box::pin(
|
||||
/// AioWrite::new(
|
||||
/// f.as_raw_fd(),
|
||||
/// f.as_fd(),
|
||||
/// 2, //offset
|
||||
/// WBUF,
|
||||
/// 0, //priority
|
||||
@@ -775,13 +778,13 @@ impl<'a> AsRef<libc::aiocb> for AioReadv<'a> {
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct AioWrite<'a> {
|
||||
aiocb: AioCb,
|
||||
aiocb: AioCb<'a>,
|
||||
_data: PhantomData<&'a [u8]>,
|
||||
_pin: PhantomPinned,
|
||||
}
|
||||
|
||||
impl<'a> AioWrite<'a> {
|
||||
unsafe_pinned!(aiocb: AioCb);
|
||||
unsafe_pinned!(aiocb: AioCb<'a>);
|
||||
|
||||
/// Returns the requested length of the aio operation in bytes
|
||||
///
|
||||
@@ -799,13 +802,11 @@ impl<'a> AioWrite<'a> {
|
||||
/// * `fd`: File descriptor to write to
|
||||
/// * `offs`: File offset
|
||||
/// * `buf`: A memory buffer. It must outlive the `AioWrite`.
|
||||
/// * `prio`: If POSIX Prioritized IO is supported, then the
|
||||
/// operation will be prioritized at the process's
|
||||
/// priority level minus `prio`
|
||||
/// * `sigev_notify`: Determines how you will be notified of event
|
||||
/// completion.
|
||||
/// * `prio`: If POSIX Prioritized IO is supported, then the operation
|
||||
/// will be prioritized at the process's priority level minus `prio`
|
||||
/// * `sigev_notify`: Determines how you will be notified of event completion.
|
||||
pub fn new(
|
||||
fd: RawFd,
|
||||
fd: BorrowedFd<'a>,
|
||||
offs: off_t,
|
||||
buf: &'a [u8],
|
||||
prio: i32,
|
||||
@@ -817,7 +818,7 @@ impl<'a> AioWrite<'a> {
|
||||
// but technically its only unsafe to dereference it, not to create
|
||||
// it. Type Safety guarantees that we'll never pass aiocb to
|
||||
// aio_read or aio_readv.
|
||||
aiocb.aiocb.0.aio_buf = buf.as_ptr() as *mut c_void;
|
||||
aiocb.aiocb.0.aio_buf = buf.as_ptr().cast_mut().cast();
|
||||
aiocb.aiocb.0.aio_lio_opcode = libc::LIO_WRITE;
|
||||
aiocb.aiocb.0.aio_offset = offs;
|
||||
AioWrite {
|
||||
@@ -839,13 +840,13 @@ impl<'a> Aio for AioWrite<'a> {
|
||||
aio_methods!(aio_write);
|
||||
}
|
||||
|
||||
impl<'a> AsMut<libc::aiocb> for AioWrite<'a> {
|
||||
impl AsMut<libc::aiocb> for AioWrite<'_> {
|
||||
fn as_mut(&mut self) -> &mut libc::aiocb {
|
||||
&mut self.aiocb.aiocb.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AsRef<libc::aiocb> for AioWrite<'a> {
|
||||
impl AsRef<libc::aiocb> for AioWrite<'_> {
|
||||
fn as_ref(&self) -> &libc::aiocb {
|
||||
&self.aiocb.aiocb.0
|
||||
}
|
||||
@@ -867,7 +868,7 @@ impl<'a> AsRef<libc::aiocb> for AioWrite<'a> {
|
||||
/// # use nix::sys::signal::SigevNotify;
|
||||
/// # use std::{thread, time};
|
||||
/// # use std::io::IoSlice;
|
||||
/// # use std::os::unix::io::AsRawFd;
|
||||
/// # use std::os::unix::io::AsFd;
|
||||
/// # use tempfile::tempfile;
|
||||
/// const wbuf0: &[u8] = b"abcdef";
|
||||
/// const wbuf1: &[u8] = b"123456";
|
||||
@@ -876,7 +877,7 @@ impl<'a> AsRef<libc::aiocb> for AioWrite<'a> {
|
||||
/// let mut f = tempfile().unwrap();
|
||||
/// let mut aiow = Box::pin(
|
||||
/// AioWritev::new(
|
||||
/// f.as_raw_fd(),
|
||||
/// f.as_fd(),
|
||||
/// 2, //offset
|
||||
/// &wbufs,
|
||||
/// 0, //priority
|
||||
@@ -893,14 +894,14 @@ impl<'a> AsRef<libc::aiocb> for AioWrite<'a> {
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct AioWritev<'a> {
|
||||
aiocb: AioCb,
|
||||
aiocb: AioCb<'a>,
|
||||
_data: PhantomData<&'a [&'a [u8]]>,
|
||||
_pin: PhantomPinned,
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
impl<'a> AioWritev<'a> {
|
||||
unsafe_pinned!(aiocb: AioCb);
|
||||
unsafe_pinned!(aiocb: AioCb<'a>);
|
||||
|
||||
/// Returns the number of buffers the operation will read into.
|
||||
pub fn iovlen(&self) -> usize {
|
||||
@@ -921,7 +922,7 @@ impl<'a> AioWritev<'a> {
|
||||
/// * `sigev_notify`: Determines how you will be notified of event
|
||||
/// completion.
|
||||
pub fn new(
|
||||
fd: RawFd,
|
||||
fd: BorrowedFd<'a>,
|
||||
offs: off_t,
|
||||
bufs: &[IoSlice<'a>],
|
||||
prio: i32,
|
||||
@@ -935,7 +936,7 @@ impl<'a> AioWritev<'a> {
|
||||
// but technically its only unsafe to dereference it, not to create
|
||||
// it. Type Safety guarantees that we'll never pass aiocb to
|
||||
// aio_read or aio_readv.
|
||||
aiocb.aiocb.0.aio_buf = bufs.as_ptr() as *mut c_void;
|
||||
aiocb.aiocb.0.aio_buf = bufs.as_ptr().cast_mut().cast();
|
||||
aiocb.aiocb.0.aio_lio_opcode = libc::LIO_WRITEV;
|
||||
aiocb.aiocb.0.aio_offset = offs;
|
||||
AioWritev {
|
||||
@@ -959,14 +960,14 @@ impl<'a> Aio for AioWritev<'a> {
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
impl<'a> AsMut<libc::aiocb> for AioWritev<'a> {
|
||||
impl AsMut<libc::aiocb> for AioWritev<'_> {
|
||||
fn as_mut(&mut self) -> &mut libc::aiocb {
|
||||
&mut self.aiocb.aiocb.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
impl<'a> AsRef<libc::aiocb> for AioWritev<'a> {
|
||||
impl AsRef<libc::aiocb> for AioWritev<'_> {
|
||||
fn as_ref(&self) -> &libc::aiocb {
|
||||
&self.aiocb.aiocb.0
|
||||
}
|
||||
@@ -986,17 +987,17 @@ impl<'a> AsRef<libc::aiocb> for AioWritev<'a> {
|
||||
/// # use nix::sys::signal::SigevNotify;
|
||||
/// # use std::{thread, time};
|
||||
/// # use std::io::Write;
|
||||
/// # use std::os::unix::io::AsRawFd;
|
||||
/// # use std::os::unix::io::AsFd;
|
||||
/// # use tempfile::tempfile;
|
||||
/// let wbuf = b"CDEF";
|
||||
/// let mut f = tempfile().unwrap();
|
||||
/// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(),
|
||||
/// let mut aiocb = Box::pin(AioWrite::new(f.as_fd(),
|
||||
/// 2, //offset
|
||||
/// &wbuf[..],
|
||||
/// 0, //priority
|
||||
/// SigevNotify::SigevNone));
|
||||
/// aiocb.as_mut().submit().unwrap();
|
||||
/// let cs = aio_cancel_all(f.as_raw_fd()).unwrap();
|
||||
/// let cs = aio_cancel_all(f.as_fd()).unwrap();
|
||||
/// if cs == AioCancelStat::AioNotCanceled {
|
||||
/// while (aiocb.as_mut().error() == Err(Errno::EINPROGRESS)) {
|
||||
/// thread::sleep(time::Duration::from_millis(10));
|
||||
@@ -1009,8 +1010,8 @@ impl<'a> AsRef<libc::aiocb> for AioWritev<'a> {
|
||||
/// # References
|
||||
///
|
||||
/// [`aio_cancel`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html)
|
||||
pub fn aio_cancel_all(fd: RawFd) -> Result<AioCancelStat> {
|
||||
match unsafe { libc::aio_cancel(fd, ptr::null_mut()) } {
|
||||
pub fn aio_cancel_all<F: AsFd>(fd: F) -> Result<AioCancelStat> {
|
||||
match unsafe { libc::aio_cancel(fd.as_fd().as_raw_fd(), ptr::null_mut()) } {
|
||||
libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled),
|
||||
libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled),
|
||||
libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone),
|
||||
@@ -1031,18 +1032,18 @@ pub fn aio_cancel_all(fd: RawFd) -> Result<AioCancelStat> {
|
||||
/// ```
|
||||
/// # use nix::sys::aio::*;
|
||||
/// # use nix::sys::signal::SigevNotify;
|
||||
/// # use std::os::unix::io::AsRawFd;
|
||||
/// # use std::os::unix::io::AsFd;
|
||||
/// # use tempfile::tempfile;
|
||||
/// const WBUF: &[u8] = b"abcdef123456";
|
||||
/// let mut f = tempfile().unwrap();
|
||||
/// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(),
|
||||
/// let mut aiocb = Box::pin(AioWrite::new(f.as_fd(),
|
||||
/// 2, //offset
|
||||
/// WBUF,
|
||||
/// 0, //priority
|
||||
/// SigevNotify::SigevNone));
|
||||
/// aiocb.as_mut().submit().unwrap();
|
||||
/// aio_suspend(&[&*aiocb], None).expect("aio_suspend failed");
|
||||
/// assert_eq!(aiocb.as_mut().aio_return().unwrap() as usize, WBUF.len());
|
||||
/// assert_eq!(aiocb.as_mut().aio_return().unwrap(), WBUF.len());
|
||||
/// ```
|
||||
/// # References
|
||||
///
|
||||
@@ -1051,8 +1052,15 @@ pub fn aio_suspend(
|
||||
list: &[&dyn AsRef<libc::aiocb>],
|
||||
timeout: Option<TimeSpec>,
|
||||
) -> Result<()> {
|
||||
let p = list as *const [&dyn AsRef<libc::aiocb>]
|
||||
as *const [*const libc::aiocb] as *const *const libc::aiocb;
|
||||
// Note that this allocation could be eliminated by making the argument
|
||||
// generic, and accepting arguments like &[AioWrite]. But that would
|
||||
// prevent using aio_suspend to wait on a heterogeneous list of mixed
|
||||
// operations.
|
||||
let v = list
|
||||
.iter()
|
||||
.map(|x| x.as_ref() as *const libc::aiocb)
|
||||
.collect::<Vec<*const libc::aiocb>>();
|
||||
let p = v.as_ptr();
|
||||
let timep = match timeout {
|
||||
None => ptr::null::<libc::timespec>(),
|
||||
Some(x) => x.as_ref() as *const libc::timespec,
|
||||
@@ -1074,14 +1082,14 @@ pub fn aio_suspend(
|
||||
/// This mode is useful for otherwise-synchronous programs that want to execute
|
||||
/// a handful of I/O operations in parallel.
|
||||
/// ```
|
||||
/// # use std::os::unix::io::AsRawFd;
|
||||
/// # use std::os::unix::io::AsFd;
|
||||
/// # use nix::sys::aio::*;
|
||||
/// # use nix::sys::signal::SigevNotify;
|
||||
/// # use tempfile::tempfile;
|
||||
/// const WBUF: &[u8] = b"abcdef123456";
|
||||
/// let mut f = tempfile().unwrap();
|
||||
/// let mut aiow = Box::pin(AioWrite::new(
|
||||
/// f.as_raw_fd(),
|
||||
/// f.as_fd(),
|
||||
/// 2, // offset
|
||||
/// WBUF,
|
||||
/// 0, // priority
|
||||
@@ -1098,7 +1106,7 @@ pub fn aio_suspend(
|
||||
/// technique for reducing overall context-switch overhead, especially when
|
||||
/// combined with kqueue.
|
||||
/// ```
|
||||
/// # use std::os::unix::io::AsRawFd;
|
||||
/// # use std::os::unix::io::AsFd;
|
||||
/// # use std::thread;
|
||||
/// # use std::time;
|
||||
/// # use nix::errno::Errno;
|
||||
@@ -1108,7 +1116,7 @@ pub fn aio_suspend(
|
||||
/// const WBUF: &[u8] = b"abcdef123456";
|
||||
/// let mut f = tempfile().unwrap();
|
||||
/// let mut aiow = Box::pin(AioWrite::new(
|
||||
/// f.as_raw_fd(),
|
||||
/// f.as_fd(),
|
||||
/// 2, // offset
|
||||
/// WBUF,
|
||||
/// 0, // priority
|
||||
@@ -1132,18 +1140,15 @@ pub fn aio_suspend(
|
||||
/// possibly resubmit some.
|
||||
/// ```
|
||||
/// # use libc::c_int;
|
||||
/// # use std::os::unix::io::AsRawFd;
|
||||
/// # use std::os::unix::io::AsFd;
|
||||
/// # use std::sync::atomic::{AtomicBool, Ordering};
|
||||
/// # use std::thread;
|
||||
/// # use std::time;
|
||||
/// # use lazy_static::lazy_static;
|
||||
/// # use nix::errno::Errno;
|
||||
/// # use nix::sys::aio::*;
|
||||
/// # use nix::sys::signal::*;
|
||||
/// # use tempfile::tempfile;
|
||||
/// lazy_static! {
|
||||
/// pub static ref SIGNALED: AtomicBool = AtomicBool::new(false);
|
||||
/// }
|
||||
/// pub static SIGNALED: AtomicBool = AtomicBool::new(false);
|
||||
///
|
||||
/// extern fn sigfunc(_: c_int) {
|
||||
/// SIGNALED.store(true, Ordering::Relaxed);
|
||||
@@ -1157,7 +1162,7 @@ pub fn aio_suspend(
|
||||
/// const WBUF: &[u8] = b"abcdef123456";
|
||||
/// let mut f = tempfile().unwrap();
|
||||
/// let mut aiow = Box::pin(AioWrite::new(
|
||||
/// f.as_raw_fd(),
|
||||
/// f.as_fd(),
|
||||
/// 2, // offset
|
||||
/// WBUF,
|
||||
/// 0, // priority
|
||||
@@ -1172,6 +1177,10 @@ pub fn aio_suspend(
|
||||
/// // notification, we know that all operations are complete.
|
||||
/// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len());
|
||||
/// ```
|
||||
#[deprecated(
|
||||
since = "0.27.0",
|
||||
note = "https://github.com/nix-rust/nix/issues/2017"
|
||||
)]
|
||||
pub fn lio_listio(
|
||||
mode: LioMode,
|
||||
list: &mut [Pin<&mut dyn AsMut<libc::aiocb>>],
|
||||
@@ -1186,56 +1195,3 @@ pub fn lio_listio(
|
||||
})
|
||||
.map(drop)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod t {
|
||||
use super::*;
|
||||
|
||||
/// aio_suspend relies on casting Rust Aio* struct pointers to libc::aiocb
|
||||
/// pointers. This test ensures that such casts are valid.
|
||||
#[test]
|
||||
fn casting() {
|
||||
let sev = SigevNotify::SigevNone;
|
||||
let aiof = AioFsync::new(666, AioFsyncMode::O_SYNC, 0, sev);
|
||||
assert_eq!(
|
||||
aiof.as_ref() as *const libc::aiocb,
|
||||
&aiof as *const AioFsync as *const libc::aiocb
|
||||
);
|
||||
|
||||
let mut rbuf = [];
|
||||
let aior = AioRead::new(666, 0, &mut rbuf, 0, sev);
|
||||
assert_eq!(
|
||||
aior.as_ref() as *const libc::aiocb,
|
||||
&aior as *const AioRead as *const libc::aiocb
|
||||
);
|
||||
|
||||
let wbuf = [];
|
||||
let aiow = AioWrite::new(666, 0, &wbuf, 0, sev);
|
||||
assert_eq!(
|
||||
aiow.as_ref() as *const libc::aiocb,
|
||||
&aiow as *const AioWrite as *const libc::aiocb
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[test]
|
||||
fn casting_vectored() {
|
||||
let sev = SigevNotify::SigevNone;
|
||||
|
||||
let mut rbuf = [];
|
||||
let mut rbufs = [IoSliceMut::new(&mut rbuf)];
|
||||
let aiorv = AioReadv::new(666, 0, &mut rbufs[..], 0, sev);
|
||||
assert_eq!(
|
||||
aiorv.as_ref() as *const libc::aiocb,
|
||||
&aiorv as *const AioReadv as *const libc::aiocb
|
||||
);
|
||||
|
||||
let wbuf = [];
|
||||
let wbufs = [IoSlice::new(&wbuf)];
|
||||
let aiowv = AioWritev::new(666, 0, &wbufs, 0, sev);
|
||||
assert_eq!(
|
||||
aiowv.as_ref() as *const libc::aiocb,
|
||||
&aiowv as *const AioWritev as *const libc::aiocb
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+131
-4
@@ -1,9 +1,10 @@
|
||||
use crate::errno::Errno;
|
||||
pub use crate::poll_timeout::PollTimeout as EpollTimeout;
|
||||
pub use crate::poll_timeout::PollTimeoutTryFromError as EpollTimeoutTryFromError;
|
||||
use crate::Result;
|
||||
use libc::{self, c_int};
|
||||
use std::mem;
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::ptr;
|
||||
use std::os::unix::io::{AsFd, AsRawFd, FromRawFd, OwnedFd, RawFd};
|
||||
|
||||
libc_bitflags!(
|
||||
pub struct EpollFlags: c_int {
|
||||
@@ -70,6 +71,126 @@ impl EpollEvent {
|
||||
}
|
||||
}
|
||||
|
||||
/// A safe wrapper around [`epoll`](https://man7.org/linux/man-pages/man7/epoll.7.html).
|
||||
/// ```
|
||||
/// # use nix::sys::{epoll::{EpollTimeout, Epoll, EpollEvent, EpollFlags, EpollCreateFlags}, eventfd::{EventFd, EfdFlags}};
|
||||
/// # use nix::unistd::write;
|
||||
/// # use std::os::unix::io::{OwnedFd, FromRawFd, AsFd};
|
||||
/// # use std::time::{Instant, Duration};
|
||||
/// # fn main() -> nix::Result<()> {
|
||||
/// const DATA: u64 = 17;
|
||||
/// const MILLIS: u8 = 100;
|
||||
///
|
||||
/// // Create epoll
|
||||
/// let epoll = Epoll::new(EpollCreateFlags::empty())?;
|
||||
///
|
||||
/// // Create eventfd & Add event
|
||||
/// let eventfd = EventFd::new()?;
|
||||
/// epoll.add(&eventfd, EpollEvent::new(EpollFlags::EPOLLIN,DATA))?;
|
||||
///
|
||||
/// // Arm eventfd & Time wait
|
||||
/// eventfd.write(1)?;
|
||||
/// let now = Instant::now();
|
||||
///
|
||||
/// // Wait on event
|
||||
/// let mut events = [EpollEvent::empty()];
|
||||
/// epoll.wait(&mut events, MILLIS)?;
|
||||
///
|
||||
/// // Assert data correct & timeout didn't occur
|
||||
/// assert_eq!(events[0].data(), DATA);
|
||||
/// assert!(now.elapsed().as_millis() < MILLIS.into());
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct Epoll(pub OwnedFd);
|
||||
impl Epoll {
|
||||
/// Creates a new epoll instance and returns a file descriptor referring to that instance.
|
||||
///
|
||||
/// [`epoll_create1`](https://man7.org/linux/man-pages/man2/epoll_create1.2.html).
|
||||
pub fn new(flags: EpollCreateFlags) -> Result<Self> {
|
||||
let res = unsafe { libc::epoll_create1(flags.bits()) };
|
||||
let fd = Errno::result(res)?;
|
||||
let owned_fd = unsafe { OwnedFd::from_raw_fd(fd) };
|
||||
Ok(Self(owned_fd))
|
||||
}
|
||||
/// Add an entry to the interest list of the epoll file descriptor for
|
||||
/// specified in events.
|
||||
///
|
||||
/// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_ADD`.
|
||||
pub fn add<Fd: AsFd>(&self, fd: Fd, mut event: EpollEvent) -> Result<()> {
|
||||
self.epoll_ctl(EpollOp::EpollCtlAdd, fd, &mut event)
|
||||
}
|
||||
/// Remove (deregister) the target file descriptor `fd` from the interest list.
|
||||
///
|
||||
/// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_DEL` .
|
||||
pub fn delete<Fd: AsFd>(&self, fd: Fd) -> Result<()> {
|
||||
self.epoll_ctl(EpollOp::EpollCtlDel, fd, None)
|
||||
}
|
||||
/// Change the settings associated with `fd` in the interest list to the new settings specified
|
||||
/// in `event`.
|
||||
///
|
||||
/// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_MOD`.
|
||||
pub fn modify<Fd: AsFd>(
|
||||
&self,
|
||||
fd: Fd,
|
||||
event: &mut EpollEvent,
|
||||
) -> Result<()> {
|
||||
self.epoll_ctl(EpollOp::EpollCtlMod, fd, event)
|
||||
}
|
||||
/// Waits for I/O events, blocking the calling thread if no events are currently available.
|
||||
/// (This can be thought of as fetching items from the ready list of the epoll instance.)
|
||||
///
|
||||
/// [`epoll_wait`](https://man7.org/linux/man-pages/man2/epoll_wait.2.html)
|
||||
pub fn wait<T: Into<EpollTimeout>>(
|
||||
&self,
|
||||
events: &mut [EpollEvent],
|
||||
timeout: T,
|
||||
) -> Result<usize> {
|
||||
let res = unsafe {
|
||||
libc::epoll_wait(
|
||||
self.0.as_raw_fd(),
|
||||
events.as_mut_ptr().cast(),
|
||||
events.len() as c_int,
|
||||
timeout.into().into(),
|
||||
)
|
||||
};
|
||||
|
||||
Errno::result(res).map(|r| r as usize)
|
||||
}
|
||||
/// This system call is used to add, modify, or remove entries in the interest list of the epoll
|
||||
/// instance referred to by `self`. It requests that the operation `op` be performed for the
|
||||
/// target file descriptor, `fd`.
|
||||
///
|
||||
/// When possible prefer [`Epoll::add`], [`Epoll::delete`] and [`Epoll::modify`].
|
||||
///
|
||||
/// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html)
|
||||
fn epoll_ctl<'a, Fd: AsFd, T>(
|
||||
&self,
|
||||
op: EpollOp,
|
||||
fd: Fd,
|
||||
event: T,
|
||||
) -> Result<()>
|
||||
where
|
||||
T: Into<Option<&'a mut EpollEvent>>,
|
||||
{
|
||||
let event: Option<&mut EpollEvent> = event.into();
|
||||
let ptr = event
|
||||
.map(|x| &mut x.event as *mut libc::epoll_event)
|
||||
.unwrap_or(std::ptr::null_mut());
|
||||
unsafe {
|
||||
Errno::result(libc::epoll_ctl(
|
||||
self.0.as_raw_fd(),
|
||||
op as c_int,
|
||||
fd.as_fd().as_raw_fd(),
|
||||
ptr,
|
||||
))
|
||||
.map(drop)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.27.0", note = "Use Epoll::new() instead")]
|
||||
#[inline]
|
||||
pub fn epoll_create() -> Result<RawFd> {
|
||||
let res = unsafe { libc::epoll_create(1024) };
|
||||
@@ -77,6 +198,7 @@ pub fn epoll_create() -> Result<RawFd> {
|
||||
Errno::result(res)
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.27.0", note = "Use Epoll::new() instead")]
|
||||
#[inline]
|
||||
pub fn epoll_create1(flags: EpollCreateFlags) -> Result<RawFd> {
|
||||
let res = unsafe { libc::epoll_create1(flags.bits()) };
|
||||
@@ -84,6 +206,10 @@ pub fn epoll_create1(flags: EpollCreateFlags) -> Result<RawFd> {
|
||||
Errno::result(res)
|
||||
}
|
||||
|
||||
#[deprecated(
|
||||
since = "0.27.0",
|
||||
note = "Use corresponding Epoll methods instead"
|
||||
)]
|
||||
#[inline]
|
||||
pub fn epoll_ctl<'a, T>(
|
||||
epfd: RawFd,
|
||||
@@ -102,13 +228,14 @@ where
|
||||
if let Some(ref mut event) = event {
|
||||
libc::epoll_ctl(epfd, op as c_int, fd, &mut event.event)
|
||||
} else {
|
||||
libc::epoll_ctl(epfd, op as c_int, fd, ptr::null_mut())
|
||||
libc::epoll_ctl(epfd, op as c_int, fd, std::ptr::null_mut())
|
||||
}
|
||||
};
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.27.0", note = "Use Epoll::wait() instead")]
|
||||
#[inline]
|
||||
pub fn epoll_wait(
|
||||
epfd: RawFd,
|
||||
@@ -118,7 +245,7 @@ pub fn epoll_wait(
|
||||
let res = unsafe {
|
||||
libc::epoll_wait(
|
||||
epfd,
|
||||
events.as_mut_ptr() as *mut libc::epoll_event,
|
||||
events.as_mut_ptr().cast(),
|
||||
events.len() as c_int,
|
||||
timeout_ms as c_int,
|
||||
)
|
||||
|
||||
+238
-152
@@ -1,5 +1,7 @@
|
||||
/* TOOD: Implement for other kqueue based systems
|
||||
*/
|
||||
//! Kernel event notification mechanism
|
||||
//!
|
||||
//! # See Also
|
||||
//! [kqueue(2)](https://www.freebsd.org/cgi/man.cgi?query=kqueue)
|
||||
|
||||
use crate::{Errno, Result};
|
||||
#[cfg(not(target_os = "netbsd"))]
|
||||
@@ -8,23 +10,88 @@ use libc::{c_int, c_long, intptr_t, time_t, timespec, uintptr_t};
|
||||
use libc::{c_long, intptr_t, size_t, time_t, timespec, uintptr_t};
|
||||
use std::convert::TryInto;
|
||||
use std::mem;
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::os::fd::{AsFd, BorrowedFd};
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd};
|
||||
use std::ptr;
|
||||
|
||||
// Redefine kevent in terms of programmer-friendly enums and bitfields.
|
||||
/// A kernel event queue. Used to notify a process of various asynchronous
|
||||
/// events.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct KEvent {
|
||||
kevent: libc::kevent,
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
/// A kernel event queue.
|
||||
///
|
||||
/// Used by the kernel to notify the process of various types of asynchronous
|
||||
/// events.
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug)]
|
||||
pub struct Kqueue(OwnedFd);
|
||||
|
||||
impl AsFd for Kqueue {
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
self.0.as_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Kqueue> for OwnedFd {
|
||||
fn from(value: Kqueue) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Kqueue {
|
||||
/// Create a new kernel event queue.
|
||||
pub fn new() -> Result<Self> {
|
||||
let res = unsafe { libc::kqueue() };
|
||||
|
||||
Errno::result(res).map(|fd| unsafe { Self(OwnedFd::from_raw_fd(fd)) })
|
||||
}
|
||||
|
||||
/// Register new events with the kqueue, and return any pending events to
|
||||
/// the user.
|
||||
///
|
||||
/// This method will block until either the timeout expires, or a registered
|
||||
/// event triggers a notification.
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `changelist` - Any new kevents to register for notifications.
|
||||
/// - `eventlist` - Storage space for the kernel to return notifications.
|
||||
/// - `timeout` - An optional timeout.
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns the number of events placed in the `eventlist`. If an error
|
||||
/// occurs while processing an element of the `changelist` and there is
|
||||
/// enough room in the `eventlist`, then the event will be placed in the
|
||||
/// `eventlist` with `EV_ERROR` set in `flags` and the system error in
|
||||
/// `data`.
|
||||
pub fn kevent(
|
||||
&self,
|
||||
changelist: &[KEvent],
|
||||
eventlist: &mut [KEvent],
|
||||
timeout_opt: Option<timespec>,
|
||||
) -> Result<usize> {
|
||||
let res = unsafe {
|
||||
libc::kevent(
|
||||
self.0.as_raw_fd(),
|
||||
changelist.as_ptr().cast(),
|
||||
changelist.len() as type_of_nchanges,
|
||||
eventlist.as_mut_ptr().cast(),
|
||||
eventlist.len() as type_of_nchanges,
|
||||
if let Some(ref timeout) = timeout_opt {
|
||||
timeout as *const timespec
|
||||
} else {
|
||||
ptr::null()
|
||||
},
|
||||
)
|
||||
};
|
||||
Errno::result(res).map(|r| r as usize)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(freebsdlike, apple_targets, target_os = "openbsd"))]
|
||||
type type_of_udata = *mut libc::c_void;
|
||||
#[cfg(target_os = "netbsd")]
|
||||
type type_of_udata = intptr_t;
|
||||
@@ -37,22 +104,31 @@ libc_enum! {
|
||||
#[cfg_attr(target_os = "netbsd", repr(u32))]
|
||||
#[cfg_attr(not(target_os = "netbsd"), repr(i16))]
|
||||
#[non_exhaustive]
|
||||
/// Kqueue filter types. These are all the different types of event that a
|
||||
/// kqueue can notify for.
|
||||
pub enum EventFilter {
|
||||
/// Notifies on the completion of a POSIX AIO operation.
|
||||
EVFILT_AIO,
|
||||
/// Returns whenever there is no remaining data in the write buffer
|
||||
#[cfg(target_os = "freebsd")]
|
||||
/// Returns whenever there is no remaining data in the write buffer
|
||||
EVFILT_EMPTY,
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
/// Takes a descriptor as the identifier, and returns whenever one of
|
||||
/// the specified exceptional conditions has occurred on the descriptor.
|
||||
EVFILT_EXCEPT,
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos"))]
|
||||
#[cfg(any(freebsdlike, apple_targets))]
|
||||
/// Establishes a file system monitor.
|
||||
EVFILT_FS,
|
||||
#[cfg(target_os = "freebsd")]
|
||||
/// Notify for completion of a list of POSIX AIO operations.
|
||||
/// # See Also
|
||||
/// [lio_listio(2)](https://www.freebsd.org/cgi/man.cgi?query=lio_listio)
|
||||
EVFILT_LIO,
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
#[cfg(apple_targets)]
|
||||
/// Mach portsets
|
||||
EVFILT_MACHPORT,
|
||||
/// Notifies when a process performs one or more of the requested
|
||||
/// events.
|
||||
EVFILT_PROC,
|
||||
/// Returns events associated with the process referenced by a given
|
||||
/// process descriptor, created by `pdfork()`. The events to monitor are:
|
||||
@@ -60,157 +136,207 @@ libc_enum! {
|
||||
/// - NOTE_EXIT: the process has exited. The exit status will be stored in data.
|
||||
#[cfg(target_os = "freebsd")]
|
||||
EVFILT_PROCDESC,
|
||||
/// Takes a file descriptor as the identifier, and notifies whenever
|
||||
/// there is data available to read.
|
||||
EVFILT_READ,
|
||||
/// Returns whenever an asynchronous `sendfile()` call completes.
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[doc(hidden)]
|
||||
#[deprecated(since = "0.27.0", note = "Never fully implemented by the OS")]
|
||||
EVFILT_SENDFILE,
|
||||
/// Takes a signal number to monitor as the identifier and notifies when
|
||||
/// the given signal is delivered to the process.
|
||||
EVFILT_SIGNAL,
|
||||
/// Establishes a timer and notifies when the timer expires.
|
||||
EVFILT_TIMER,
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos"))]
|
||||
#[cfg(any(freebsdlike, apple_targets))]
|
||||
/// Notifies only when explicitly requested by the user.
|
||||
EVFILT_USER,
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
#[cfg(apple_targets)]
|
||||
/// Virtual memory events
|
||||
EVFILT_VM,
|
||||
/// Notifies when a requested event happens on a specified file.
|
||||
EVFILT_VNODE,
|
||||
/// Takes a file descriptor as the identifier, and notifies whenever
|
||||
/// it is possible to write to the file without blocking.
|
||||
EVFILT_WRITE,
|
||||
}
|
||||
impl TryFrom<type_of_event_filter>
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
#[cfg(any(freebsdlike, apple_targets, target_os = "openbsd"))]
|
||||
#[doc(hidden)]
|
||||
pub type type_of_event_flag = u16;
|
||||
#[cfg(target_os = "netbsd")]
|
||||
#[doc(hidden)]
|
||||
pub type type_of_event_flag = u32;
|
||||
libc_bitflags! {
|
||||
pub struct EventFlag: type_of_event_flag {
|
||||
/// Event flags. See the man page for details.
|
||||
// There's no useful documentation we can write for the individual flags
|
||||
// that wouldn't simply be repeating the man page.
|
||||
pub struct EvFlags: type_of_event_flag {
|
||||
#[allow(missing_docs)]
|
||||
EV_ADD;
|
||||
#[allow(missing_docs)]
|
||||
EV_CLEAR;
|
||||
#[allow(missing_docs)]
|
||||
EV_DELETE;
|
||||
#[allow(missing_docs)]
|
||||
EV_DISABLE;
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
|
||||
target_os = "ios", target_os = "macos",
|
||||
target_os = "netbsd", target_os = "openbsd"))]
|
||||
#[cfg(bsd)]
|
||||
#[allow(missing_docs)]
|
||||
EV_DISPATCH;
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[allow(missing_docs)]
|
||||
EV_DROP;
|
||||
#[allow(missing_docs)]
|
||||
EV_ENABLE;
|
||||
#[allow(missing_docs)]
|
||||
EV_EOF;
|
||||
#[allow(missing_docs)]
|
||||
EV_ERROR;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
#[cfg(apple_targets)]
|
||||
#[allow(missing_docs)]
|
||||
EV_FLAG0;
|
||||
#[allow(missing_docs)]
|
||||
EV_FLAG1;
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
#[allow(missing_docs)]
|
||||
EV_NODATA;
|
||||
#[allow(missing_docs)]
|
||||
EV_ONESHOT;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
#[cfg(apple_targets)]
|
||||
#[allow(missing_docs)]
|
||||
EV_OOBAND;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
#[cfg(apple_targets)]
|
||||
#[allow(missing_docs)]
|
||||
EV_POLL;
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
|
||||
target_os = "ios", target_os = "macos",
|
||||
target_os = "netbsd", target_os = "openbsd"))]
|
||||
#[cfg(bsd)]
|
||||
#[allow(missing_docs)]
|
||||
EV_RECEIPT;
|
||||
}
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.30.0", note = "Use `EvFlags instead`")]
|
||||
/// The deprecated EventFlag type alias
|
||||
pub type EventFlag = EvFlags;
|
||||
|
||||
libc_bitflags!(
|
||||
/// Filter-specific flags. See the man page for details.
|
||||
// There's no useful documentation we can write for the individual flags
|
||||
// that wouldn't simply be repeating the man page.
|
||||
#[allow(missing_docs)]
|
||||
pub struct FilterFlag: u32 {
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
#[cfg(apple_targets)]
|
||||
#[allow(missing_docs)]
|
||||
NOTE_ABSOLUTE;
|
||||
#[allow(missing_docs)]
|
||||
NOTE_ATTRIB;
|
||||
#[allow(missing_docs)]
|
||||
NOTE_CHILD;
|
||||
#[allow(missing_docs)]
|
||||
NOTE_DELETE;
|
||||
#[cfg(target_os = "openbsd")]
|
||||
#[allow(missing_docs)]
|
||||
NOTE_EOF;
|
||||
#[allow(missing_docs)]
|
||||
NOTE_EXEC;
|
||||
#[allow(missing_docs)]
|
||||
NOTE_EXIT;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
#[cfg(apple_targets)]
|
||||
#[allow(missing_docs)]
|
||||
NOTE_EXITSTATUS;
|
||||
#[allow(missing_docs)]
|
||||
NOTE_EXTEND;
|
||||
#[cfg(any(target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly"))]
|
||||
#[cfg(any(apple_targets, freebsdlike))]
|
||||
#[allow(missing_docs)]
|
||||
NOTE_FFAND;
|
||||
#[cfg(any(target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly"))]
|
||||
#[cfg(any(apple_targets, freebsdlike))]
|
||||
#[allow(missing_docs)]
|
||||
NOTE_FFCOPY;
|
||||
#[cfg(any(target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly"))]
|
||||
#[cfg(any(apple_targets, freebsdlike))]
|
||||
#[allow(missing_docs)]
|
||||
NOTE_FFCTRLMASK;
|
||||
#[cfg(any(target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly"))]
|
||||
#[cfg(any(apple_targets, freebsdlike))]
|
||||
#[allow(missing_docs)]
|
||||
NOTE_FFLAGSMASK;
|
||||
#[cfg(any(target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly"))]
|
||||
#[cfg(any(apple_targets, freebsdlike))]
|
||||
#[allow(missing_docs)]
|
||||
NOTE_FFNOP;
|
||||
#[cfg(any(target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly"))]
|
||||
#[cfg(any(apple_targets, freebsdlike))]
|
||||
#[allow(missing_docs)]
|
||||
NOTE_FFOR;
|
||||
#[allow(missing_docs)]
|
||||
NOTE_FORK;
|
||||
#[allow(missing_docs)]
|
||||
NOTE_LINK;
|
||||
#[allow(missing_docs)]
|
||||
NOTE_LOWAT;
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[allow(missing_docs)]
|
||||
NOTE_MSECONDS;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
#[cfg(apple_targets)]
|
||||
#[allow(missing_docs)]
|
||||
NOTE_NONE;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
|
||||
#[cfg(any(
|
||||
apple_targets,
|
||||
target_os = "freebsd"))]
|
||||
#[allow(missing_docs)]
|
||||
NOTE_NSECONDS;
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
#[allow(missing_docs)]
|
||||
NOTE_OOB;
|
||||
#[allow(missing_docs)]
|
||||
NOTE_PCTRLMASK;
|
||||
#[allow(missing_docs)]
|
||||
NOTE_PDATAMASK;
|
||||
#[allow(missing_docs)]
|
||||
NOTE_RENAME;
|
||||
#[allow(missing_docs)]
|
||||
NOTE_REVOKE;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
|
||||
#[cfg(any(
|
||||
apple_targets,
|
||||
target_os = "freebsd"))]
|
||||
#[allow(missing_docs)]
|
||||
NOTE_SECONDS;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
#[cfg(apple_targets)]
|
||||
#[allow(missing_docs)]
|
||||
NOTE_SIGNAL;
|
||||
#[allow(missing_docs)]
|
||||
NOTE_TRACK;
|
||||
#[allow(missing_docs)]
|
||||
NOTE_TRACKERR;
|
||||
#[cfg(any(target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly"))]
|
||||
#[cfg(any(apple_targets, freebsdlike))]
|
||||
#[allow(missing_docs)]
|
||||
NOTE_TRIGGER;
|
||||
#[cfg(target_os = "openbsd")]
|
||||
#[allow(missing_docs)]
|
||||
NOTE_TRUNCATE;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
|
||||
#[cfg(any(
|
||||
apple_targets,
|
||||
target_os = "freebsd"))]
|
||||
#[allow(missing_docs)]
|
||||
NOTE_USECONDS;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
#[cfg(apple_targets)]
|
||||
#[allow(missing_docs)]
|
||||
NOTE_VM_ERROR;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
#[cfg(apple_targets)]
|
||||
#[allow(missing_docs)]
|
||||
NOTE_VM_PRESSURE;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
#[cfg(apple_targets)]
|
||||
#[allow(missing_docs)]
|
||||
NOTE_VM_PRESSURE_SUDDEN_TERMINATE;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
#[cfg(apple_targets)]
|
||||
#[allow(missing_docs)]
|
||||
NOTE_VM_PRESSURE_TERMINATE;
|
||||
#[allow(missing_docs)]
|
||||
NOTE_WRITE;
|
||||
}
|
||||
);
|
||||
|
||||
pub fn kqueue() -> Result<RawFd> {
|
||||
let res = unsafe { libc::kqueue() };
|
||||
|
||||
Errno::result(res)
|
||||
#[allow(missing_docs)]
|
||||
#[deprecated(since = "0.27.0", note = "Use KEvent::new instead")]
|
||||
pub fn kqueue() -> Result<Kqueue> {
|
||||
Kqueue::new()
|
||||
}
|
||||
|
||||
// KEvent can't derive Send because on some operating systems, udata is defined
|
||||
@@ -220,10 +346,12 @@ unsafe impl Send for KEvent {}
|
||||
|
||||
impl KEvent {
|
||||
#[allow(clippy::needless_update)] // Not needless on all platforms.
|
||||
/// Construct a new `KEvent` suitable for submission to the kernel via the
|
||||
/// `changelist` argument of [`Kqueue::kevent`].
|
||||
pub fn new(
|
||||
ident: uintptr_t,
|
||||
filter: EventFilter,
|
||||
flags: EventFlag,
|
||||
flags: EvFlags,
|
||||
fflags: FilterFlag,
|
||||
data: intptr_t,
|
||||
udata: intptr_t,
|
||||
@@ -242,33 +370,46 @@ impl KEvent {
|
||||
}
|
||||
}
|
||||
|
||||
/// Value used to identify this event. The exact interpretation is
|
||||
/// determined by the attached filter, but often is a raw file descriptor.
|
||||
pub fn ident(&self) -> uintptr_t {
|
||||
self.kevent.ident
|
||||
}
|
||||
|
||||
/// Identifies the kernel filter used to process this event.
|
||||
///
|
||||
/// Will only return an error if the kernel reports an event via a filter
|
||||
/// that is unknown to Nix.
|
||||
pub fn filter(&self) -> Result<EventFilter> {
|
||||
self.kevent.filter.try_into()
|
||||
}
|
||||
|
||||
pub fn flags(&self) -> EventFlag {
|
||||
EventFlag::from_bits(self.kevent.flags).unwrap()
|
||||
/// Flags control what the kernel will do when this event is added with
|
||||
/// [`Kqueue::kevent`].
|
||||
pub fn flags(&self) -> EvFlags {
|
||||
EvFlags::from_bits(self.kevent.flags).unwrap()
|
||||
}
|
||||
|
||||
/// Filter-specific flags.
|
||||
pub fn fflags(&self) -> FilterFlag {
|
||||
FilterFlag::from_bits(self.kevent.fflags).unwrap()
|
||||
}
|
||||
|
||||
/// Filter-specific data value.
|
||||
pub fn data(&self) -> intptr_t {
|
||||
self.kevent.data as intptr_t
|
||||
}
|
||||
|
||||
/// Opaque user-defined value passed through the kernel unchanged.
|
||||
pub fn udata(&self) -> intptr_t {
|
||||
self.kevent.udata as intptr_t
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[deprecated(since = "0.27.0", note = "Use Kqueue::kevent instead")]
|
||||
pub fn kevent(
|
||||
kq: RawFd,
|
||||
kq: &Kqueue,
|
||||
changelist: &[KEvent],
|
||||
eventlist: &mut [KEvent],
|
||||
timeout_ms: usize,
|
||||
@@ -279,50 +420,34 @@ pub fn kevent(
|
||||
tv_nsec: ((timeout_ms % 1000) * 1_000_000) as c_long,
|
||||
};
|
||||
|
||||
kevent_ts(kq, changelist, eventlist, Some(timeout))
|
||||
kq.kevent(changelist, eventlist, Some(timeout))
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
#[cfg(any(apple_targets, freebsdlike, target_os = "openbsd"))]
|
||||
type type_of_nchanges = c_int;
|
||||
#[cfg(target_os = "netbsd")]
|
||||
type type_of_nchanges = size_t;
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[deprecated(since = "0.27.0", note = "Use Kqueue::kevent instead")]
|
||||
pub fn kevent_ts(
|
||||
kq: RawFd,
|
||||
kq: &Kqueue,
|
||||
changelist: &[KEvent],
|
||||
eventlist: &mut [KEvent],
|
||||
timeout_opt: Option<timespec>,
|
||||
) -> Result<usize> {
|
||||
let res = unsafe {
|
||||
libc::kevent(
|
||||
kq,
|
||||
changelist.as_ptr() as *const libc::kevent,
|
||||
changelist.len() as type_of_nchanges,
|
||||
eventlist.as_mut_ptr() as *mut libc::kevent,
|
||||
eventlist.len() as type_of_nchanges,
|
||||
if let Some(ref timeout) = timeout_opt {
|
||||
timeout as *const timespec
|
||||
} else {
|
||||
ptr::null()
|
||||
},
|
||||
)
|
||||
};
|
||||
|
||||
Errno::result(res).map(|r| r as usize)
|
||||
kq.kevent(changelist, eventlist, timeout_opt)
|
||||
}
|
||||
|
||||
/// Modify an existing [`KEvent`].
|
||||
// Probably should deprecate. Would anybody ever use it over `KEvent::new`?
|
||||
#[deprecated(since = "0.27.0", note = "Use Kqueue::kevent instead")]
|
||||
#[inline]
|
||||
pub fn ev_set(
|
||||
ev: &mut KEvent,
|
||||
ident: usize,
|
||||
filter: EventFilter,
|
||||
flags: EventFlag,
|
||||
flags: EvFlags,
|
||||
fflags: FilterFlag,
|
||||
udata: intptr_t,
|
||||
) {
|
||||
@@ -333,42 +458,3 @@ pub fn ev_set(
|
||||
ev.kevent.data = 0;
|
||||
ev.kevent.udata = udata as type_of_udata;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_struct_kevent() {
|
||||
use std::mem;
|
||||
|
||||
let udata: intptr_t = 12345;
|
||||
|
||||
let actual = KEvent::new(
|
||||
0xdead_beef,
|
||||
EventFilter::EVFILT_READ,
|
||||
EventFlag::EV_ONESHOT | EventFlag::EV_ADD,
|
||||
FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT,
|
||||
0x1337,
|
||||
udata,
|
||||
);
|
||||
assert_eq!(0xdead_beef, actual.ident());
|
||||
let filter = actual.kevent.filter;
|
||||
assert_eq!(libc::EVFILT_READ, filter);
|
||||
assert_eq!(libc::EV_ONESHOT | libc::EV_ADD, actual.flags().bits());
|
||||
assert_eq!(libc::NOTE_CHILD | libc::NOTE_EXIT, actual.fflags().bits());
|
||||
assert_eq!(0x1337, actual.data());
|
||||
assert_eq!(udata as type_of_udata, actual.udata() as type_of_udata);
|
||||
assert_eq!(mem::size_of::<libc::kevent>(), mem::size_of::<KEvent>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_kevent_filter() {
|
||||
let udata: intptr_t = 12345;
|
||||
|
||||
let actual = KEvent::new(
|
||||
0xdead_beef,
|
||||
EventFilter::EVFILT_READ,
|
||||
EventFlag::EV_ONESHOT | EventFlag::EV_ADD,
|
||||
FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT,
|
||||
0x1337,
|
||||
udata,
|
||||
);
|
||||
assert_eq!(EventFilter::EVFILT_READ, actual.filter().unwrap());
|
||||
}
|
||||
|
||||
+108
-7
@@ -1,17 +1,118 @@
|
||||
use crate::errno::Errno;
|
||||
use crate::Result;
|
||||
use std::os::unix::io::RawFd;
|
||||
use crate::{unistd, Result};
|
||||
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd};
|
||||
|
||||
libc_bitflags! {
|
||||
/// Eventfd flags.
|
||||
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
|
||||
/// Set the close-on-exec (`FD_CLOEXEC`) flag on the new event file descriptor.
|
||||
EFD_CLOEXEC; // Since Linux 2.6.27/FreeBSD 13.0
|
||||
/// Set the `O_NONBLOCK` file status flag on the new event file description.
|
||||
EFD_NONBLOCK; // Since Linux 2.6.27/FreeBSD 13.0
|
||||
/// Provide semaphore-like semantics for reads from the new event file
|
||||
/// descriptor.
|
||||
EFD_SEMAPHORE; // Since Linux 2.6.30/FreeBSD 13.0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eventfd(initval: libc::c_uint, flags: EfdFlags) -> Result<RawFd> {
|
||||
#[deprecated(
|
||||
since = "0.28.0",
|
||||
note = "Use EventFd::from_value_and_flags() instead"
|
||||
)]
|
||||
#[allow(missing_docs)]
|
||||
pub fn eventfd(initval: libc::c_uint, flags: EfdFlags) -> Result<OwnedFd> {
|
||||
let res = unsafe { libc::eventfd(initval, flags.bits()) };
|
||||
|
||||
Errno::result(res).map(|r| r as RawFd)
|
||||
Errno::result(res).map(|r| unsafe { OwnedFd::from_raw_fd(r) })
|
||||
}
|
||||
|
||||
/// An eventfd file descriptor.
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct EventFd(OwnedFd);
|
||||
|
||||
impl EventFd {
|
||||
/// [`EventFd::from_value_and_flags`] with `init_val = 0` and `flags = EfdFlags::empty()`.
|
||||
pub fn new() -> Result<Self> {
|
||||
Self::from_value_and_flags(0, EfdFlags::empty())
|
||||
}
|
||||
|
||||
/// Constructs [`EventFd`] with the given `init_val` and `flags`.
|
||||
///
|
||||
/// Wrapper around [`libc::eventfd`].
|
||||
pub fn from_value_and_flags(
|
||||
init_val: u32,
|
||||
flags: EfdFlags,
|
||||
) -> Result<Self> {
|
||||
let res = unsafe { libc::eventfd(init_val, flags.bits()) };
|
||||
Errno::result(res).map(|r| Self(unsafe { OwnedFd::from_raw_fd(r) }))
|
||||
}
|
||||
|
||||
/// [`EventFd::from_value_and_flags`] with `init_val = 0` and given `flags`.
|
||||
pub fn from_flags(flags: EfdFlags) -> Result<Self> {
|
||||
Self::from_value_and_flags(0, flags)
|
||||
}
|
||||
|
||||
/// [`EventFd::from_value_and_flags`] with given `init_val` and `flags = EfdFlags::empty()`.
|
||||
pub fn from_value(init_val: u32) -> Result<Self> {
|
||||
Self::from_value_and_flags(init_val, EfdFlags::empty())
|
||||
}
|
||||
|
||||
/// Constructs an `EventFd` wrapping an existing `OwnedFd`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `OwnedFd` is a valid eventfd.
|
||||
pub unsafe fn from_owned_fd(fd: OwnedFd) -> Self {
|
||||
Self(fd)
|
||||
}
|
||||
|
||||
/// Enqueues `value` triggers, i.e., adds the integer value supplied in `value`
|
||||
/// to the counter.
|
||||
///
|
||||
/// The next `value` calls to `poll`, `select` or `epoll` will return immediately.
|
||||
///
|
||||
/// [`EventFd::write`] with `value`.
|
||||
pub fn write(&self, value: u64) -> Result<usize> {
|
||||
unistd::write(&self.0, &value.to_ne_bytes())
|
||||
}
|
||||
|
||||
/// Reads the value from the file descriptor.
|
||||
///
|
||||
/// * If [`EFD_SEMAPHORE`](EfdFlags::EFD_SEMAPHORE) was not specified and
|
||||
/// the eventfd counter has a nonzero value, then this function returns
|
||||
/// an `u64` containing that value, and the counter's value is reset to
|
||||
/// zero.
|
||||
///
|
||||
/// * If [`EFD_SEMAPHORE`](EfdFlags::EFD_SEMAPHORE) was specified and the
|
||||
/// eventfd counter has a nonzero value, then this function returns an
|
||||
/// `u64` containing the value 1, and the counter's value is decremented
|
||||
/// by 1.
|
||||
///
|
||||
/// * If the eventfd counter is zero at the time of this call, then the
|
||||
/// call either blocks until the counter becomes nonzero (at which time,
|
||||
/// this function proceeds as described above) or fails with the error
|
||||
/// `EAGAIN` if the file descriptor has been made nonblocking with
|
||||
/// [`EFD_NONBLOCK`](EfdFlags::EFD_NONBLOCK).
|
||||
pub fn read(&self) -> Result<u64> {
|
||||
let mut arr = [0; std::mem::size_of::<u64>()];
|
||||
unistd::read(&self.0, &mut arr)?;
|
||||
Ok(u64::from_ne_bytes(arr))
|
||||
}
|
||||
}
|
||||
impl AsFd for EventFd {
|
||||
fn as_fd(&self) -> BorrowedFd {
|
||||
self.0.as_fd()
|
||||
}
|
||||
}
|
||||
impl AsRawFd for EventFd {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EventFd> for OwnedFd {
|
||||
fn from(value: EventFd) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,446 @@
|
||||
//! Monitoring API for filesystem events.
|
||||
//!
|
||||
//! Fanotify is a Linux-only API to monitor filesystems events.
|
||||
//!
|
||||
//! Additional capabilities compared to the `inotify` API include the ability to
|
||||
//! monitor all of the objects in a mounted filesystem, the ability to make
|
||||
//! access permission decisions, and the possibility to read or modify files
|
||||
//! before access by other applications.
|
||||
//!
|
||||
//! For more documentation, please read
|
||||
//! [fanotify(7)](https://man7.org/linux/man-pages/man7/fanotify.7.html).
|
||||
|
||||
use crate::errno::Errno;
|
||||
use crate::fcntl::OFlag;
|
||||
use crate::unistd::{close, read, write};
|
||||
use crate::{NixPath, Result};
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::{size_of, MaybeUninit};
|
||||
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd};
|
||||
use std::ptr;
|
||||
|
||||
libc_bitflags! {
|
||||
/// Mask for defining which events shall be listened with [`Fanotify::mark()`]
|
||||
/// and for querying notifications.
|
||||
pub struct MaskFlags: u64 {
|
||||
/// File was accessed.
|
||||
FAN_ACCESS;
|
||||
/// File was modified.
|
||||
FAN_MODIFY;
|
||||
/// Metadata has changed. Since Linux 5.1.
|
||||
FAN_ATTRIB;
|
||||
/// Writtable file was closed.
|
||||
FAN_CLOSE_WRITE;
|
||||
/// Unwrittable file was closed.
|
||||
FAN_CLOSE_NOWRITE;
|
||||
/// File was opened.
|
||||
FAN_OPEN;
|
||||
/// File was moved from X. Since Linux 5.1.
|
||||
FAN_MOVED_FROM;
|
||||
/// File was moved to Y. Since Linux 5.1.
|
||||
FAN_MOVED_TO;
|
||||
/// Subfile was created. Since Linux 5.1.
|
||||
FAN_CREATE;
|
||||
/// Subfile was deleted. Since Linux 5.1.
|
||||
FAN_DELETE;
|
||||
/// Self was deleted. Since Linux 5.1.
|
||||
FAN_DELETE_SELF;
|
||||
/// Self was moved. Since Linux 5.1.
|
||||
FAN_MOVE_SELF;
|
||||
/// File was opened for execution. Since Linux 5.0.
|
||||
FAN_OPEN_EXEC;
|
||||
|
||||
/// Event queue overflowed.
|
||||
FAN_Q_OVERFLOW;
|
||||
/// Filesystem error. Since Linux 5.16.
|
||||
FAN_FS_ERROR;
|
||||
|
||||
/// Permission to open file was requested.
|
||||
FAN_OPEN_PERM;
|
||||
/// Permission to access file was requested.
|
||||
FAN_ACCESS_PERM;
|
||||
/// Permission to open file for execution was requested. Since Linux
|
||||
/// 5.0.
|
||||
FAN_OPEN_EXEC_PERM;
|
||||
|
||||
/// Interested in child events.
|
||||
FAN_EVENT_ON_CHILD;
|
||||
|
||||
/// File was renamed. Since Linux 5.17.
|
||||
FAN_RENAME;
|
||||
|
||||
/// Event occurred against dir.
|
||||
FAN_ONDIR;
|
||||
|
||||
/// Combination of `FAN_CLOSE_WRITE` and `FAN_CLOSE_NOWRITE`.
|
||||
FAN_CLOSE;
|
||||
/// Combination of `FAN_MOVED_FROM` and `FAN_MOVED_TO`.
|
||||
FAN_MOVE;
|
||||
}
|
||||
}
|
||||
|
||||
libc_bitflags! {
|
||||
/// Configuration options for [`Fanotify::init()`].
|
||||
pub struct InitFlags: libc::c_uint {
|
||||
/// Close-on-exec flag set on the file descriptor.
|
||||
FAN_CLOEXEC;
|
||||
/// Nonblocking flag set on the file descriptor.
|
||||
FAN_NONBLOCK;
|
||||
|
||||
/// Receipt of events notifications.
|
||||
FAN_CLASS_NOTIF;
|
||||
/// Receipt of events for permission decisions, after they contain final
|
||||
/// data.
|
||||
FAN_CLASS_CONTENT;
|
||||
/// Receipt of events for permission decisions, before they contain
|
||||
/// final data.
|
||||
FAN_CLASS_PRE_CONTENT;
|
||||
|
||||
/// Remove the limit on the number of events in the event queue.
|
||||
///
|
||||
/// Prior to Linux kernel 5.13, this limit was hardcoded to 16384. After
|
||||
/// 5.13, one can change it via file `/proc/sys/fs/fanotify/max_queued_events`.
|
||||
///
|
||||
/// See `fanotify(7)` for details about this limit. Use of this flag
|
||||
/// requires the `CAP_SYS_ADMIN` capability.
|
||||
FAN_UNLIMITED_QUEUE;
|
||||
/// Remove the limit on the number of fanotify marks per user.
|
||||
///
|
||||
/// Prior to Linux kernel 5.13, this limit was hardcoded to 8192 (per
|
||||
/// group, not per user). After 5.13, one can change it via file
|
||||
/// `/proc/sys/fs/fanotify/max_user_marks`.
|
||||
///
|
||||
/// See `fanotify(7)` for details about this limit. Use of this flag
|
||||
/// requires the `CAP_SYS_ADMIN` capability.
|
||||
FAN_UNLIMITED_MARKS;
|
||||
|
||||
/// Make `FanotifyEvent::pid` return pidfd. Since Linux 5.15.
|
||||
FAN_REPORT_PIDFD;
|
||||
/// Make `FanotifyEvent::pid` return thread id. Since Linux 4.20.
|
||||
FAN_REPORT_TID;
|
||||
}
|
||||
}
|
||||
|
||||
libc_bitflags! {
|
||||
/// File status flags for fanotify events file descriptors.
|
||||
pub struct EventFFlags: libc::c_uint {
|
||||
/// Read only access.
|
||||
O_RDONLY as libc::c_uint;
|
||||
/// Write only access.
|
||||
O_WRONLY as libc::c_uint;
|
||||
/// Read and write access.
|
||||
O_RDWR as libc::c_uint;
|
||||
/// Support for files exceeded 2 GB.
|
||||
O_LARGEFILE as libc::c_uint;
|
||||
/// Close-on-exec flag for the file descriptor. Since Linux 3.18.
|
||||
O_CLOEXEC as libc::c_uint;
|
||||
/// Append mode for the file descriptor.
|
||||
O_APPEND as libc::c_uint;
|
||||
/// Synchronized I/O data integrity completion.
|
||||
O_DSYNC as libc::c_uint;
|
||||
/// No file last access time update.
|
||||
O_NOATIME as libc::c_uint;
|
||||
/// Nonblocking mode for the file descriptor.
|
||||
O_NONBLOCK as libc::c_uint;
|
||||
/// Synchronized I/O file integrity completion.
|
||||
O_SYNC as libc::c_uint;
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<OFlag> for EventFFlags {
|
||||
type Error = Errno;
|
||||
|
||||
fn try_from(o_flag: OFlag) -> Result<Self> {
|
||||
EventFFlags::from_bits(o_flag.bits() as u32).ok_or(Errno::EINVAL)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EventFFlags> for OFlag {
|
||||
fn from(event_f_flags: EventFFlags) -> Self {
|
||||
OFlag::from_bits_retain(event_f_flags.bits() as i32)
|
||||
}
|
||||
}
|
||||
|
||||
libc_bitflags! {
|
||||
/// Configuration options for [`Fanotify::mark()`].
|
||||
pub struct MarkFlags: libc::c_uint {
|
||||
/// Add the events to the marks.
|
||||
FAN_MARK_ADD;
|
||||
/// Remove the events to the marks.
|
||||
FAN_MARK_REMOVE;
|
||||
/// Don't follow symlinks, mark them.
|
||||
FAN_MARK_DONT_FOLLOW;
|
||||
/// Raise an error if filesystem to be marked is not a directory.
|
||||
FAN_MARK_ONLYDIR;
|
||||
/// Events added to or removed from the marks.
|
||||
FAN_MARK_IGNORED_MASK;
|
||||
/// Ignore mask shall survive modify events.
|
||||
FAN_MARK_IGNORED_SURV_MODIFY;
|
||||
/// Remove all marks.
|
||||
FAN_MARK_FLUSH;
|
||||
/// Do not pin inode object in the inode cache. Since Linux 5.19.
|
||||
FAN_MARK_EVICTABLE;
|
||||
/// Events added to or removed from the marks. Since Linux 6.0.
|
||||
FAN_MARK_IGNORE;
|
||||
|
||||
/// Default flag.
|
||||
FAN_MARK_INODE;
|
||||
/// Mark the mount specified by pathname.
|
||||
FAN_MARK_MOUNT;
|
||||
/// Mark the filesystem specified by pathname. Since Linux 4.20.
|
||||
FAN_MARK_FILESYSTEM;
|
||||
|
||||
/// Combination of `FAN_MARK_IGNORE` and `FAN_MARK_IGNORED_SURV_MODIFY`.
|
||||
FAN_MARK_IGNORE_SURV;
|
||||
}
|
||||
}
|
||||
|
||||
/// Compile version number of fanotify API.
|
||||
pub const FANOTIFY_METADATA_VERSION: u8 = libc::FANOTIFY_METADATA_VERSION;
|
||||
|
||||
/// Abstract over [`libc::fanotify_event_metadata`], which represents an event
|
||||
/// received via [`Fanotify::read_events`].
|
||||
// Is not Clone due to fd field, to avoid use-after-close scenarios.
|
||||
#[derive(Debug, Eq, Hash, PartialEq)]
|
||||
#[repr(transparent)]
|
||||
#[allow(missing_copy_implementations)]
|
||||
pub struct FanotifyEvent(libc::fanotify_event_metadata);
|
||||
|
||||
impl FanotifyEvent {
|
||||
/// Version number for the structure. It must be compared to
|
||||
/// `FANOTIFY_METADATA_VERSION` to verify compile version and runtime
|
||||
/// version does match. It can be done with the
|
||||
/// `FanotifyEvent::check_version` method.
|
||||
pub fn version(&self) -> u8 {
|
||||
self.0.vers
|
||||
}
|
||||
|
||||
/// Checks that compile fanotify API version is equal to the version of the
|
||||
/// event.
|
||||
pub fn check_version(&self) -> bool {
|
||||
self.version() == FANOTIFY_METADATA_VERSION
|
||||
}
|
||||
|
||||
/// Mask flags of the events.
|
||||
pub fn mask(&self) -> MaskFlags {
|
||||
MaskFlags::from_bits_truncate(self.0.mask)
|
||||
}
|
||||
|
||||
/// The file descriptor of the event. If the value is `None` when reading
|
||||
/// from the fanotify group, this event is to notify that a group queue
|
||||
/// overflow occured.
|
||||
pub fn fd(&self) -> Option<BorrowedFd> {
|
||||
if self.0.fd == libc::FAN_NOFD {
|
||||
None
|
||||
} else {
|
||||
// SAFETY: self.0.fd will be opened for the lifetime of `Self`,
|
||||
// which is longer than the lifetime of the returned BorrowedFd, so
|
||||
// it is safe.
|
||||
Some(unsafe { BorrowedFd::borrow_raw(self.0.fd) })
|
||||
}
|
||||
}
|
||||
|
||||
/// PID of the process that caused the event. TID in case flag
|
||||
/// `FAN_REPORT_TID` was set at group initialization.
|
||||
pub fn pid(&self) -> i32 {
|
||||
self.0.pid
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for FanotifyEvent {
|
||||
fn drop(&mut self) {
|
||||
if self.0.fd == libc::FAN_NOFD {
|
||||
return;
|
||||
}
|
||||
let e = close(self.0.fd);
|
||||
if !std::thread::panicking() && e == Err(Errno::EBADF) {
|
||||
panic!("Closing an invalid file descriptor!");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Abstraction over the structure to be sent to allow or deny a given event.
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct FanotifyResponse<'a> {
|
||||
inner: libc::fanotify_response,
|
||||
_borrowed_fd: PhantomData<BorrowedFd<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> FanotifyResponse<'a> {
|
||||
/// Create a new response.
|
||||
pub fn new(fd: BorrowedFd<'a>, response: Response) -> Self {
|
||||
Self {
|
||||
inner: libc::fanotify_response {
|
||||
fd: fd.as_raw_fd(),
|
||||
response: response.bits(),
|
||||
},
|
||||
_borrowed_fd: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
libc_bitflags! {
|
||||
/// Response to be wrapped in [`FanotifyResponse`] and sent to the [`Fanotify`]
|
||||
/// group to allow or deny an event.
|
||||
pub struct Response: u32 {
|
||||
/// Allow the event.
|
||||
FAN_ALLOW;
|
||||
/// Deny the event.
|
||||
FAN_DENY;
|
||||
}
|
||||
}
|
||||
|
||||
/// A fanotify group. This is also a file descriptor that can feed to other
|
||||
/// interfaces consuming file descriptors.
|
||||
#[derive(Debug)]
|
||||
pub struct Fanotify {
|
||||
fd: OwnedFd,
|
||||
}
|
||||
|
||||
impl Fanotify {
|
||||
/// Initialize a new fanotify group.
|
||||
///
|
||||
/// Returns a Result containing a Fanotify instance.
|
||||
///
|
||||
/// For more information, see [fanotify_init(2)](https://man7.org/linux/man-pages/man7/fanotify_init.2.html).
|
||||
pub fn init(
|
||||
flags: InitFlags,
|
||||
event_f_flags: EventFFlags,
|
||||
) -> Result<Fanotify> {
|
||||
let res = Errno::result(unsafe {
|
||||
libc::fanotify_init(flags.bits(), event_f_flags.bits())
|
||||
});
|
||||
res.map(|fd| Fanotify {
|
||||
fd: unsafe { OwnedFd::from_raw_fd(fd) },
|
||||
})
|
||||
}
|
||||
|
||||
/// Add, remove, or modify an fanotify mark on a filesystem object.
|
||||
///
|
||||
/// Returns a Result containing either `()` on success or errno otherwise.
|
||||
///
|
||||
/// For more information, see [fanotify_mark(2)](https://man7.org/linux/man-pages/man7/fanotify_mark.2.html).
|
||||
pub fn mark<Fd: std::os::fd::AsFd, P: ?Sized + NixPath>(
|
||||
&self,
|
||||
flags: MarkFlags,
|
||||
mask: MaskFlags,
|
||||
dirfd: Fd,
|
||||
path: Option<&P>,
|
||||
) -> Result<()> {
|
||||
let res = crate::with_opt_nix_path(path, |p| unsafe {
|
||||
libc::fanotify_mark(
|
||||
self.fd.as_raw_fd(),
|
||||
flags.bits(),
|
||||
mask.bits(),
|
||||
dirfd.as_fd().as_raw_fd(),
|
||||
p,
|
||||
)
|
||||
})?;
|
||||
|
||||
Errno::result(res).map(|_| ())
|
||||
}
|
||||
|
||||
/// Read incoming events from the fanotify group.
|
||||
///
|
||||
/// Returns a Result containing either a `Vec` of events on success or errno
|
||||
/// otherwise.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Possible errors can be those that are explicitly listed in
|
||||
/// [fanotify(2)](https://man7.org/linux/man-pages/man7/fanotify.2.html) in
|
||||
/// addition to the possible errors caused by `read` call.
|
||||
/// In particular, `EAGAIN` is returned when no event is available on a
|
||||
/// group that has been initialized with the flag `InitFlags::FAN_NONBLOCK`,
|
||||
/// thus making this method nonblocking.
|
||||
pub fn read_events(&self) -> Result<Vec<FanotifyEvent>> {
|
||||
let metadata_size = size_of::<libc::fanotify_event_metadata>();
|
||||
const BUFSIZ: usize = 4096;
|
||||
let mut buffer = [0u8; BUFSIZ];
|
||||
let mut events = Vec::new();
|
||||
let mut offset = 0;
|
||||
|
||||
let nread = read(&self.fd, &mut buffer)?;
|
||||
|
||||
while (nread - offset) >= metadata_size {
|
||||
let metadata = unsafe {
|
||||
let mut metadata =
|
||||
MaybeUninit::<libc::fanotify_event_metadata>::uninit();
|
||||
ptr::copy_nonoverlapping(
|
||||
buffer.as_ptr().add(offset),
|
||||
metadata.as_mut_ptr().cast(),
|
||||
(BUFSIZ - offset).min(metadata_size),
|
||||
);
|
||||
metadata.assume_init()
|
||||
};
|
||||
|
||||
events.push(FanotifyEvent(metadata));
|
||||
offset += metadata.event_len as usize;
|
||||
}
|
||||
|
||||
Ok(events)
|
||||
}
|
||||
|
||||
/// Write an event response on the fanotify group.
|
||||
///
|
||||
/// Returns a Result containing either `()` on success or errno otherwise.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Possible errors can be those that are explicitly listed in
|
||||
/// [fanotify(2)](https://man7.org/linux/man-pages/man7/fanotify.2.html) in
|
||||
/// addition to the possible errors caused by `write` call.
|
||||
/// In particular, `EAGAIN` or `EWOULDBLOCK` is returned when no event is
|
||||
/// available on a group that has been initialized with the flag
|
||||
/// `InitFlags::FAN_NONBLOCK`, thus making this method nonblocking.
|
||||
pub fn write_response(&self, response: FanotifyResponse) -> Result<()> {
|
||||
write(self.fd.as_fd(), unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
(&response.inner as *const libc::fanotify_response).cast(),
|
||||
size_of::<libc::fanotify_response>(),
|
||||
)
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for Fanotify {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||
Fanotify {
|
||||
fd: unsafe { OwnedFd::from_raw_fd(fd) },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsFd for Fanotify {
|
||||
fn as_fd(&'_ self) -> BorrowedFd<'_> {
|
||||
self.fd.as_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Fanotify {
|
||||
fn as_raw_fd(&self) -> RawFd
|
||||
{
|
||||
self.fd.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Fanotify> for OwnedFd {
|
||||
fn from(value: Fanotify) -> Self {
|
||||
value.fd
|
||||
}
|
||||
}
|
||||
|
||||
impl Fanotify {
|
||||
/// Constructs a `Fanotify` wrapping an existing `OwnedFd`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `OwnedFd` is a valid `Fanotify`.
|
||||
pub unsafe fn from_owned_fd(fd: OwnedFd) -> Self {
|
||||
Self {
|
||||
fd
|
||||
}
|
||||
}
|
||||
}
|
||||
+41
-16
@@ -32,7 +32,7 @@ use libc::{c_char, c_int};
|
||||
use std::ffi::{CStr, OsStr, OsString};
|
||||
use std::mem::{size_of, MaybeUninit};
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd};
|
||||
use std::ptr;
|
||||
|
||||
libc_bitflags! {
|
||||
@@ -101,9 +101,9 @@ libc_bitflags! {
|
||||
|
||||
/// An inotify instance. This is also a file descriptor, you can feed it to
|
||||
/// other interfaces consuming file descriptors, epoll for example.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug)]
|
||||
pub struct Inotify {
|
||||
fd: RawFd,
|
||||
fd: OwnedFd,
|
||||
}
|
||||
|
||||
/// This object is returned when you create a new watch on an inotify instance.
|
||||
@@ -143,7 +143,9 @@ impl Inotify {
|
||||
pub fn init(flags: InitFlags) -> Result<Inotify> {
|
||||
let res = Errno::result(unsafe { libc::inotify_init1(flags.bits()) });
|
||||
|
||||
res.map(|fd| Inotify { fd })
|
||||
res.map(|fd| Inotify {
|
||||
fd: unsafe { OwnedFd::from_raw_fd(fd) },
|
||||
})
|
||||
}
|
||||
|
||||
/// Adds a new watch on the target file or directory.
|
||||
@@ -152,12 +154,16 @@ impl Inotify {
|
||||
///
|
||||
/// For more information see, [inotify_add_watch(2)](https://man7.org/linux/man-pages/man2/inotify_add_watch.2.html).
|
||||
pub fn add_watch<P: ?Sized + NixPath>(
|
||||
self,
|
||||
&self,
|
||||
path: &P,
|
||||
mask: AddWatchFlags,
|
||||
) -> Result<WatchDescriptor> {
|
||||
let res = path.with_nix_path(|cstr| unsafe {
|
||||
libc::inotify_add_watch(self.fd, cstr.as_ptr(), mask.bits())
|
||||
libc::inotify_add_watch(
|
||||
self.fd.as_raw_fd(),
|
||||
cstr.as_ptr(),
|
||||
mask.bits(),
|
||||
)
|
||||
})?;
|
||||
|
||||
Errno::result(res).map(|wd| WatchDescriptor { wd })
|
||||
@@ -169,7 +175,7 @@ impl Inotify {
|
||||
/// Returns an EINVAL error if the watch descriptor is invalid.
|
||||
///
|
||||
/// For more information see, [inotify_rm_watch(2)](https://man7.org/linux/man-pages/man2/inotify_rm_watch.2.html).
|
||||
pub fn rm_watch(self, wd: WatchDescriptor) -> Result<()> {
|
||||
pub fn rm_watch(&self, wd: WatchDescriptor) -> Result<()> {
|
||||
cfg_if! {
|
||||
if #[cfg(target_os = "linux")] {
|
||||
let arg = wd.wd;
|
||||
@@ -177,7 +183,7 @@ impl Inotify {
|
||||
let arg = wd.wd as u32;
|
||||
}
|
||||
}
|
||||
let res = unsafe { libc::inotify_rm_watch(self.fd, arg) };
|
||||
let res = unsafe { libc::inotify_rm_watch(self.fd.as_raw_fd(), arg) };
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
@@ -188,21 +194,21 @@ impl Inotify {
|
||||
///
|
||||
/// Returns as many events as available. If the call was non blocking and no
|
||||
/// events could be read then the EAGAIN error is returned.
|
||||
pub fn read_events(self) -> Result<Vec<InotifyEvent>> {
|
||||
pub fn read_events(&self) -> Result<Vec<InotifyEvent>> {
|
||||
let header_size = size_of::<libc::inotify_event>();
|
||||
const BUFSIZ: usize = 4096;
|
||||
let mut buffer = [0u8; BUFSIZ];
|
||||
let mut events = Vec::new();
|
||||
let mut offset = 0;
|
||||
|
||||
let nread = read(self.fd, &mut buffer)?;
|
||||
let nread = read(&self.fd, &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,
|
||||
event.as_mut_ptr().cast(),
|
||||
(BUFSIZ - offset).min(header_size),
|
||||
);
|
||||
event.assume_init()
|
||||
@@ -233,16 +239,35 @@ impl Inotify {
|
||||
|
||||
Ok(events)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Inotify {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.fd
|
||||
/// Constructs an `Inotify` wrapping an existing `OwnedFd`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `OwnedFd` is a valid `Inotify`.
|
||||
pub unsafe fn from_owned_fd(fd: OwnedFd) -> Self {
|
||||
Self {
|
||||
fd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for Inotify {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||
Inotify { fd }
|
||||
Inotify {
|
||||
fd: unsafe { OwnedFd::from_raw_fd(fd) },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsFd for Inotify {
|
||||
fn as_fd(&'_ self) -> BorrowedFd<'_> {
|
||||
self.fd.as_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Inotify> for OwnedFd {
|
||||
fn from(value: Inotify) -> Self {
|
||||
value.fd
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
/// The datatype used for the ioctl number
|
||||
#[doc(hidden)]
|
||||
#[cfg(not(target_os = "illumos"))]
|
||||
#[cfg(not(solarish))]
|
||||
pub type ioctl_num_type = ::libc::c_ulong;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[cfg(target_os = "illumos")]
|
||||
#[cfg(solarish)]
|
||||
pub type ioctl_num_type = ::libc::c_int;
|
||||
|
||||
/// The datatype used for the 3rd argument
|
||||
|
||||
+51
-44
@@ -1,8 +1,20 @@
|
||||
use cfg_if::cfg_if;
|
||||
|
||||
/// The datatype used for the ioctl number
|
||||
#[cfg(any(target_os = "android", target_env = "musl", target_env = "ohos"))]
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "fuchsia",
|
||||
target_env = "musl",
|
||||
target_env = "ohos"
|
||||
))]
|
||||
#[doc(hidden)]
|
||||
pub type ioctl_num_type = ::libc::c_int;
|
||||
#[cfg(not(any(target_os = "android", target_env = "musl", target_env = "ohos")))]
|
||||
#[cfg(not(any(
|
||||
target_os = "android",
|
||||
target_os = "fuchsia",
|
||||
target_env = "musl",
|
||||
target_env = "ohos"
|
||||
)))]
|
||||
#[doc(hidden)]
|
||||
pub type ioctl_num_type = ::libc::c_ulong;
|
||||
/// The datatype used for the 3rd argument
|
||||
@@ -14,48 +26,43 @@ pub const NRBITS: ioctl_num_type = 8;
|
||||
#[doc(hidden)]
|
||||
pub const TYPEBITS: ioctl_num_type = 8;
|
||||
|
||||
#[cfg(any(
|
||||
target_arch = "mips",
|
||||
target_arch = "mips64",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64",
|
||||
target_arch = "sparc64"
|
||||
))]
|
||||
mod consts {
|
||||
#[doc(hidden)]
|
||||
pub const NONE: u8 = 1;
|
||||
#[doc(hidden)]
|
||||
pub const READ: u8 = 2;
|
||||
#[doc(hidden)]
|
||||
pub const WRITE: u8 = 4;
|
||||
#[doc(hidden)]
|
||||
pub const SIZEBITS: u8 = 13;
|
||||
#[doc(hidden)]
|
||||
pub const DIRBITS: u8 = 3;
|
||||
}
|
||||
|
||||
// "Generic" ioctl protocol
|
||||
#[cfg(any(
|
||||
target_arch = "x86",
|
||||
target_arch = "arm",
|
||||
target_arch = "s390x",
|
||||
target_arch = "x86_64",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "riscv32",
|
||||
target_arch = "riscv64",
|
||||
target_arch = "loongarch64"
|
||||
))]
|
||||
mod consts {
|
||||
#[doc(hidden)]
|
||||
pub const NONE: u8 = 0;
|
||||
#[doc(hidden)]
|
||||
pub const READ: u8 = 2;
|
||||
#[doc(hidden)]
|
||||
pub const WRITE: u8 = 1;
|
||||
#[doc(hidden)]
|
||||
pub const SIZEBITS: u8 = 14;
|
||||
#[doc(hidden)]
|
||||
pub const DIRBITS: u8 = 2;
|
||||
cfg_if! {
|
||||
if #[cfg(any(
|
||||
target_arch = "mips",
|
||||
target_arch = "mips32r6",
|
||||
target_arch = "mips64",
|
||||
target_arch = "mips64r6",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64",
|
||||
target_arch = "sparc64"
|
||||
))] {
|
||||
mod consts {
|
||||
#[doc(hidden)]
|
||||
pub const NONE: u8 = 1;
|
||||
#[doc(hidden)]
|
||||
pub const READ: u8 = 2;
|
||||
#[doc(hidden)]
|
||||
pub const WRITE: u8 = 4;
|
||||
#[doc(hidden)]
|
||||
pub const SIZEBITS: u8 = 13;
|
||||
#[doc(hidden)]
|
||||
pub const DIRBITS: u8 = 3;
|
||||
}
|
||||
} else {
|
||||
// "Generic" ioctl protocol
|
||||
mod consts {
|
||||
#[doc(hidden)]
|
||||
pub const NONE: u8 = 0;
|
||||
#[doc(hidden)]
|
||||
pub const READ: u8 = 2;
|
||||
#[doc(hidden)]
|
||||
pub const WRITE: u8 = 1;
|
||||
#[doc(hidden)]
|
||||
pub const SIZEBITS: u8 = 14;
|
||||
#[doc(hidden)]
|
||||
pub const DIRBITS: u8 = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub use self::consts::*;
|
||||
|
||||
+63
-51
@@ -72,7 +72,7 @@
|
||||
//! # const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
|
||||
//! # const SPI_IOC_TYPE_MODE: u8 = 1;
|
||||
//! pub unsafe fn spi_read_mode(fd: c_int, data: *mut u8) -> Result<c_int> {
|
||||
//! let res = libc::ioctl(fd, request_code_read!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, mem::size_of::<u8>()), data);
|
||||
//! let res = unsafe { libc::ioctl(fd, request_code_read!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, mem::size_of::<u8>()), data) };
|
||||
//! Errno::result(res)
|
||||
//! }
|
||||
//! # fn main() {}
|
||||
@@ -121,11 +121,11 @@
|
||||
//!
|
||||
//! ```
|
||||
//! # #[macro_use] extern crate nix;
|
||||
//! # #[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
//! # #[cfg(linux_android)]
|
||||
//! # use nix::libc::TCGETS as TCGETS;
|
||||
//! # #[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
//! # #[cfg(linux_android)]
|
||||
//! # use nix::libc::termios as termios;
|
||||
//! # #[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
//! # #[cfg(linux_android)]
|
||||
//! ioctl_read_bad!(tcgets, TCGETS, termios);
|
||||
//! # fn main() {}
|
||||
//! ```
|
||||
@@ -179,9 +179,13 @@
|
||||
//! # const SPI_IOC_TYPE_MESSAGE: u8 = 0;
|
||||
//! # pub struct spi_ioc_transfer(u64);
|
||||
//! pub unsafe fn spi_message(fd: c_int, data: &mut [spi_ioc_transfer]) -> Result<c_int> {
|
||||
//! let res = libc::ioctl(fd,
|
||||
//! request_code_write!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, data.len() * mem::size_of::<spi_ioc_transfer>()),
|
||||
//! data);
|
||||
//! let res = unsafe {
|
||||
//! libc::ioctl(
|
||||
//! fd,
|
||||
//! request_code_write!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, data.len() * mem::size_of::<spi_ioc_transfer>()),
|
||||
//! data
|
||||
//! )
|
||||
//! };
|
||||
//! Errno::result(res)
|
||||
//! }
|
||||
//! # fn main() {}
|
||||
@@ -223,40 +227,18 @@
|
||||
//! ```
|
||||
use cfg_if::cfg_if;
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
|
||||
#[cfg(any(linux_android, target_os = "fuchsia", target_os = "redox"))]
|
||||
#[macro_use]
|
||||
mod linux;
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "linux",
|
||||
target_os = "redox"
|
||||
))]
|
||||
#[cfg(any(linux_android, target_os = "fuchsia", target_os = "redox"))]
|
||||
pub use self::linux::*;
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "illumos",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "haiku",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
#[cfg(any(bsd, solarish, target_os = "haiku",))]
|
||||
#[macro_use]
|
||||
mod bsd;
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "illumos",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "haiku",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
#[cfg(any(bsd, solarish, target_os = "haiku",))]
|
||||
pub use self::bsd::*;
|
||||
|
||||
/// Convert raw ioctl return value to a Nix result
|
||||
@@ -305,7 +287,9 @@ macro_rules! ioctl_none {
|
||||
$(#[$attr])*
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int)
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_none!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type))
|
||||
unsafe {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_none!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -345,7 +329,9 @@ macro_rules! ioctl_none_bad {
|
||||
$(#[$attr])*
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int)
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type))
|
||||
unsafe {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -383,7 +369,9 @@ macro_rules! ioctl_read {
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int,
|
||||
data: *mut $ty)
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
unsafe {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -408,7 +396,7 @@ macro_rules! ioctl_read {
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate nix;
|
||||
/// # #[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
/// # #[cfg(linux_android)]
|
||||
/// ioctl_read_bad!(tcgets, libc::TCGETS, libc::termios);
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
@@ -419,7 +407,9 @@ macro_rules! ioctl_read_bad {
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int,
|
||||
data: *mut $ty)
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
unsafe {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -456,7 +446,9 @@ macro_rules! ioctl_write_ptr {
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int,
|
||||
data: *const $ty)
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
unsafe {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -481,7 +473,7 @@ macro_rules! ioctl_write_ptr {
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate nix;
|
||||
/// # #[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
/// # #[cfg(linux_android)]
|
||||
/// ioctl_write_ptr_bad!(tcsets, libc::TCSETS, libc::termios);
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
@@ -492,13 +484,15 @@ macro_rules! ioctl_write_ptr_bad {
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int,
|
||||
data: *const $ty)
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
unsafe {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] {
|
||||
if #[cfg(freebsdlike)] {
|
||||
/// Generates a wrapper function for a ioctl that writes an integer to the kernel.
|
||||
///
|
||||
/// The arguments to this macro are:
|
||||
@@ -533,7 +527,9 @@ cfg_if! {
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int,
|
||||
data: $crate::sys::ioctl::ioctl_param_type)
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write_int!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
unsafe {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write_int!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -574,7 +570,9 @@ cfg_if! {
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int,
|
||||
data: $crate::sys::ioctl::ioctl_param_type)
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$crate::libc::c_int>()) as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
unsafe {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$crate::libc::c_int>()) as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -600,7 +598,7 @@ cfg_if! {
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate nix;
|
||||
/// # #[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
/// # #[cfg(linux_android)]
|
||||
/// ioctl_write_int_bad!(tcsbrk, libc::TCSBRK);
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
@@ -618,7 +616,9 @@ macro_rules! ioctl_write_int_bad {
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int,
|
||||
data: $crate::libc::c_int)
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
unsafe {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -655,7 +655,11 @@ macro_rules! ioctl_readwrite {
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int,
|
||||
data: *mut $ty)
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
let ioty = $ioty;
|
||||
let nr = $nr;
|
||||
unsafe {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!(ioty, nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -683,7 +687,9 @@ macro_rules! ioctl_readwrite_bad {
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int,
|
||||
data: *mut $ty)
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
unsafe {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -712,7 +718,9 @@ macro_rules! ioctl_read_buf {
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int,
|
||||
data: &mut [$ty])
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
unsafe {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data.as_mut_ptr()))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -751,7 +759,9 @@ macro_rules! ioctl_write_buf {
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int,
|
||||
data: &[$ty])
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
unsafe {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data.as_ptr()))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -780,7 +790,9 @@ macro_rules! ioctl_readwrite_buf {
|
||||
pub unsafe fn $name(fd: $crate::libc::c_int,
|
||||
data: &mut [$ty])
|
||||
-> $crate::Result<$crate::libc::c_int> {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data))
|
||||
unsafe {
|
||||
convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data.as_mut_ptr()))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
+77
-13
@@ -1,15 +1,14 @@
|
||||
//! Interfaces for managing memory-backed files.
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::os::unix::io::{FromRawFd, OwnedFd, RawFd};
|
||||
|
||||
use crate::errno::Errno;
|
||||
use crate::Result;
|
||||
use std::ffi::CStr;
|
||||
use crate::{NixPath, Result};
|
||||
|
||||
libc_bitflags!(
|
||||
/// Options that change the behavior of [`memfd_create`].
|
||||
pub struct MemFdCreateFlag: libc::c_uint {
|
||||
pub struct MFdFlags: libc::c_uint {
|
||||
/// Set the close-on-exec ([`FD_CLOEXEC`]) flag on the new file descriptor.
|
||||
///
|
||||
/// By default, the new file descriptor is set to remain open across an [`execve`]
|
||||
@@ -29,9 +28,68 @@ libc_bitflags!(
|
||||
///
|
||||
/// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html
|
||||
MFD_ALLOW_SEALING;
|
||||
/// Anonymous file will be created using huge pages. It should be safe now to
|
||||
/// combine with [`MFD_ALLOW_SEALING`] too.
|
||||
/// However, despite its presence, on FreeBSD it is unimplemented for now (ENOSYS).
|
||||
///
|
||||
/// See also the hugetlb filesystem in [`memfd_create(2)`].
|
||||
///
|
||||
/// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html
|
||||
#[cfg(linux_android)]
|
||||
MFD_HUGETLB;
|
||||
/// Shift to get the huge page size.
|
||||
#[cfg(target_env = "ohos")]
|
||||
MFD_HUGE_SHIFT;
|
||||
/// Mask to get the huge page size.
|
||||
#[cfg(target_env = "ohos")]
|
||||
MFD_HUGE_MASK;
|
||||
/// hugetlb size of 64KB.
|
||||
#[cfg(target_env = "ohos")]
|
||||
MFD_HUGE_64KB;
|
||||
/// hugetlb size of 512KB.
|
||||
#[cfg(target_env = "ohos")]
|
||||
MFD_HUGE_512KB;
|
||||
/// Following are to be used with [`MFD_HUGETLB`], indicating the desired hugetlb size.
|
||||
///
|
||||
/// See also the hugetlb filesystem in [`memfd_create(2)`].
|
||||
///
|
||||
/// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html
|
||||
#[cfg(linux_android)]
|
||||
MFD_HUGE_1MB;
|
||||
/// hugetlb size of 2MB.
|
||||
#[cfg(linux_android)]
|
||||
MFD_HUGE_2MB;
|
||||
/// hugetlb size of 8MB.
|
||||
#[cfg(linux_android)]
|
||||
MFD_HUGE_8MB;
|
||||
/// hugetlb size of 16MB.
|
||||
#[cfg(linux_android)]
|
||||
MFD_HUGE_16MB;
|
||||
/// hugetlb size of 32MB.
|
||||
#[cfg(linux_android)]
|
||||
MFD_HUGE_32MB;
|
||||
/// hugetlb size of 256MB.
|
||||
#[cfg(linux_android)]
|
||||
MFD_HUGE_256MB;
|
||||
/// hugetlb size of 512MB.
|
||||
#[cfg(linux_android)]
|
||||
MFD_HUGE_512MB;
|
||||
/// hugetlb size of 1GB.
|
||||
#[cfg(linux_android)]
|
||||
MFD_HUGE_1GB;
|
||||
/// hugetlb size of 2GB.
|
||||
#[cfg(linux_android)]
|
||||
MFD_HUGE_2GB;
|
||||
/// hugetlb size of 16GB.
|
||||
#[cfg(linux_android)]
|
||||
MFD_HUGE_16GB;
|
||||
}
|
||||
);
|
||||
|
||||
#[deprecated(since = "0.30.0", note = "Use `MFdFlags instead`")]
|
||||
/// The deprecated MemFdCreateFlag type alias
|
||||
pub type MemFdCreateFlag = MFdFlags;
|
||||
|
||||
/// Creates an anonymous file that lives in memory, and return a file-descriptor to it.
|
||||
///
|
||||
/// The file behaves like a regular file, and so can be modified, truncated, memory-mapped, and so on.
|
||||
@@ -40,26 +98,32 @@ libc_bitflags!(
|
||||
/// For more information, see [`memfd_create(2)`].
|
||||
///
|
||||
/// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html
|
||||
pub fn memfd_create(name: &CStr, flags: MemFdCreateFlag) -> Result<RawFd> {
|
||||
let res = unsafe {
|
||||
cfg_if! {
|
||||
#[inline] // Delays codegen, preventing linker errors with dylibs and --no-allow-shlib-undefined
|
||||
pub fn memfd_create<P: NixPath + ?Sized>(
|
||||
name: &P,
|
||||
flags: MFdFlags,
|
||||
) -> Result<OwnedFd> {
|
||||
let res = name.with_nix_path(|cstr| {
|
||||
unsafe {
|
||||
cfg_if! {
|
||||
if #[cfg(all(
|
||||
// Android does not have a memfd_create symbol
|
||||
not(target_os = "android"),
|
||||
any(
|
||||
target_os = "freebsd",
|
||||
// If the OS is Linux, gnu and musl expose a memfd_create symbol but not uclibc
|
||||
// If the OS is Linux, gnu/musl/ohos expose a memfd_create symbol but not uclibc
|
||||
target_env = "gnu",
|
||||
target_env = "musl",
|
||||
target_env = "ohos",
|
||||
target_env = "ohos"
|
||||
)))]
|
||||
{
|
||||
libc::memfd_create(name.as_ptr(), flags.bits())
|
||||
libc::memfd_create(cstr.as_ptr(), flags.bits())
|
||||
} else {
|
||||
libc::syscall(libc::SYS_memfd_create, name.as_ptr(), flags.bits())
|
||||
libc::syscall(libc::SYS_memfd_create, cstr.as_ptr(), flags.bits())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
})?;
|
||||
|
||||
Errno::result(res).map(|r| r as RawFd)
|
||||
Errno::result(res).map(|r| unsafe { OwnedFd::from_raw_fd(r as RawFd) })
|
||||
}
|
||||
|
||||
+226
-158
@@ -1,14 +1,18 @@
|
||||
//! Memory management declarations.
|
||||
|
||||
use crate::errno::Errno;
|
||||
#[cfg(not(any(target_os = "android", target_env = "ohos")))]
|
||||
#[cfg(not(target_os = "android"))]
|
||||
use crate::NixPath;
|
||||
use crate::Result;
|
||||
#[cfg(not(any(target_os = "android", target_env = "ohos")))]
|
||||
#[cfg(not(target_os = "android"))]
|
||||
#[cfg(feature = "fs")]
|
||||
use crate::{fcntl::OFlag, sys::stat::Mode};
|
||||
use libc::{self, c_int, c_void, off_t, size_t};
|
||||
use std::{os::unix::io::RawFd, num::NonZeroUsize};
|
||||
use std::ptr::NonNull;
|
||||
use std::{
|
||||
num::NonZeroUsize,
|
||||
os::unix::io::{AsFd, AsRawFd},
|
||||
};
|
||||
|
||||
libc_bitflags! {
|
||||
/// Desired memory protection of a memory mapping.
|
||||
@@ -22,12 +26,10 @@ libc_bitflags! {
|
||||
/// Pages can be executed
|
||||
PROT_EXEC;
|
||||
/// Apply protection up to the end of a mapping that grows upwards.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
PROT_GROWSDOWN;
|
||||
/// Apply protection down to the beginning of a mapping that grows downwards.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
PROT_GROWSUP;
|
||||
}
|
||||
}
|
||||
@@ -36,154 +38,161 @@ libc_bitflags! {
|
||||
/// Additional parameters for [`mmap`].
|
||||
pub struct MapFlags: c_int {
|
||||
/// Compatibility flag. Ignored.
|
||||
#[cfg(not(any(target_os = "solaris", target_os = "redox")))]
|
||||
MAP_FILE;
|
||||
/// Share this mapping. Mutually exclusive with `MAP_PRIVATE`.
|
||||
MAP_SHARED;
|
||||
/// Force mmap to check and fail on unknown flags. This also enables `MAP_SYNC`.
|
||||
#[cfg(target_os = "linux")]
|
||||
MAP_SHARED_VALIDATE;
|
||||
/// 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;
|
||||
/// Place the mapping at exactly the address specified in `addr`, but never clobber an existing range.
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MAP_FIXED_NOREPLACE;
|
||||
/// To be used with `MAP_FIXED`, to forbid the system
|
||||
/// to select a different address than the one specified.
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MAP_EXCL;
|
||||
/// Synonym for `MAP_ANONYMOUS`.
|
||||
MAP_ANON;
|
||||
/// The mapping is not backed by any file.
|
||||
MAP_ANONYMOUS;
|
||||
/// Put the mapping into the first 2GB of the process address space.
|
||||
#[cfg(any(all(any(target_os = "android", target_os = "linux"),
|
||||
#[cfg(any(all(linux_android,
|
||||
any(target_arch = "x86", target_arch = "x86_64")),
|
||||
all(target_os = "linux", any(target_env = "musl", target_env = "ohos"), 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 = "linux", target_env = "ohos", target_arch = "x86_64"),
|
||||
all(target_os = "freebsd", target_pointer_width = "64")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MAP_32BIT;
|
||||
/// Used for stacks; indicates to the kernel that the mapping should extend downward in memory.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
MAP_GROWSDOWN;
|
||||
/// Compatibility flag. Ignored.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
MAP_DENYWRITE;
|
||||
/// Compatibility flag. Ignored.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
MAP_EXECUTABLE;
|
||||
/// Mark the mmaped region to be locked in the same way as `mlock(2)`.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
MAP_LOCKED;
|
||||
/// Do not reserve swap space for this mapping.
|
||||
///
|
||||
/// This was removed in FreeBSD 11 and is unused in DragonFlyBSD.
|
||||
#[cfg(not(any(target_os = "dragonfly", target_os = "freebsd")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(not(any(freebsdlike, target_os = "aix", target_os = "hurd", target_os = "redox")))]
|
||||
MAP_NORESERVE;
|
||||
/// Populate page tables for a mapping.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
MAP_POPULATE;
|
||||
/// Only meaningful when used with `MAP_POPULATE`. Don't perform read-ahead.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
MAP_NONBLOCK;
|
||||
/// Allocate the mapping using "huge pages."
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
MAP_HUGETLB;
|
||||
/// Make use of 64KB huge page (must be supported by the system)
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MAP_HUGE_64KB;
|
||||
/// Make use of 512KB huge page (must be supported by the system)
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MAP_HUGE_512KB;
|
||||
/// Make use of 1MB huge page (must be supported by the system)
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MAP_HUGE_1MB;
|
||||
/// Make use of 2MB huge page (must be supported by the system)
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MAP_HUGE_2MB;
|
||||
/// Make use of 8MB huge page (must be supported by the system)
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MAP_HUGE_8MB;
|
||||
/// Make use of 16MB huge page (must be supported by the system)
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MAP_HUGE_16MB;
|
||||
/// Make use of 32MB huge page (must be supported by the system)
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MAP_HUGE_32MB;
|
||||
/// Make use of 256MB huge page (must be supported by the system)
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MAP_HUGE_256MB;
|
||||
/// Make use of 512MB huge page (must be supported by the system)
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MAP_HUGE_512MB;
|
||||
/// Make use of 1GB huge page (must be supported by the system)
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MAP_HUGE_1GB;
|
||||
/// Make use of 2GB huge page (must be supported by the system)
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MAP_HUGE_2GB;
|
||||
/// Make use of 16GB huge page (must be supported by the system)
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MAP_HUGE_16GB;
|
||||
|
||||
/// Lock the mapped region into memory as with `mlock(2)`.
|
||||
#[cfg(target_os = "netbsd")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MAP_WIRED;
|
||||
/// Causes dirtied data in the specified range to be flushed to disk only when necessary.
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
MAP_NOSYNC;
|
||||
/// Rename private pages to a file.
|
||||
///
|
||||
/// This was removed in FreeBSD 11 and is unused in DragonFlyBSD.
|
||||
#[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(netbsdlike)]
|
||||
MAP_RENAME;
|
||||
/// Region may contain semaphores.
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(freebsdlike, netbsdlike))]
|
||||
MAP_HASSEMAPHORE;
|
||||
/// Region grows down, like a stack.
|
||||
#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux", target_os = "openbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(linux_android, freebsdlike, netbsdlike))]
|
||||
MAP_STACK;
|
||||
/// Do not write through the page caches, write directly to the file. Used for Direct Access (DAX) enabled file systems.
|
||||
// Available on Linux glibc and musl, MIPS* target excluded.
|
||||
#[cfg(all(target_os = "linux", not(any(target_arch = "mips", target_arch = "mips64", target_arch = "mips32r6", target_arch = "mips64r6")), not(target_env = "uclibc")))]
|
||||
MAP_SYNC;
|
||||
/// Pages in this mapping are not retained in the kernel's memory cache.
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(apple_targets)]
|
||||
MAP_NOCACHE;
|
||||
/// Allows the W/X bit on the page, it's necessary on aarch64 architecture.
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(apple_targets)]
|
||||
MAP_JIT;
|
||||
/// Allows to use large pages, underlying alignment based on size.
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MAP_ALIGNED_SUPER;
|
||||
/// Pages will be discarded in the core dumps.
|
||||
#[cfg(target_os = "openbsd")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MAP_CONCEAL;
|
||||
/// Attempt to place the mapping at exactly the address specified in `addr`.
|
||||
/// it's a default behavior on OpenBSD.
|
||||
#[cfg(netbsdlike)]
|
||||
MAP_TRYFIXED;
|
||||
}
|
||||
}
|
||||
|
||||
impl MapFlags {
|
||||
/// Create `MAP_HUGETLB` with provided size of huge page.
|
||||
///
|
||||
/// Under the hood it computes `MAP_HUGETLB | (huge_page_size_log2 << libc::MAP_HUGE_SHIFT`).
|
||||
/// `huge_page_size_log2` denotes logarithm of huge page size to use and should be
|
||||
/// between 16 and 63 (inclusively).
|
||||
///
|
||||
/// ```
|
||||
/// # use nix::sys::mman::MapFlags;
|
||||
/// let f = MapFlags::map_hugetlb_with_size_log2(30).unwrap();
|
||||
/// assert_eq!(f, MapFlags::MAP_HUGETLB | MapFlags::MAP_HUGE_1GB);
|
||||
/// ```
|
||||
#[cfg(any(linux_android, target_os = "fuchsia"))]
|
||||
pub fn map_hugetlb_with_size_log2(
|
||||
huge_page_size_log2: u32,
|
||||
) -> Option<Self> {
|
||||
if (16..=63).contains(&huge_page_size_log2) {
|
||||
let flag = libc::MAP_HUGETLB
|
||||
| (huge_page_size_log2 << libc::MAP_HUGE_SHIFT) as i32;
|
||||
Some(Self(flag.into()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,19 +202,19 @@ libc_bitflags! {
|
||||
pub struct MRemapFlags: c_int {
|
||||
/// Permit the kernel to relocate the mapping to a new virtual address, if necessary.
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MREMAP_MAYMOVE;
|
||||
/// Place the mapping at exactly the address specified in `new_address`.
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MREMAP_FIXED;
|
||||
/// Works in conjunction with `MREMAP_MAYMOVE` but does not unmap `old_address`.
|
||||
/// Note that, in this case, `old_size` and `new_size` must be the same.
|
||||
#[cfg(target_os = "linux")]
|
||||
MREMAP_DONTUNMAP;
|
||||
/// Place the mapping at exactly the address specified in `new_address`.
|
||||
#[cfg(target_os = "netbsd")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MAP_FIXED;
|
||||
/// Allows to duplicate the mapping to be able to apply different flags on the copy.
|
||||
#[cfg(target_os = "netbsd")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MAP_REMAPDUP;
|
||||
}
|
||||
}
|
||||
@@ -228,30 +237,24 @@ libc_enum! {
|
||||
/// Do not expect access in the near future.
|
||||
MADV_DONTNEED,
|
||||
/// Free up a given range of pages and its associated backing store.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
MADV_REMOVE,
|
||||
/// Do not make pages in this range available to the child after a `fork(2)`.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
MADV_DONTFORK,
|
||||
/// Undo the effect of `MADV_DONTFORK`.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
MADV_DOFORK,
|
||||
/// Poison the given pages.
|
||||
///
|
||||
/// Subsequent references to those pages are treated like hardware memory corruption.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
MADV_HWPOISON,
|
||||
/// Enable Kernel Samepage Merging (KSM) for the given pages.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
MADV_MERGEABLE,
|
||||
/// Undo the effect of `MADV_MERGEABLE`
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
MADV_UNMERGEABLE,
|
||||
/// Preserve the memory of each page but offline the original page.
|
||||
#[cfg(any(target_os = "android",
|
||||
@@ -266,68 +269,73 @@ libc_enum! {
|
||||
target_arch = "sparc64"))))]
|
||||
MADV_SOFT_OFFLINE,
|
||||
/// Enable Transparent Huge Pages (THP) for pages in the given range.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
MADV_HUGEPAGE,
|
||||
/// Undo the effect of `MADV_HUGEPAGE`.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
MADV_NOHUGEPAGE,
|
||||
/// Exclude the given range from a core dump.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
MADV_DONTDUMP,
|
||||
/// Undo the effect of an earlier `MADV_DONTDUMP`.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
MADV_DODUMP,
|
||||
/// Specify that the application no longer needs the pages in the given range.
|
||||
#[cfg(not(any(target_os = "aix", target_os = "hurd", target_os = "cygwin", target_os = "redox")))]
|
||||
MADV_FREE,
|
||||
/// Request that the system not flush the current range to disk unless it needs to.
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
MADV_NOSYNC,
|
||||
/// Undoes the effects of `MADV_NOSYNC` for any future pages dirtied within the given range.
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
MADV_AUTOSYNC,
|
||||
/// Region is not included in a core file.
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
MADV_NOCORE,
|
||||
/// Include region in a core file
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
MADV_CORE,
|
||||
/// This process should not be killed when swap space is exhausted.
|
||||
#[cfg(any(target_os = "freebsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MADV_PROTECT,
|
||||
/// Invalidate the hardware page table for the given region.
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MADV_INVAL,
|
||||
/// Set the offset of the page directory page to `value` for the virtual page table.
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
MADV_SETMAP,
|
||||
/// Indicates that the application will not need the data in the given range.
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(apple_targets)]
|
||||
MADV_ZERO_WIRED_PAGES,
|
||||
/// Pages can be reused (by anyone).
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(apple_targets)]
|
||||
MADV_FREE_REUSABLE,
|
||||
/// Caller wants to reuse those pages.
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(apple_targets)]
|
||||
MADV_FREE_REUSE,
|
||||
// Darwin doesn't document this flag's behavior.
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(apple_targets)]
|
||||
#[allow(missing_docs)]
|
||||
MADV_CAN_REUSE,
|
||||
/// Reclaim the address range when applicable.
|
||||
#[cfg(linux_android)]
|
||||
MADV_PAGEOUT,
|
||||
/// Deactivate the address range when applicable.
|
||||
#[cfg(linux_android)]
|
||||
MADV_COLD,
|
||||
/// After fork, the adress range is zero filled.
|
||||
#[cfg(linux_android)]
|
||||
MADV_WIPEONFORK,
|
||||
/// Undo `MADV_WIPEONFORK` when it applied.
|
||||
#[cfg(linux_android)]
|
||||
MADV_KEEPONFORK,
|
||||
/// Pre-load the address range for reading to reduce page-fault latency.
|
||||
#[cfg(linux_android)]
|
||||
MADV_POPULATE_READ,
|
||||
/// Pre-fault the address range for writing to reduce page-fault
|
||||
/// latency on subsequent writes.
|
||||
#[cfg(linux_android)]
|
||||
MADV_POPULATE_WRITE,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,19 +347,17 @@ libc_bitflags! {
|
||||
/// Invalidate all cached data.
|
||||
MS_INVALIDATE;
|
||||
/// Invalidate pages, but leave them mapped.
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(apple_targets)]
|
||||
MS_KILLPAGES;
|
||||
/// Deactivate pages, but leave them mapped.
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(apple_targets)]
|
||||
MS_DEACTIVATE;
|
||||
/// Perform an update and wait for it to complete.
|
||||
MS_SYNC;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "haiku"))]
|
||||
#[cfg(not(any(target_os = "haiku", target_os = "cygwin", target_os = "redox")))]
|
||||
libc_bitflags! {
|
||||
/// Flags for [`mlockall`].
|
||||
pub struct MlockAllFlags: c_int {
|
||||
@@ -372,8 +378,8 @@ libc_bitflags! {
|
||||
/// `addr` must meet all the requirements described in the [`mlock(2)`] man page.
|
||||
///
|
||||
/// [`mlock(2)`]: https://man7.org/linux/man-pages/man2/mlock.2.html
|
||||
pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> {
|
||||
Errno::result(libc::mlock(addr, length)).map(drop)
|
||||
pub unsafe fn mlock(addr: NonNull<c_void>, length: size_t) -> Result<()> {
|
||||
unsafe { Errno::result(libc::mlock(addr.as_ptr(), length)).map(drop) }
|
||||
}
|
||||
|
||||
/// Unlocks all memory pages that contain part of the address range with
|
||||
@@ -385,8 +391,8 @@ pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> {
|
||||
/// page.
|
||||
///
|
||||
/// [`munlock(2)`]: https://man7.org/linux/man-pages/man2/munlock.2.html
|
||||
pub unsafe fn munlock(addr: *const c_void, length: size_t) -> Result<()> {
|
||||
Errno::result(libc::munlock(addr, length)).map(drop)
|
||||
pub unsafe fn munlock(addr: NonNull<c_void>, length: size_t) -> Result<()> {
|
||||
unsafe { Errno::result(libc::munlock(addr.as_ptr(), length)).map(drop) }
|
||||
}
|
||||
|
||||
/// Locks all memory pages mapped into this process' address space.
|
||||
@@ -394,7 +400,7 @@ pub unsafe fn munlock(addr: *const c_void, length: size_t) -> Result<()> {
|
||||
/// Locked pages never move to the swap area. For more information, see [`mlockall(2)`].
|
||||
///
|
||||
/// [`mlockall(2)`]: https://man7.org/linux/man-pages/man2/mlockall.2.html
|
||||
#[cfg(not(target_os = "haiku"))]
|
||||
#[cfg(not(any(target_os = "haiku", target_os = "cygwin", target_os = "redox")))]
|
||||
pub fn mlockall(flags: MlockAllFlags) -> Result<()> {
|
||||
unsafe { Errno::result(libc::mlockall(flags.bits())) }.map(drop)
|
||||
}
|
||||
@@ -404,37 +410,73 @@ pub fn mlockall(flags: MlockAllFlags) -> Result<()> {
|
||||
/// For more information, see [`munlockall(2)`].
|
||||
///
|
||||
/// [`munlockall(2)`]: https://man7.org/linux/man-pages/man2/munlockall.2.html
|
||||
#[cfg(not(target_os = "haiku"))]
|
||||
#[cfg(not(any(target_os = "haiku", target_os = "cygwin", target_os = "redox")))]
|
||||
pub fn munlockall() -> Result<()> {
|
||||
unsafe { Errno::result(libc::munlockall()) }.map(drop)
|
||||
}
|
||||
|
||||
/// allocate memory, or map files or devices into memory
|
||||
/// Allocate memory, or map files or devices into memory
|
||||
///
|
||||
/// For anonymous mappings (`MAP_ANON`/`MAP_ANONYMOUS`), see [mmap_anonymous].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// See the [`mmap(2)`] man page for detailed requirements.
|
||||
///
|
||||
/// [`mmap(2)`]: https://man7.org/linux/man-pages/man2/mmap.2.html
|
||||
pub unsafe fn mmap(
|
||||
pub unsafe fn mmap<F: AsFd>(
|
||||
addr: Option<NonZeroUsize>,
|
||||
length: NonZeroUsize,
|
||||
prot: ProtFlags,
|
||||
flags: MapFlags,
|
||||
fd: RawFd,
|
||||
f: F,
|
||||
offset: off_t,
|
||||
) -> Result<*mut c_void> {
|
||||
let ptr = addr.map_or(
|
||||
std::ptr::null_mut(),
|
||||
|a| usize::from(a) as *mut c_void
|
||||
);
|
||||
|
||||
let ret = libc::mmap(ptr, length.into(), prot.bits(), flags.bits(), fd, offset);
|
||||
) -> Result<NonNull<c_void>> {
|
||||
let ptr = addr.map_or(std::ptr::null_mut(), |a| a.get() as *mut c_void);
|
||||
|
||||
if ret == libc::MAP_FAILED {
|
||||
let fd = f.as_fd().as_raw_fd();
|
||||
let ret = unsafe {
|
||||
libc::mmap(ptr, length.into(), prot.bits(), flags.bits(), fd, offset)
|
||||
};
|
||||
|
||||
if std::ptr::eq(ret, libc::MAP_FAILED) {
|
||||
Err(Errno::last())
|
||||
} else {
|
||||
Ok(ret)
|
||||
// SAFETY: `libc::mmap` returns a valid non-null pointer or `libc::MAP_FAILED`, thus `ret`
|
||||
// will be non-null here.
|
||||
Ok(unsafe { NonNull::new_unchecked(ret) })
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an anonymous memory mapping.
|
||||
///
|
||||
/// This function is a wrapper around [`mmap`]:
|
||||
/// `mmap(ptr, len, prot, MAP_ANONYMOUS | flags, -1, 0)`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// See the [`mmap(2)`] man page for detailed requirements.
|
||||
///
|
||||
/// [`mmap(2)`]: https://man7.org/linux/man-pages/man2/mmap.2.html
|
||||
pub unsafe fn mmap_anonymous(
|
||||
addr: Option<NonZeroUsize>,
|
||||
length: NonZeroUsize,
|
||||
prot: ProtFlags,
|
||||
flags: MapFlags,
|
||||
) -> Result<NonNull<c_void>> {
|
||||
let ptr = addr.map_or(std::ptr::null_mut(), |a| a.get() as *mut c_void);
|
||||
|
||||
let flags = MapFlags::MAP_ANONYMOUS | flags;
|
||||
let ret = unsafe {
|
||||
libc::mmap(ptr, length.into(), prot.bits(), flags.bits(), -1, 0)
|
||||
};
|
||||
|
||||
if std::ptr::eq(ret, libc::MAP_FAILED) {
|
||||
Err(Errno::last())
|
||||
} else {
|
||||
// SAFETY: `libc::mmap` returns a valid non-null pointer or `libc::MAP_FAILED`, thus `ret`
|
||||
// will be non-null here.
|
||||
Ok(unsafe { NonNull::new_unchecked(ret) })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,33 +489,43 @@ pub unsafe fn mmap(
|
||||
/// detailed requirements.
|
||||
#[cfg(any(target_os = "linux", target_os = "netbsd"))]
|
||||
pub unsafe fn mremap(
|
||||
addr: *mut c_void,
|
||||
addr: NonNull<c_void>,
|
||||
old_size: size_t,
|
||||
new_size: size_t,
|
||||
flags: MRemapFlags,
|
||||
new_address: Option<*mut c_void>,
|
||||
) -> Result<*mut c_void> {
|
||||
new_address: Option<NonNull<c_void>>,
|
||||
) -> Result<NonNull<c_void>> {
|
||||
#[cfg(target_os = "linux")]
|
||||
let ret = libc::mremap(
|
||||
addr,
|
||||
old_size,
|
||||
new_size,
|
||||
flags.bits(),
|
||||
new_address.unwrap_or(std::ptr::null_mut()),
|
||||
);
|
||||
let ret = unsafe {
|
||||
libc::mremap(
|
||||
addr.as_ptr(),
|
||||
old_size,
|
||||
new_size,
|
||||
flags.bits(),
|
||||
new_address
|
||||
.map(NonNull::as_ptr)
|
||||
.unwrap_or(std::ptr::null_mut()),
|
||||
)
|
||||
};
|
||||
#[cfg(target_os = "netbsd")]
|
||||
let ret = libc::mremap(
|
||||
addr,
|
||||
old_size,
|
||||
new_address.unwrap_or(std::ptr::null_mut()),
|
||||
new_size,
|
||||
flags.bits(),
|
||||
);
|
||||
let ret = unsafe {
|
||||
libc::mremap(
|
||||
addr.as_ptr(),
|
||||
old_size,
|
||||
new_address
|
||||
.map(NonNull::as_ptr)
|
||||
.unwrap_or(std::ptr::null_mut()),
|
||||
new_size,
|
||||
flags.bits(),
|
||||
)
|
||||
};
|
||||
|
||||
if ret == libc::MAP_FAILED {
|
||||
if std::ptr::eq(ret, libc::MAP_FAILED) {
|
||||
Err(Errno::last())
|
||||
} else {
|
||||
Ok(ret)
|
||||
// SAFETY: `libc::mremap` returns a valid non-null pointer or `libc::MAP_FAILED`, thus `ret`
|
||||
// will be non-null here.
|
||||
Ok(unsafe { NonNull::new_unchecked(ret) })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -485,8 +537,8 @@ pub unsafe fn mremap(
|
||||
/// page.
|
||||
///
|
||||
/// [`munmap(2)`]: https://man7.org/linux/man-pages/man2/munmap.2.html
|
||||
pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> {
|
||||
Errno::result(libc::munmap(addr, len)).map(drop)
|
||||
pub unsafe fn munmap(addr: NonNull<c_void>, len: size_t) -> Result<()> {
|
||||
unsafe { Errno::result(libc::munmap(addr.as_ptr(), len)).map(drop) }
|
||||
}
|
||||
|
||||
/// give advice about use of memory
|
||||
@@ -497,12 +549,16 @@ pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> {
|
||||
/// [`MmapAdvise::MADV_FREE`].
|
||||
///
|
||||
/// [`madvise(2)`]: https://man7.org/linux/man-pages/man2/madvise.2.html
|
||||
#[allow(rustdoc::broken_intra_doc_links)] // For Hurd as `MADV_FREE` is not available on it
|
||||
pub unsafe fn madvise(
|
||||
addr: *mut c_void,
|
||||
addr: NonNull<c_void>,
|
||||
length: size_t,
|
||||
advise: MmapAdvise,
|
||||
) -> Result<()> {
|
||||
Errno::result(libc::madvise(addr, length, advise as i32)).map(drop)
|
||||
unsafe {
|
||||
Errno::result(libc::madvise(addr.as_ptr(), length, advise as i32))
|
||||
.map(drop)
|
||||
}
|
||||
}
|
||||
|
||||
/// Set protection of memory mapping.
|
||||
@@ -517,26 +573,30 @@ pub unsafe fn madvise(
|
||||
///
|
||||
/// ```
|
||||
/// # use nix::libc::size_t;
|
||||
/// # use nix::sys::mman::{mmap, mprotect, MapFlags, ProtFlags};
|
||||
/// # use nix::sys::mman::{mmap_anonymous, mprotect, MapFlags, ProtFlags};
|
||||
/// # use std::ptr;
|
||||
/// # use std::os::unix::io::BorrowedFd;
|
||||
/// const ONE_K: size_t = 1024;
|
||||
/// let one_k_non_zero = std::num::NonZeroUsize::new(ONE_K).unwrap();
|
||||
/// let mut slice: &mut [u8] = unsafe {
|
||||
/// let mem = mmap(None, one_k_non_zero, ProtFlags::PROT_NONE,
|
||||
/// MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, -1, 0).unwrap();
|
||||
/// let mem = mmap_anonymous(None, one_k_non_zero, ProtFlags::PROT_NONE, MapFlags::MAP_PRIVATE)
|
||||
/// .unwrap();
|
||||
/// mprotect(mem, ONE_K, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE).unwrap();
|
||||
/// std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K)
|
||||
/// std::slice::from_raw_parts_mut(mem.as_ptr().cast(), ONE_K)
|
||||
/// };
|
||||
/// assert_eq!(slice[0], 0x00);
|
||||
/// slice[0] = 0xFF;
|
||||
/// assert_eq!(slice[0], 0xFF);
|
||||
/// ```
|
||||
pub unsafe fn mprotect(
|
||||
addr: *mut c_void,
|
||||
addr: NonNull<c_void>,
|
||||
length: size_t,
|
||||
prot: ProtFlags,
|
||||
) -> Result<()> {
|
||||
Errno::result(libc::mprotect(addr, length, prot.bits())).map(drop)
|
||||
unsafe {
|
||||
Errno::result(libc::mprotect(addr.as_ptr(), length, prot.bits()))
|
||||
.map(drop)
|
||||
}
|
||||
}
|
||||
|
||||
/// synchronize a mapped region
|
||||
@@ -548,14 +608,17 @@ pub unsafe fn mprotect(
|
||||
///
|
||||
/// [`msync(2)`]: https://man7.org/linux/man-pages/man2/msync.2.html
|
||||
pub unsafe fn msync(
|
||||
addr: *mut c_void,
|
||||
addr: NonNull<c_void>,
|
||||
length: size_t,
|
||||
flags: MsFlags,
|
||||
) -> Result<()> {
|
||||
Errno::result(libc::msync(addr, length, flags.bits())).map(drop)
|
||||
unsafe {
|
||||
Errno::result(libc::msync(addr.as_ptr(), length, flags.bits()))
|
||||
.map(drop)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_env = "ohos")))]
|
||||
#[cfg(not(target_os = "android"))]
|
||||
feature! {
|
||||
#![feature = "fs"]
|
||||
/// Creates and opens a new, or opens an existing, POSIX shared memory object.
|
||||
@@ -567,21 +630,26 @@ pub fn shm_open<P>(
|
||||
name: &P,
|
||||
flag: OFlag,
|
||||
mode: Mode
|
||||
) -> Result<RawFd>
|
||||
) -> Result<std::os::unix::io::OwnedFd>
|
||||
where P: ?Sized + NixPath
|
||||
{
|
||||
use std::os::unix::io::{FromRawFd, OwnedFd};
|
||||
|
||||
let ret = name.with_nix_path(|cstr| {
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
#[cfg(apple_targets)]
|
||||
unsafe {
|
||||
libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::c_uint)
|
||||
}
|
||||
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
|
||||
#[cfg(not(apple_targets))]
|
||||
unsafe {
|
||||
libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::mode_t)
|
||||
}
|
||||
})?;
|
||||
|
||||
Errno::result(ret)
|
||||
match ret {
|
||||
-1 => Err(Errno::last()),
|
||||
fd => Ok(unsafe{ OwnedFd::from_raw_fd(fd) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -590,7 +658,7 @@ pub fn shm_open<P>(
|
||||
/// For more information, see [`shm_unlink(3)`].
|
||||
///
|
||||
/// [`shm_unlink(3)`]: https://man7.org/linux/man-pages/man3/shm_unlink.3.html
|
||||
#[cfg(not(any(target_os = "android", target_env = "ohos")))]
|
||||
#[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()) })?;
|
||||
|
||||
+41
-60
@@ -1,10 +1,11 @@
|
||||
//! Mostly platform-specific functionality
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
all(target_os = "linux", not(target_env = "uclibc")),
|
||||
target_os = "macos",
|
||||
freebsdlike,
|
||||
all(
|
||||
target_os = "linux",
|
||||
not(any(target_env = "uclibc", target_env = "ohos"))
|
||||
),
|
||||
apple_targets,
|
||||
target_os = "netbsd"
|
||||
))]
|
||||
feature! {
|
||||
@@ -15,48 +16,42 @@ feature! {
|
||||
feature! {
|
||||
#![feature = "event"]
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub mod epoll;
|
||||
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"))]
|
||||
#[allow(missing_docs)]
|
||||
#[cfg(bsd)]
|
||||
pub mod event;
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[allow(missing_docs)]
|
||||
/// Event file descriptor.
|
||||
#[cfg(any(linux_android, target_os = "freebsd"))]
|
||||
pub mod eventfd;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
feature! {
|
||||
#![feature = "fanotify"]
|
||||
pub mod fanotify;
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
bsd,
|
||||
linux_android,
|
||||
solarish,
|
||||
target_os = "fuchsia",
|
||||
target_os = "redox",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "illumos",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
#[cfg(feature = "ioctl")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))]
|
||||
#[macro_use]
|
||||
pub mod ioctl;
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
|
||||
#[cfg(any(linux_android, target_os = "freebsd"))]
|
||||
feature! {
|
||||
#![feature = "fs"]
|
||||
pub mod memfd;
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
feature! {
|
||||
#![feature = "mman"]
|
||||
pub mod mman;
|
||||
@@ -68,20 +63,18 @@ feature! {
|
||||
pub mod personality;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
feature! {
|
||||
#![feature = "process"]
|
||||
pub mod prctl;
|
||||
}
|
||||
|
||||
feature! {
|
||||
#![feature = "pthread"]
|
||||
pub mod pthread;
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
#[cfg(any(linux_android, bsd))]
|
||||
feature! {
|
||||
#![feature = "ptrace"]
|
||||
#[allow(missing_docs)]
|
||||
@@ -94,7 +87,7 @@ feature! {
|
||||
pub mod quota;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_os = "linux", netbsdlike))]
|
||||
feature! {
|
||||
#![feature = "reboot"]
|
||||
pub mod reboot;
|
||||
@@ -103,7 +96,7 @@ feature! {
|
||||
#[cfg(not(any(
|
||||
target_os = "redox",
|
||||
target_os = "fuchsia",
|
||||
target_os = "illumos",
|
||||
solarish,
|
||||
target_os = "haiku"
|
||||
)))]
|
||||
feature! {
|
||||
@@ -111,20 +104,12 @@ feature! {
|
||||
pub mod resource;
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
feature! {
|
||||
#![feature = "poll"]
|
||||
pub mod select;
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"
|
||||
))]
|
||||
#[cfg(any(linux_android, freebsdlike, apple_targets, solarish))]
|
||||
feature! {
|
||||
#![feature = "zerocopy"]
|
||||
pub mod sendfile;
|
||||
@@ -132,14 +117,13 @@ feature! {
|
||||
|
||||
pub mod signal;
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
feature! {
|
||||
#![feature = "signal"]
|
||||
#[allow(missing_docs)]
|
||||
pub mod signalfd;
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
feature! {
|
||||
#![feature = "socket"]
|
||||
#[allow(missing_docs)]
|
||||
@@ -153,13 +137,11 @@ feature! {
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "openbsd"
|
||||
linux_android,
|
||||
freebsdlike,
|
||||
apple_targets,
|
||||
target_os = "openbsd",
|
||||
target_os = "cygwin"
|
||||
))]
|
||||
feature! {
|
||||
#![feature = "fs"]
|
||||
@@ -171,8 +153,7 @@ feature! {
|
||||
pub mod statvfs;
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub mod sysinfo;
|
||||
|
||||
@@ -200,13 +181,13 @@ feature! {
|
||||
pub mod wait;
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
feature! {
|
||||
#![feature = "inotify"]
|
||||
pub mod inotify;
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
feature! {
|
||||
#![feature = "time"]
|
||||
pub mod timerfd;
|
||||
@@ -215,7 +196,7 @@ feature! {
|
||||
#[cfg(all(
|
||||
any(
|
||||
target_os = "freebsd",
|
||||
target_os = "illumos",
|
||||
solarish,
|
||||
target_os = "linux",
|
||||
target_os = "netbsd"
|
||||
),
|
||||
|
||||
@@ -20,8 +20,7 @@ libc_bitflags! {
|
||||
/// [`mmap(2)`]: https://man7.org/linux/man-pages/man2/mmap.2.html
|
||||
ADDR_LIMIT_3GB;
|
||||
/// User-space function pointers to signal handlers point to descriptors.
|
||||
#[cfg(not(any(target_env = "musl", target_env = "ohos", target_env = "uclibc")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(not(any(target_env = "musl", target_env = "uclibc", target_env = "ohos")))]
|
||||
FDPIC_FUNCPTRS;
|
||||
/// Map page 0 as read-only.
|
||||
MMAP_PAGE_ZERO;
|
||||
@@ -42,8 +41,7 @@ libc_bitflags! {
|
||||
/// version number.
|
||||
///
|
||||
/// [`uname(2)`]: https://man7.org/linux/man-pages/man2/uname.2.html
|
||||
#[cfg(not(any(target_env = "musl", target_env = "ohos", target_env = "uclibc")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(not(any(target_env = "musl", target_env = "uclibc", target_env = "ohos")))]
|
||||
UNAME26;
|
||||
/// No effects.
|
||||
WHOLE_SECONDS;
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
//! prctl is a Linux-only API for performing operations on a process or thread.
|
||||
//!
|
||||
//! Note that careless use of some prctl() operations can confuse the user-space run-time
|
||||
//! environment, so these operations should be used with care.
|
||||
//!
|
||||
//! For more documentation, please read [prctl(2)](https://man7.org/linux/man-pages/man2/prctl.2.html).
|
||||
|
||||
use crate::errno::Errno;
|
||||
use crate::sys::signal::Signal;
|
||||
use crate::Result;
|
||||
|
||||
use libc::{c_int, c_ulong, c_void};
|
||||
use std::convert::TryFrom;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::num::NonZeroUsize;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
libc_enum! {
|
||||
/// The type of hardware memory corruption kill policy for the thread.
|
||||
|
||||
#[repr(i32)]
|
||||
#[non_exhaustive]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum PrctlMCEKillPolicy {
|
||||
/// The thread will receive SIGBUS as soon as a memory corruption is detected.
|
||||
PR_MCE_KILL_EARLY,
|
||||
/// The process is killed only when it accesses a corrupted page.
|
||||
PR_MCE_KILL_LATE,
|
||||
/// Uses the system-wide default.
|
||||
PR_MCE_KILL_DEFAULT,
|
||||
}
|
||||
impl TryFrom<i32>
|
||||
}
|
||||
|
||||
fn prctl_set_bool(option: c_int, status: bool) -> Result<()> {
|
||||
let res = unsafe { libc::prctl(option, status as c_ulong, 0, 0, 0) };
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
fn prctl_get_bool(option: c_int) -> Result<bool> {
|
||||
let res = unsafe { libc::prctl(option, 0, 0, 0, 0) };
|
||||
Errno::result(res).map(|res| res != 0)
|
||||
}
|
||||
|
||||
/// Set the "child subreaper" attribute for this process
|
||||
pub fn set_child_subreaper(attribute: bool) -> Result<()> {
|
||||
prctl_set_bool(libc::PR_SET_CHILD_SUBREAPER, attribute)
|
||||
}
|
||||
|
||||
/// Get the "child subreaper" attribute for this process
|
||||
pub fn get_child_subreaper() -> Result<bool> {
|
||||
// prctl writes into this var
|
||||
let mut subreaper: c_int = 0;
|
||||
|
||||
let res = unsafe {
|
||||
libc::prctl(libc::PR_GET_CHILD_SUBREAPER, &mut subreaper, 0, 0, 0)
|
||||
};
|
||||
|
||||
Errno::result(res).map(|_| subreaper != 0)
|
||||
}
|
||||
|
||||
/// Set the dumpable attribute which determines if core dumps are created for this process.
|
||||
pub fn set_dumpable(attribute: bool) -> Result<()> {
|
||||
prctl_set_bool(libc::PR_SET_DUMPABLE, attribute)
|
||||
}
|
||||
|
||||
/// Get the dumpable attribute for this process.
|
||||
pub fn get_dumpable() -> Result<bool> {
|
||||
prctl_get_bool(libc::PR_GET_DUMPABLE)
|
||||
}
|
||||
|
||||
/// Set the "keep capabilities" attribute for this process. This causes the thread to retain
|
||||
/// capabilities even if it switches its UID to a nonzero value.
|
||||
pub fn set_keepcaps(attribute: bool) -> Result<()> {
|
||||
prctl_set_bool(libc::PR_SET_KEEPCAPS, attribute)
|
||||
}
|
||||
|
||||
/// Get the "keep capabilities" attribute for this process
|
||||
pub fn get_keepcaps() -> Result<bool> {
|
||||
prctl_get_bool(libc::PR_GET_KEEPCAPS)
|
||||
}
|
||||
|
||||
/// Clear the thread memory corruption kill policy and use the system-wide default
|
||||
pub fn clear_mce_kill() -> Result<()> {
|
||||
let res = unsafe {
|
||||
libc::prctl(libc::PR_MCE_KILL, libc::PR_MCE_KILL_CLEAR, 0, 0, 0)
|
||||
};
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
/// Set the thread memory corruption kill policy
|
||||
pub fn set_mce_kill(policy: PrctlMCEKillPolicy) -> Result<()> {
|
||||
let res = unsafe {
|
||||
libc::prctl(
|
||||
libc::PR_MCE_KILL,
|
||||
libc::PR_MCE_KILL_SET,
|
||||
policy as c_ulong,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
};
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
/// Get the thread memory corruption kill policy
|
||||
pub fn get_mce_kill() -> Result<PrctlMCEKillPolicy> {
|
||||
let res = unsafe { libc::prctl(libc::PR_MCE_KILL_GET, 0, 0, 0, 0) };
|
||||
|
||||
match Errno::result(res) {
|
||||
Ok(val) => Ok(PrctlMCEKillPolicy::try_from(val)?),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the parent-death signal of the calling process. This is the signal that the calling process
|
||||
/// will get when its parent dies.
|
||||
pub fn set_pdeathsig<T: Into<Option<Signal>>>(signal: T) -> Result<()> {
|
||||
let sig = match signal.into() {
|
||||
Some(s) => s as c_int,
|
||||
None => 0,
|
||||
};
|
||||
|
||||
let res = unsafe { libc::prctl(libc::PR_SET_PDEATHSIG, sig, 0, 0, 0) };
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
/// Returns the current parent-death signal
|
||||
pub fn get_pdeathsig() -> Result<Option<Signal>> {
|
||||
// prctl writes into this var
|
||||
let mut sig: c_int = 0;
|
||||
|
||||
let res = unsafe { libc::prctl(libc::PR_GET_PDEATHSIG, &mut sig, 0, 0, 0) };
|
||||
|
||||
match Errno::result(res) {
|
||||
Ok(_) => Ok(match sig {
|
||||
0 => None,
|
||||
_ => Some(Signal::try_from(sig)?),
|
||||
}),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the name of the calling thread. Strings longer than 15 bytes will be truncated.
|
||||
pub fn set_name(name: &CStr) -> Result<()> {
|
||||
let res = unsafe { libc::prctl(libc::PR_SET_NAME, name.as_ptr(), 0, 0, 0) };
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
/// Return the name of the calling thread
|
||||
pub fn get_name() -> Result<CString> {
|
||||
// Size of buffer determined by linux/sched.h TASK_COMM_LEN
|
||||
let buf = [0u8; 16];
|
||||
|
||||
let res = unsafe { libc::prctl(libc::PR_GET_NAME, &buf, 0, 0, 0) };
|
||||
|
||||
Errno::result(res).and_then(|_| {
|
||||
CStr::from_bytes_until_nul(&buf)
|
||||
.map(CStr::to_owned)
|
||||
.map_err(|_| Errno::EINVAL)
|
||||
})
|
||||
}
|
||||
|
||||
/// Sets the timer slack value for the calling thread. Timer slack is used by the kernel to group
|
||||
/// timer expirations and make them the supplied amount of nanoseconds late.
|
||||
pub fn set_timerslack(ns: c_ulong) -> Result<()> {
|
||||
let res = unsafe { libc::prctl(libc::PR_SET_TIMERSLACK, ns, 0, 0, 0) };
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
/// Get the timerslack for the calling thread.
|
||||
pub fn get_timerslack() -> Result<i32> {
|
||||
let res = unsafe { libc::prctl(libc::PR_GET_TIMERSLACK, 0, 0, 0, 0) };
|
||||
|
||||
Errno::result(res)
|
||||
}
|
||||
|
||||
/// Disable all performance counters attached to the calling process.
|
||||
pub fn task_perf_events_disable() -> Result<()> {
|
||||
let res =
|
||||
unsafe { libc::prctl(libc::PR_TASK_PERF_EVENTS_DISABLE, 0, 0, 0, 0) };
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
/// Enable all performance counters attached to the calling process.
|
||||
pub fn task_perf_events_enable() -> Result<()> {
|
||||
let res =
|
||||
unsafe { libc::prctl(libc::PR_TASK_PERF_EVENTS_ENABLE, 0, 0, 0, 0) };
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
/// Set the calling threads "no new privs" attribute. Once set this option can not be unset.
|
||||
pub fn set_no_new_privs() -> Result<()> {
|
||||
prctl_set_bool(libc::PR_SET_NO_NEW_PRIVS, true) // Cannot be unset
|
||||
}
|
||||
|
||||
/// Get the "no new privs" attribute for the calling thread.
|
||||
pub fn get_no_new_privs() -> Result<bool> {
|
||||
prctl_get_bool(libc::PR_GET_NO_NEW_PRIVS)
|
||||
}
|
||||
|
||||
/// Set the state of the "THP disable" flag for the calling thread. Setting this disables
|
||||
/// transparent huge pages.
|
||||
pub fn set_thp_disable(flag: bool) -> Result<()> {
|
||||
prctl_set_bool(libc::PR_SET_THP_DISABLE, flag)
|
||||
}
|
||||
|
||||
/// Get the "THP disable" flag for the calling thread.
|
||||
pub fn get_thp_disable() -> Result<bool> {
|
||||
prctl_get_bool(libc::PR_GET_THP_DISABLE)
|
||||
}
|
||||
|
||||
/// Set an identifier (or reset it) to the address memory range.
|
||||
pub fn set_vma_anon_name(addr: NonNull<c_void>, length: NonZeroUsize, name: Option<&CStr>) -> Result<()> {
|
||||
let nameref = match name {
|
||||
Some(n) => n.as_ptr(),
|
||||
_ => std::ptr::null()
|
||||
};
|
||||
let res = unsafe { libc::prctl(libc::PR_SET_VMA, libc::PR_SET_VMA_ANON_NAME, addr.as_ptr(), length, nameref) };
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
+17
-25
@@ -9,10 +9,7 @@ use std::ptr;
|
||||
pub type RequestType = c_int;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "openbsd"))] {
|
||||
if #[cfg(any(freebsdlike, apple_targets, target_os = "openbsd"))] {
|
||||
#[doc(hidden)]
|
||||
pub type AddressType = *mut ::libc::c_char;
|
||||
} else {
|
||||
@@ -29,33 +26,26 @@ libc_enum! {
|
||||
PT_TRACE_ME,
|
||||
PT_READ_I,
|
||||
PT_READ_D,
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(apple_targets)]
|
||||
PT_READ_U,
|
||||
PT_WRITE_I,
|
||||
PT_WRITE_D,
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(apple_targets)]
|
||||
PT_WRITE_U,
|
||||
PT_CONTINUE,
|
||||
PT_KILL,
|
||||
#[cfg(any(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos"),
|
||||
#[cfg(any(any(freebsdlike, apple_targets),
|
||||
all(target_os = "openbsd", target_arch = "x86_64"),
|
||||
all(target_os = "netbsd", any(target_arch = "x86_64",
|
||||
target_arch = "powerpc"))))]
|
||||
PT_STEP,
|
||||
PT_ATTACH,
|
||||
PT_DETACH,
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(apple_targets)]
|
||||
PT_SIGEXC,
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(apple_targets)]
|
||||
PT_THUPDATE,
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(apple_targets)]
|
||||
PT_ATTACHEXC
|
||||
}
|
||||
}
|
||||
@@ -66,13 +56,15 @@ unsafe fn ptrace_other(
|
||||
addr: AddressType,
|
||||
data: c_int,
|
||||
) -> Result<c_int> {
|
||||
Errno::result(libc::ptrace(
|
||||
request as RequestType,
|
||||
libc::pid_t::from(pid),
|
||||
addr,
|
||||
data,
|
||||
))
|
||||
.map(|_| 0)
|
||||
unsafe {
|
||||
Errno::result(libc::ptrace(
|
||||
request as RequestType,
|
||||
libc::pid_t::from(pid),
|
||||
addr,
|
||||
data,
|
||||
))
|
||||
.map(|_| 0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the process as traceable, as with `ptrace(PT_TRACEME, ...)`
|
||||
@@ -157,7 +149,7 @@ pub fn kill(pid: Pid) -> Result<()> {
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(any(
|
||||
any(target_os = "dragonfly", target_os = "freebsd", target_os = "macos"),
|
||||
any(freebsdlike, apple_targets),
|
||||
all(target_os = "openbsd", target_arch = "x86_64"),
|
||||
all(
|
||||
target_os = "netbsd",
|
||||
|
||||
+313
-56
@@ -14,11 +14,12 @@ pub type AddressType = *mut ::libc::c_void;
|
||||
target_os = "linux",
|
||||
any(
|
||||
all(
|
||||
target_arch = "x86_64",
|
||||
any(target_env = "gnu", target_env = "musl", target_env = "ohos")
|
||||
any(target_arch = "x86_64", target_arch = "aarch64"),
|
||||
any(target_env = "gnu", target_env = "musl")
|
||||
),
|
||||
all(target_arch = "x86", target_env = "gnu")
|
||||
)
|
||||
all(target_arch = "x86", target_env = "gnu"),
|
||||
all(target_arch = "riscv64", target_env = "gnu"),
|
||||
),
|
||||
))]
|
||||
use libc::user_regs_struct;
|
||||
|
||||
@@ -35,8 +36,8 @@ cfg_if! {
|
||||
}
|
||||
|
||||
libc_enum! {
|
||||
#[cfg_attr(not(any(target_env = "musl", target_env = "ohos", target_env = "uclibc", target_os = "android")), repr(u32))]
|
||||
#[cfg_attr(any(target_env = "musl", target_env = "ohos", target_env = "uclibc", target_os = "android"), repr(i32))]
|
||||
#[cfg_attr(not(any(target_env = "musl", target_env = "uclibc", target_os = "android", target_env = "ohos")), repr(u32))]
|
||||
#[cfg_attr(any(target_env = "musl", target_env = "uclibc", target_os = "android", target_env = "ohos"), repr(i32))]
|
||||
/// Ptrace Request enum defining the action to be taken.
|
||||
#[non_exhaustive]
|
||||
pub enum Request {
|
||||
@@ -54,7 +55,9 @@ libc_enum! {
|
||||
all(target_os = "linux", any(target_env = "musl",
|
||||
target_env = "ohos",
|
||||
target_arch = "mips",
|
||||
target_arch = "mips32r6",
|
||||
target_arch = "mips64",
|
||||
target_arch = "mips64r6",
|
||||
target_arch = "x86_64",
|
||||
target_pointer_width = "32"))))]
|
||||
PTRACE_GETREGS,
|
||||
@@ -62,7 +65,9 @@ libc_enum! {
|
||||
all(target_os = "linux", any(target_env = "musl",
|
||||
target_env = "ohos",
|
||||
target_arch = "mips",
|
||||
target_arch = "mips32r6",
|
||||
target_arch = "mips64",
|
||||
target_arch = "mips64r6",
|
||||
target_arch = "x86_64",
|
||||
target_pointer_width = "32"))))]
|
||||
PTRACE_SETREGS,
|
||||
@@ -70,7 +75,9 @@ libc_enum! {
|
||||
all(target_os = "linux", any(target_env = "musl",
|
||||
target_env = "ohos",
|
||||
target_arch = "mips",
|
||||
target_arch = "mips32r6",
|
||||
target_arch = "mips64",
|
||||
target_arch = "mips64r6",
|
||||
target_arch = "x86_64",
|
||||
target_pointer_width = "32"))))]
|
||||
PTRACE_GETFPREGS,
|
||||
@@ -78,7 +85,9 @@ libc_enum! {
|
||||
all(target_os = "linux", any(target_env = "musl",
|
||||
target_env = "ohos",
|
||||
target_arch = "mips",
|
||||
target_arch = "mips32r6",
|
||||
target_arch = "mips64",
|
||||
target_arch = "mips64r6",
|
||||
target_arch = "x86_64",
|
||||
target_pointer_width = "32"))))]
|
||||
PTRACE_SETFPREGS,
|
||||
@@ -87,14 +96,18 @@ libc_enum! {
|
||||
#[cfg(all(target_os = "linux", any(target_env = "musl",
|
||||
target_env = "ohos",
|
||||
target_arch = "mips",
|
||||
target_arch = "mips32r6",
|
||||
target_arch = "mips64",
|
||||
target_arch = "mips64r6",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64")))]
|
||||
PTRACE_GETFPXREGS,
|
||||
#[cfg(all(target_os = "linux", any(target_env = "musl",
|
||||
target_env = "ohos",
|
||||
target_arch = "mips",
|
||||
target_arch = "mips32r6",
|
||||
target_arch = "mips64",
|
||||
target_arch = "mips64r6",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64")))]
|
||||
PTRACE_SETFPXREGS,
|
||||
@@ -104,22 +117,28 @@ libc_enum! {
|
||||
PTRACE_GETSIGINFO,
|
||||
PTRACE_SETSIGINFO,
|
||||
#[cfg(all(target_os = "linux", not(any(target_arch = "mips",
|
||||
target_arch = "mips64"))))]
|
||||
target_arch = "mips32r6",
|
||||
target_arch = "mips64",
|
||||
target_arch = "mips64r6"))))]
|
||||
PTRACE_GETREGSET,
|
||||
#[cfg(all(target_os = "linux", not(any(target_arch = "mips",
|
||||
target_arch = "mips64"))))]
|
||||
target_arch = "mips32r6",
|
||||
target_arch = "mips64",
|
||||
target_arch = "mips64r6"))))]
|
||||
PTRACE_SETREGSET,
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
PTRACE_SEIZE,
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
PTRACE_INTERRUPT,
|
||||
#[cfg(all(target_os = "linux", not(any(target_arch = "mips",
|
||||
target_arch = "mips64"))))]
|
||||
target_arch = "mips32r6",
|
||||
target_arch = "mips64",
|
||||
target_arch = "mips64r6"))))]
|
||||
PTRACE_LISTEN,
|
||||
#[cfg(all(target_os = "linux", not(any(target_arch = "mips",
|
||||
target_arch = "mips64"))))]
|
||||
target_arch = "mips32r6",
|
||||
target_arch = "mips64",
|
||||
target_arch = "mips64r6"))))]
|
||||
PTRACE_PEEKSIGINFO,
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu",
|
||||
any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
@@ -127,6 +146,8 @@ libc_enum! {
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu",
|
||||
any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
PTRACE_SYSEMU_SINGLESTEP,
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu"))]
|
||||
PTRACE_GET_SYSCALL_INFO,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,6 +179,117 @@ libc_enum! {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
any(
|
||||
all(
|
||||
target_env = "gnu",
|
||||
any(
|
||||
target_arch = "x86_64",
|
||||
target_arch = "x86",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "riscv64",
|
||||
)
|
||||
),
|
||||
all(
|
||||
target_env = "musl",
|
||||
target_arch = "aarch64",
|
||||
)
|
||||
),
|
||||
))]
|
||||
libc_enum! {
|
||||
#[repr(i32)]
|
||||
/// Defines a specific register set, as used in `PTRACE_GETREGSET` and `PTRACE_SETREGSET`.
|
||||
#[non_exhaustive]
|
||||
pub enum RegisterSetValue {
|
||||
NT_PRSTATUS,
|
||||
NT_PRFPREG,
|
||||
NT_PRPSINFO,
|
||||
NT_TASKSTRUCT,
|
||||
NT_AUXV,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
any(
|
||||
all(
|
||||
target_env = "gnu",
|
||||
any(
|
||||
target_arch = "x86_64",
|
||||
target_arch = "x86",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "riscv64",
|
||||
)
|
||||
),
|
||||
all(
|
||||
target_env = "musl",
|
||||
target_arch = "aarch64",
|
||||
)
|
||||
),
|
||||
))]
|
||||
/// Represents register set areas, such as general-purpose registers or
|
||||
/// floating-point registers.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This trait is marked unsafe, since implementation of the trait must match
|
||||
/// ptrace's request `VALUE` and return data type `Regs`.
|
||||
pub unsafe trait RegisterSet {
|
||||
/// Corresponding type of registers in the kernel.
|
||||
const VALUE: RegisterSetValue;
|
||||
|
||||
/// Struct representing the register space.
|
||||
type Regs;
|
||||
}
|
||||
|
||||
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
any(
|
||||
all(
|
||||
target_env = "gnu",
|
||||
any(
|
||||
target_arch = "x86_64",
|
||||
target_arch = "x86",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "riscv64",
|
||||
)
|
||||
),
|
||||
all(
|
||||
target_env = "musl",
|
||||
target_arch = "aarch64",
|
||||
)
|
||||
),
|
||||
))]
|
||||
/// Register sets used in [`getregset`] and [`setregset`]
|
||||
pub mod regset {
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
/// General-purpose registers.
|
||||
pub enum NT_PRSTATUS {}
|
||||
|
||||
unsafe impl RegisterSet for NT_PRSTATUS {
|
||||
const VALUE: RegisterSetValue = RegisterSetValue::NT_PRSTATUS;
|
||||
type Regs = user_regs_struct;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
/// Floating-point registers.
|
||||
pub enum NT_PRFPREG {}
|
||||
|
||||
unsafe impl RegisterSet for NT_PRFPREG {
|
||||
const VALUE: RegisterSetValue = RegisterSetValue::NT_PRFPREG;
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
type Regs = libc::user_fpregs_struct;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
type Regs = libc::user_fpsimd_struct;
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
type Regs = libc::__riscv_mc_d_ext_state;
|
||||
}
|
||||
}
|
||||
|
||||
libc_bitflags! {
|
||||
/// Ptrace options used in conjunction with the PTRACE_SETOPTIONS request.
|
||||
/// See `man ptrace` for more details.
|
||||
@@ -205,12 +337,18 @@ fn ptrace_peek(
|
||||
}
|
||||
|
||||
/// Get user registers, as with `ptrace(PTRACE_GETREGS, ...)`
|
||||
///
|
||||
/// Note that since `PTRACE_GETREGS` are not available on all platforms (as in [ptrace(2)]),
|
||||
/// `ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, ...)` is used instead to achieve the same effect
|
||||
/// on aarch64 and riscv64.
|
||||
///
|
||||
/// [ptrace(2)]: https://www.man7.org/linux/man-pages/man2/ptrace.2.html
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
any(
|
||||
all(
|
||||
target_arch = "x86_64",
|
||||
any(target_env = "gnu", target_env = "musl", target_env = "ohos")
|
||||
any(target_env = "gnu", target_env = "musl")
|
||||
),
|
||||
all(target_arch = "x86", target_env = "gnu")
|
||||
)
|
||||
@@ -219,13 +357,74 @@ pub fn getregs(pid: Pid) -> Result<user_regs_struct> {
|
||||
ptrace_get_data::<user_regs_struct>(Request::PTRACE_GETREGS, pid)
|
||||
}
|
||||
|
||||
/// Get user registers, as with `ptrace(PTRACE_GETREGS, ...)`
|
||||
///
|
||||
/// Note that since `PTRACE_GETREGS` are not available on all platforms (as in [ptrace(2)]),
|
||||
/// `ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, ...)` is used instead to achieve the same effect
|
||||
/// on aarch64 and riscv64.
|
||||
///
|
||||
/// [ptrace(2)]: https://www.man7.org/linux/man-pages/man2/ptrace.2.html
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
any(
|
||||
all(
|
||||
target_arch = "aarch64",
|
||||
any(target_env = "gnu", target_env = "musl")
|
||||
),
|
||||
all(target_arch = "riscv64", target_env = "gnu")
|
||||
)
|
||||
))]
|
||||
pub fn getregs(pid: Pid) -> Result<user_regs_struct> {
|
||||
getregset::<regset::NT_PRSTATUS>(pid)
|
||||
}
|
||||
|
||||
/// Get a particular set of user registers, as with `ptrace(PTRACE_GETREGSET, ...)`
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
any(
|
||||
all(
|
||||
target_env = "gnu",
|
||||
any(
|
||||
target_arch = "x86_64",
|
||||
target_arch = "x86",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "riscv64"
|
||||
)
|
||||
),
|
||||
all(target_env = "musl", target_arch = "aarch64")
|
||||
)
|
||||
))]
|
||||
pub fn getregset<S: RegisterSet>(pid: Pid) -> Result<S::Regs> {
|
||||
let request = Request::PTRACE_GETREGSET;
|
||||
let mut data = mem::MaybeUninit::<S::Regs>::uninit();
|
||||
let mut iov = libc::iovec {
|
||||
iov_base: data.as_mut_ptr().cast(),
|
||||
iov_len: mem::size_of::<S::Regs>(),
|
||||
};
|
||||
unsafe {
|
||||
ptrace_other(
|
||||
request,
|
||||
pid,
|
||||
S::VALUE as i32 as AddressType,
|
||||
(&mut iov as *mut libc::iovec).cast(),
|
||||
)?;
|
||||
};
|
||||
Ok(unsafe { data.assume_init() })
|
||||
}
|
||||
|
||||
/// Set user registers, as with `ptrace(PTRACE_SETREGS, ...)`
|
||||
///
|
||||
/// Note that since `PTRACE_SETREGS` are not available on all platforms (as in [ptrace(2)]),
|
||||
/// `ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, ...)` is used instead to achieve the same effect
|
||||
/// on aarch64 and riscv64.
|
||||
///
|
||||
/// [ptrace(2)]: https://www.man7.org/linux/man-pages/man2/ptrace.2.html
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
any(
|
||||
all(
|
||||
target_arch = "x86_64",
|
||||
any(target_env = "gnu", target_env = "musl", target_env = "ohos")
|
||||
any(target_env = "gnu", target_env = "musl")
|
||||
),
|
||||
all(target_arch = "x86", target_env = "gnu")
|
||||
)
|
||||
@@ -236,24 +435,77 @@ pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> {
|
||||
Request::PTRACE_SETREGS as RequestType,
|
||||
libc::pid_t::from(pid),
|
||||
ptr::null_mut::<c_void>(),
|
||||
®s as *const _ as *const c_void,
|
||||
®s as *const user_regs_struct as *const c_void,
|
||||
)
|
||||
};
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
/// Set user registers, as with `ptrace(PTRACE_SETREGS, ...)`
|
||||
///
|
||||
/// Note that since `PTRACE_SETREGS` are not available on all platforms (as in [ptrace(2)]),
|
||||
/// `ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, ...)` is used instead to achieve the same effect
|
||||
/// on aarch64 and riscv64.
|
||||
///
|
||||
/// [ptrace(2)]: https://www.man7.org/linux/man-pages/man2/ptrace.2.html
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
any(
|
||||
all(
|
||||
target_env = "gnu",
|
||||
any(target_arch = "aarch64", target_arch = "riscv64")
|
||||
),
|
||||
all(target_env = "musl", target_arch = "aarch64")
|
||||
)
|
||||
))]
|
||||
pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> {
|
||||
setregset::<regset::NT_PRSTATUS>(pid, regs)
|
||||
}
|
||||
|
||||
/// Set a particular set of user registers, as with `ptrace(PTRACE_SETREGSET, ...)`
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
any(
|
||||
all(
|
||||
target_env = "gnu",
|
||||
any(
|
||||
target_arch = "x86_64",
|
||||
target_arch = "x86",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "riscv64"
|
||||
)
|
||||
),
|
||||
all(target_env = "musl", target_arch = "aarch64")
|
||||
)
|
||||
))]
|
||||
pub fn setregset<S: RegisterSet>(pid: Pid, mut regs: S::Regs) -> Result<()> {
|
||||
let mut iov = libc::iovec {
|
||||
iov_base: (&mut regs as *mut S::Regs).cast(),
|
||||
iov_len: mem::size_of::<S::Regs>(),
|
||||
};
|
||||
unsafe {
|
||||
ptrace_other(
|
||||
Request::PTRACE_SETREGSET,
|
||||
pid,
|
||||
S::VALUE as i32 as AddressType,
|
||||
(&mut iov as *mut libc::iovec).cast(),
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 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 mut data = mem::MaybeUninit::<T>::uninit();
|
||||
let res = unsafe {
|
||||
libc::ptrace(
|
||||
request as RequestType,
|
||||
libc::pid_t::from(pid),
|
||||
ptr::null_mut::<T>(),
|
||||
data.as_mut_ptr() as *const _ as *const c_void,
|
||||
data.as_mut_ptr(),
|
||||
)
|
||||
};
|
||||
Errno::result(res)?;
|
||||
@@ -266,16 +518,18 @@ unsafe fn ptrace_other(
|
||||
addr: AddressType,
|
||||
data: *mut c_void,
|
||||
) -> Result<c_long> {
|
||||
Errno::result(libc::ptrace(
|
||||
request as RequestType,
|
||||
libc::pid_t::from(pid),
|
||||
addr,
|
||||
data,
|
||||
))
|
||||
.map(|_| 0)
|
||||
unsafe {
|
||||
Errno::result(libc::ptrace(
|
||||
request as RequestType,
|
||||
libc::pid_t::from(pid),
|
||||
addr,
|
||||
data,
|
||||
))
|
||||
.map(|_| 0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Set options, as with `ptrace(PTRACE_SETOPTIONS,...)`.
|
||||
/// Set options, as with `ptrace(PTRACE_SETOPTIONS, ...)`.
|
||||
pub fn setoptions(pid: Pid, options: Options) -> Result<()> {
|
||||
let res = unsafe {
|
||||
libc::ptrace(
|
||||
@@ -288,17 +542,17 @@ pub fn setoptions(pid: Pid, options: Options) -> Result<()> {
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG,...)`
|
||||
/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG, ...)`
|
||||
pub fn getevent(pid: Pid) -> Result<c_long> {
|
||||
ptrace_get_data::<c_long>(Request::PTRACE_GETEVENTMSG, pid)
|
||||
}
|
||||
|
||||
/// Get siginfo as with `ptrace(PTRACE_GETSIGINFO,...)`
|
||||
/// Get siginfo as with `ptrace(PTRACE_GETSIGINFO, ...)`
|
||||
pub fn getsiginfo(pid: Pid) -> Result<siginfo_t> {
|
||||
ptrace_get_data::<siginfo_t>(Request::PTRACE_GETSIGINFO, pid)
|
||||
}
|
||||
|
||||
/// Set siginfo as with `ptrace(PTRACE_SETSIGINFO,...)`
|
||||
/// Set siginfo as with `ptrace(PTRACE_SETSIGINFO, ...)`
|
||||
pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> {
|
||||
let ret = unsafe {
|
||||
Errno::clear();
|
||||
@@ -315,6 +569,13 @@ pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the informations of the syscall that caused the stop, as with
|
||||
/// `ptrace(PTRACE_GET_SYSCALL_INFO, ...`.
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu"))]
|
||||
pub fn syscall_info(pid: Pid) -> Result<libc::ptrace_syscall_info> {
|
||||
ptrace_get_data::<libc::ptrace_syscall_info>(Request::PTRACE_GET_SYSCALL_INFO, pid)
|
||||
}
|
||||
|
||||
/// Sets the process as traceable, as with `ptrace(PTRACE_TRACEME, ...)`
|
||||
///
|
||||
/// Indicates that this process is to be traced by its parent.
|
||||
@@ -387,7 +648,6 @@ pub fn attach(pid: Pid) -> Result<()> {
|
||||
///
|
||||
/// Attaches to the process specified in pid, making it a tracee of the calling process.
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn seize(pid: Pid, options: Options) -> Result<()> {
|
||||
unsafe {
|
||||
ptrace_other(
|
||||
@@ -434,7 +694,6 @@ pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
|
||||
///
|
||||
/// This request is equivalent to `ptrace(PTRACE_INTERRUPT, ...)`
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn interrupt(pid: Pid) -> Result<()> {
|
||||
unsafe {
|
||||
ptrace_other(
|
||||
@@ -523,42 +782,40 @@ pub fn sysemu_step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads a word from a processes memory at the given address
|
||||
/// Reads a word from a processes memory at the given address, as with
|
||||
/// ptrace(PTRACE_PEEKDATA, ...)
|
||||
pub fn read(pid: Pid, addr: AddressType) -> Result<c_long> {
|
||||
ptrace_peek(Request::PTRACE_PEEKDATA, pid, addr, ptr::null_mut())
|
||||
}
|
||||
|
||||
/// Writes a word into the processes memory at the given address
|
||||
///
|
||||
/// # 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)
|
||||
/// Writes a word into the processes memory at the given address, as with
|
||||
/// ptrace(PTRACE_POKEDATA, ...)
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
pub fn write(pid: Pid, addr: AddressType, data: c_long) -> Result<()> {
|
||||
unsafe {
|
||||
// Safety(not_unsafe_ptr_arg_deref):
|
||||
// `ptrace_other` is a common abstract
|
||||
// but in `PTRACE_POKEDATA` situation, `data` is exactly what will be wtitten
|
||||
ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data as *mut c_void)
|
||||
.map(drop)
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads a word from a user area at `offset`.
|
||||
/// Reads a word from a user area at `offset`, as with ptrace(PTRACE_PEEKUSER, ...).
|
||||
/// The user struct definition can be found in `/usr/include/sys/user.h`.
|
||||
pub fn read_user(pid: Pid, offset: AddressType) -> Result<c_long> {
|
||||
ptrace_peek(Request::PTRACE_PEEKUSER, pid, offset, ptr::null_mut())
|
||||
}
|
||||
|
||||
/// Writes a word to a user area at `offset`.
|
||||
/// Writes a word to a user area at `offset`, as with ptrace(PTRACE_POKEUSER, ...).
|
||||
/// The user struct definition can be found in `/usr/include/sys/user.h`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The `data` argument is passed directly to `ptrace(2)`. Read that man page
|
||||
/// for guidance.
|
||||
pub unsafe fn write_user(
|
||||
pid: Pid,
|
||||
offset: AddressType,
|
||||
data: *mut c_void,
|
||||
) -> Result<()> {
|
||||
ptrace_other(Request::PTRACE_POKEUSER, pid, offset, data).map(drop)
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
pub fn write_user(pid: Pid, offset: AddressType, data: c_long) -> Result<()> {
|
||||
unsafe {
|
||||
// Safety(not_unsafe_ptr_arg_deref):
|
||||
// `ptrace_other` is a common abstract
|
||||
// but in `PTRACE_POKEDATA` situation, `data` is exactly what will be wtitten
|
||||
ptrace_other(Request::PTRACE_POKEUSER, pid, offset, data as *mut c_void)
|
||||
.map(drop)
|
||||
}
|
||||
}
|
||||
|
||||
+4
-16
@@ -1,25 +1,13 @@
|
||||
//! Provides helpers for making ptrace system calls
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
mod linux;
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
pub use self::linux::*;
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
#[cfg(bsd)]
|
||||
mod bsd;
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
#[cfg(bsd)]
|
||||
pub use self::bsd::*;
|
||||
|
||||
+4
-5
@@ -21,9 +21,8 @@ use std::{mem, ptr};
|
||||
struct QuotaCmd(QuotaSubCmd, QuotaType);
|
||||
|
||||
impl QuotaCmd {
|
||||
#[allow(unused_unsafe)]
|
||||
fn as_int(&self) -> c_int {
|
||||
unsafe { libc::QCMD(self.0 as i32, self.1 as i32) }
|
||||
libc::QCMD(self.0 as i32, self.1 as i32)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,7 +264,7 @@ pub fn quotactl_on<P: ?Sized + NixPath>(
|
||||
) -> Result<()> {
|
||||
quota_file.with_nix_path(|path| {
|
||||
let mut path_copy = path.to_bytes_with_nul().to_owned();
|
||||
let p: *mut c_char = path_copy.as_mut_ptr() as *mut c_char;
|
||||
let p: *mut c_char = path_copy.as_mut_ptr().cast();
|
||||
quotactl(
|
||||
QuotaCmd(QuotaSubCmd::Q_QUOTAON, which),
|
||||
Some(special),
|
||||
@@ -309,12 +308,12 @@ pub fn quotactl_get<P: ?Sized + NixPath>(
|
||||
special: &P,
|
||||
id: c_int,
|
||||
) -> Result<Dqblk> {
|
||||
let mut dqblk = mem::MaybeUninit::uninit();
|
||||
let mut dqblk = mem::MaybeUninit::<libc::dqblk>::uninit();
|
||||
quotactl(
|
||||
QuotaCmd(QuotaSubCmd::Q_GETQUOTA, which),
|
||||
Some(special),
|
||||
id,
|
||||
dqblk.as_mut_ptr() as *mut c_char,
|
||||
dqblk.as_mut_ptr().cast(),
|
||||
)?;
|
||||
Ok(unsafe { Dqblk(dqblk.assume_init()) })
|
||||
}
|
||||
|
||||
+133
-40
@@ -1,48 +1,141 @@
|
||||
//! Reboot/shutdown or enable/disable Ctrl-Alt-Delete.
|
||||
//! Reboot/shutdown
|
||||
//!
|
||||
//! On Linux, This can also be used to enable/disable Ctrl-Alt-Delete.
|
||||
|
||||
use crate::errno::Errno;
|
||||
use crate::Result;
|
||||
use cfg_if::cfg_if;
|
||||
use std::convert::Infallible;
|
||||
use std::mem::drop;
|
||||
|
||||
libc_enum! {
|
||||
/// How exactly should the system be rebooted.
|
||||
///
|
||||
/// See [`set_cad_enabled()`](fn.set_cad_enabled.html) for
|
||||
/// enabling/disabling Ctrl-Alt-Delete.
|
||||
#[repr(i32)]
|
||||
#[non_exhaustive]
|
||||
pub enum RebootMode {
|
||||
/// Halt the system.
|
||||
RB_HALT_SYSTEM,
|
||||
/// Execute a kernel that has been loaded earlier with
|
||||
/// [`kexec_load(2)`](https://man7.org/linux/man-pages/man2/kexec_load.2.html).
|
||||
RB_KEXEC,
|
||||
/// Stop the system and switch off power, if possible.
|
||||
RB_POWER_OFF,
|
||||
/// Restart the system.
|
||||
RB_AUTOBOOT,
|
||||
// we do not support Restart2.
|
||||
/// Suspend the system using software suspend.
|
||||
RB_SW_SUSPEND,
|
||||
cfg_if! {
|
||||
if #[cfg(target_os = "linux")] {
|
||||
use std::mem::drop;
|
||||
|
||||
libc_enum! {
|
||||
/// How exactly should the system be rebooted.
|
||||
///
|
||||
/// See [`set_cad_enabled()`](fn.set_cad_enabled.html) for
|
||||
/// enabling/disabling Ctrl-Alt-Delete.
|
||||
#[repr(i32)]
|
||||
#[non_exhaustive]
|
||||
pub enum RebootMode {
|
||||
/// Halt the system.
|
||||
RB_HALT_SYSTEM,
|
||||
/// Execute a kernel that has been loaded earlier with
|
||||
/// [`kexec_load(2)`](https://man7.org/linux/man-pages/man2/kexec_load.2.html).
|
||||
RB_KEXEC,
|
||||
/// Stop the system and switch off power, if possible.
|
||||
RB_POWER_OFF,
|
||||
/// Restart the system.
|
||||
RB_AUTOBOOT,
|
||||
// we do not support Restart2.
|
||||
/// Suspend the system using software suspend.
|
||||
RB_SW_SUSPEND,
|
||||
}
|
||||
}
|
||||
|
||||
/// Reboots or shuts down the system.
|
||||
pub fn reboot(how: RebootMode) -> Result<Infallible> {
|
||||
unsafe { libc::reboot(how as libc::c_int) };
|
||||
Err(Errno::last())
|
||||
}
|
||||
|
||||
/// Enable or disable the reboot keystroke (Ctrl-Alt-Delete).
|
||||
///
|
||||
/// Corresponds to calling `reboot(RB_ENABLE_CAD)` or `reboot(RB_DISABLE_CAD)` in C.
|
||||
pub fn set_cad_enabled(enable: bool) -> Result<()> {
|
||||
let cmd = if enable {
|
||||
libc::RB_ENABLE_CAD
|
||||
} else {
|
||||
libc::RB_DISABLE_CAD
|
||||
};
|
||||
let res = unsafe { libc::reboot(cmd) };
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
} else if #[cfg(netbsdlike)] {
|
||||
use libc::c_int;
|
||||
|
||||
libc_bitflags! {
|
||||
/// How exactly should the system be rebooted.
|
||||
pub struct RebootMode: c_int {
|
||||
/// The default, causing the system to reboot in its usual fashion.
|
||||
RB_AUTOBOOT;
|
||||
/// Interpreted by the bootstrap program itself, causing it to
|
||||
/// prompt on the console as to what file should be booted.
|
||||
/// Normally, the system is booted from the file “xx(0,0)bsd”,
|
||||
/// where xx is the default disk name, without prompting for
|
||||
/// the file name.
|
||||
RB_ASKNAME;
|
||||
/// Dump kernel memory before rebooting; see `savecore(8)` for
|
||||
/// more information.
|
||||
RB_DUMP;
|
||||
/// The processor is simply halted; no reboot takes place.
|
||||
RB_HALT;
|
||||
/// Power off the system if the system hardware supports the
|
||||
/// function, otherwise it has no effect.
|
||||
///
|
||||
/// Should be used in conjunction with `RB_HALT`.
|
||||
RB_POWERDOWN;
|
||||
/// By default, the system will halt if `reboot()` is called during
|
||||
/// startup (before the system has finished autoconfiguration), even
|
||||
/// if `RB_HALT` is not specified. This is because `panic(9)`s
|
||||
/// during startup will probably just repeat on the next boot.
|
||||
/// Use of this option implies that the user has requested the
|
||||
/// action specified (for example, using the `ddb(4)` boot reboot
|
||||
/// command), so the system will reboot if a halt is not explicitly
|
||||
/// requested.
|
||||
#[cfg(target_os = "openbsd")]
|
||||
RB_USERREQ;
|
||||
/// Load the symbol table and enable a built-in debugger in the
|
||||
/// system. This option will have no useful function if the kernel
|
||||
/// is not configured for debugging. Several other options have
|
||||
/// different meaning if combined with this option, although their
|
||||
/// use may not be possible via the `reboot()` call. See `ddb(4)` for
|
||||
/// more information.
|
||||
RB_KDB;
|
||||
/// Normally, the disks are sync'd (see `sync(8)`) before the
|
||||
/// processor is halted or rebooted. This option may be useful
|
||||
/// if file system changes have been made manually or if the
|
||||
/// processor is on fire.
|
||||
RB_NOSYNC;
|
||||
/// Normally, the reboot procedure involves an automatic disk
|
||||
/// consistency check and then multi-user operations. `RB_SINGLE`
|
||||
/// prevents this, booting the system with a single-user shell on
|
||||
/// the console. `RB_SINGLE` is actually interpreted by the `init(8)`
|
||||
/// program in the newly booted system.
|
||||
///
|
||||
/// When no options are given (i.e., `RB_AUTOBOOT` is used), the
|
||||
/// system is rebooted from file /bsd in the root file system of
|
||||
/// unit 0 of a disk chosen in a processor specific way. An automatic
|
||||
/// consistency check of the disks is normally performed (see `fsck(8)`).
|
||||
RB_SINGLE;
|
||||
/// Initially invoke the `userconf(4)` facility when the system
|
||||
/// starts up again, if it has been compiled into the kernel
|
||||
/// that is loaded.
|
||||
#[cfg(target_os = "netbsd")]
|
||||
RB_USERCONF;
|
||||
/// Don't update the hardware clock from the system clock, presumably
|
||||
/// because the system clock is suspect.
|
||||
#[cfg(target_os = "openbsd")]
|
||||
RB_TIMEBAD;
|
||||
}
|
||||
}
|
||||
|
||||
/// Reboot system or halt processor
|
||||
///
|
||||
/// For more information, see the man pages:
|
||||
///
|
||||
/// * [NetBSD](https://man.netbsd.org/reboot.2)
|
||||
/// * [OpenBSD](https://man.openbsd.org/reboot.2)
|
||||
#[cfg(netbsdlike)]
|
||||
pub fn reboot(how: RebootMode) -> Result<Infallible> {
|
||||
#[cfg(target_os = "openbsd")]
|
||||
unsafe { libc::reboot(how.bits()) };
|
||||
#[cfg(target_os = "netbsd")]
|
||||
unsafe { libc::reboot(how.bits(), std::ptr::null_mut()) };
|
||||
|
||||
Err(Errno::last())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Reboots or shuts down the system.
|
||||
pub fn reboot(how: RebootMode) -> Result<Infallible> {
|
||||
unsafe { libc::reboot(how as libc::c_int) };
|
||||
Err(Errno::last())
|
||||
}
|
||||
|
||||
/// Enable or disable the reboot keystroke (Ctrl-Alt-Delete).
|
||||
///
|
||||
/// Corresponds to calling `reboot(RB_ENABLE_CAD)` or `reboot(RB_DISABLE_CAD)` in C.
|
||||
pub fn set_cad_enabled(enable: bool) -> Result<()> {
|
||||
let cmd = if enable {
|
||||
libc::RB_ENABLE_CAD
|
||||
} else {
|
||||
libc::RB_DISABLE_CAD
|
||||
};
|
||||
let res = unsafe { libc::reboot(cmd) };
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
+41
-82
@@ -10,17 +10,17 @@ pub use libc::RLIM_INFINITY;
|
||||
use std::mem;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{
|
||||
if #[cfg(any(
|
||||
all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")),
|
||||
target_os = "hurd"
|
||||
))]{
|
||||
use libc::{__rlimit_resource_t, rlimit};
|
||||
} else if #[cfg(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
bsd,
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
all(target_os = "linux", not(target_env = "gnu"))
|
||||
target_os = "aix",
|
||||
all(target_os = "linux", not(target_env = "gnu")),
|
||||
target_os = "cygwin"
|
||||
))]{
|
||||
use libc::rlimit;
|
||||
}
|
||||
@@ -42,21 +42,20 @@ libc_enum! {
|
||||
//
|
||||
// https://gcc.gnu.org/legacy-ml/gcc/2015-08/msg00441.html
|
||||
// https://github.com/rust-lang/libc/blob/master/src/unix/linux_like/linux/gnu/mod.rs
|
||||
#[cfg_attr(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")), repr(u32))]
|
||||
#[cfg_attr(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")),
|
||||
target_os = "hurd"
|
||||
), repr(u32))]
|
||||
#[cfg_attr(any(
|
||||
bsd,
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
all(target_os = "linux", not(any(target_env = "gnu", target_env = "uclibc")))
|
||||
target_os = "aix",
|
||||
all(target_os = "linux", not(any(target_env = "gnu", target_env = "uclibc"))),
|
||||
target_os = "cygwin"
|
||||
), repr(i32))]
|
||||
#[non_exhaustive]
|
||||
pub enum Resource {
|
||||
#[cfg(not(any(target_os = "freebsd", target_os = "netbsd", target_os = "openbsd")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(not(any(target_os = "freebsd", netbsdlike)))]
|
||||
/// The maximum amount (in bytes) of virtual memory the process is
|
||||
/// allowed to map.
|
||||
RLIMIT_AS,
|
||||
@@ -75,100 +74,78 @@ libc_enum! {
|
||||
RLIMIT_STACK,
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
/// The maximum number of kqueues this user id is allowed to create.
|
||||
RLIMIT_KQUEUES,
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
/// A limit on the combined number of flock locks and fcntl leases that
|
||||
/// this process may establish.
|
||||
RLIMIT_LOCKS,
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd"
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(linux_android, target_os = "freebsd", netbsdlike))]
|
||||
/// The maximum size (in bytes) which a process may lock into memory
|
||||
/// using the mlock(2) system call.
|
||||
RLIMIT_MEMLOCK,
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
/// A limit on the number of bytes that can be allocated for POSIX
|
||||
/// message queues for the real user ID of the calling process.
|
||||
RLIMIT_MSGQUEUE,
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
/// A ceiling to which the process's nice value can be raised using
|
||||
/// setpriority or nice.
|
||||
RLIMIT_NICE,
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
linux_android,
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "linux",
|
||||
netbsdlike,
|
||||
target_os = "aix",
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
/// The maximum number of simultaneous processes for this user id.
|
||||
RLIMIT_NPROC,
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
/// The maximum number of pseudo-terminals this user id is allowed to
|
||||
/// create.
|
||||
RLIMIT_NPTS,
|
||||
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "linux",
|
||||
netbsdlike,
|
||||
target_os = "aix",
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
/// When there is memory pressure and swap is available, prioritize
|
||||
/// eviction of a process' resident pages beyond this amount (in bytes).
|
||||
RLIMIT_RSS,
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
/// A ceiling on the real-time priority that may be set for this process
|
||||
/// using sched_setscheduler and sched_set‐ param.
|
||||
RLIMIT_RTPRIO,
|
||||
|
||||
#[cfg(any(target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
/// A limit (in microseconds) on the amount of CPU time that a process
|
||||
/// scheduled under a real-time scheduling policy may con‐ sume without
|
||||
/// making a blocking system call.
|
||||
RLIMIT_RTTIME,
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
/// A limit on the number of signals that may be queued for the real
|
||||
/// user ID of the calling process.
|
||||
RLIMIT_SIGPENDING,
|
||||
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
/// The maximum size (in bytes) of socket buffer usage for this user.
|
||||
RLIMIT_SBSIZE,
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
/// The maximum size (in bytes) of the swap space that may be reserved
|
||||
/// or used by all of this user id's processes.
|
||||
RLIMIT_SWAP,
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
/// An alias for RLIMIT_AS.
|
||||
RLIMIT_VMEM,
|
||||
}
|
||||
@@ -202,7 +179,10 @@ pub fn getrlimit(resource: Resource) -> Result<(rlim_t, rlim_t)> {
|
||||
let mut old_rlim = mem::MaybeUninit::<rlimit>::uninit();
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{
|
||||
if #[cfg(any(
|
||||
all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")),
|
||||
target_os = "hurd"
|
||||
))] {
|
||||
let res = unsafe { libc::getrlimit(resource as __rlimit_resource_t, old_rlim.as_mut_ptr()) };
|
||||
} else {
|
||||
let res = unsafe { libc::getrlimit(resource as c_int, old_rlim.as_mut_ptr()) };
|
||||
@@ -255,7 +235,10 @@ pub fn setrlimit(
|
||||
rlim_max: hard_limit,
|
||||
};
|
||||
cfg_if! {
|
||||
if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{
|
||||
if #[cfg(any(
|
||||
all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")),
|
||||
target_os = "hurd",
|
||||
))]{
|
||||
let res = unsafe { libc::setrlimit(resource as __rlimit_resource_t, &new_rlim as *const rlimit) };
|
||||
}else{
|
||||
let res = unsafe { libc::setrlimit(resource as c_int, &new_rlim as *const rlimit) };
|
||||
@@ -277,7 +260,6 @@ libc_enum! {
|
||||
RUSAGE_CHILDREN,
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
/// Resource usage for the calling thread.
|
||||
RUSAGE_THREAD,
|
||||
}
|
||||
@@ -313,7 +295,9 @@ impl Usage {
|
||||
TimeVal::from(self.0.ru_stime)
|
||||
}
|
||||
|
||||
/// The resident set size at its peak, in kilobytes.
|
||||
/// The resident set size at its peak,
|
||||
#[cfg_attr(apple_targets, doc = " in bytes.")]
|
||||
#[cfg_attr(not(apple_targets), doc = " in kilobytes.")]
|
||||
pub fn max_rss(&self) -> c_long {
|
||||
self.0.ru_maxrss
|
||||
}
|
||||
@@ -416,28 +400,3 @@ pub fn getrusage(who: UsageWho) -> Result<Usage> {
|
||||
Errno::result(res).map(|_| Usage(rusage.assume_init()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{getrusage, UsageWho};
|
||||
|
||||
#[test]
|
||||
pub fn test_self_cpu_time() {
|
||||
// Make sure some CPU time is used.
|
||||
let mut numbers: Vec<i32> = (1..1_000_000).collect();
|
||||
numbers.iter_mut().for_each(|item| *item *= 2);
|
||||
|
||||
// FIXME: this is here to help ensure the compiler does not optimize the whole
|
||||
// thing away. Replace the assert with test::black_box once stabilized.
|
||||
assert_eq!(numbers[100..200].iter().sum::<i32>(), 30_100);
|
||||
|
||||
let usage = getrusage(UsageWho::RUSAGE_SELF)
|
||||
.expect("Failed to call getrusage for SELF");
|
||||
let rusage = usage.as_ref();
|
||||
|
||||
let user = usage.user_time();
|
||||
assert!(user.tv_sec() > 0 || user.tv_usec() > 0);
|
||||
assert_eq!(user.tv_sec(), rusage.ru_utime.tv_sec);
|
||||
assert_eq!(user.tv_usec(), rusage.ru_utime.tv_usec);
|
||||
}
|
||||
}
|
||||
|
||||
+65
-201
@@ -7,7 +7,7 @@ use std::convert::TryFrom;
|
||||
use std::iter::FusedIterator;
|
||||
use std::mem;
|
||||
use std::ops::Range;
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::os::unix::io::{AsRawFd, BorrowedFd, RawFd};
|
||||
use std::ptr::{null, null_mut};
|
||||
|
||||
pub use libc::FD_SETSIZE;
|
||||
@@ -15,7 +15,10 @@ pub use libc::FD_SETSIZE;
|
||||
/// Contains a set of file descriptors used by [`select`]
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct FdSet(libc::fd_set);
|
||||
pub struct FdSet<'fd> {
|
||||
set: libc::fd_set,
|
||||
_fd: std::marker::PhantomData<BorrowedFd<'fd>>,
|
||||
}
|
||||
|
||||
fn assert_fd_valid(fd: RawFd) {
|
||||
assert!(
|
||||
@@ -24,37 +27,40 @@ fn assert_fd_valid(fd: RawFd) {
|
||||
);
|
||||
}
|
||||
|
||||
impl FdSet {
|
||||
impl<'fd> FdSet<'fd> {
|
||||
/// Create an empty `FdSet`
|
||||
pub fn new() -> FdSet {
|
||||
pub fn new() -> FdSet<'fd> {
|
||||
let mut fdset = mem::MaybeUninit::uninit();
|
||||
unsafe {
|
||||
libc::FD_ZERO(fdset.as_mut_ptr());
|
||||
FdSet(fdset.assume_init())
|
||||
Self {
|
||||
set: fdset.assume_init(),
|
||||
_fd: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a file descriptor to an `FdSet`
|
||||
pub fn insert(&mut self, fd: RawFd) {
|
||||
assert_fd_valid(fd);
|
||||
unsafe { libc::FD_SET(fd, &mut self.0) };
|
||||
pub fn insert(&mut self, fd: BorrowedFd<'fd>) {
|
||||
assert_fd_valid(fd.as_raw_fd());
|
||||
unsafe { libc::FD_SET(fd.as_raw_fd(), &mut self.set) };
|
||||
}
|
||||
|
||||
/// Remove a file descriptor from an `FdSet`
|
||||
pub fn remove(&mut self, fd: RawFd) {
|
||||
assert_fd_valid(fd);
|
||||
unsafe { libc::FD_CLR(fd, &mut self.0) };
|
||||
pub fn remove(&mut self, fd: BorrowedFd<'fd>) {
|
||||
assert_fd_valid(fd.as_raw_fd());
|
||||
unsafe { libc::FD_CLR(fd.as_raw_fd(), &mut self.set) };
|
||||
}
|
||||
|
||||
/// Test an `FdSet` for the presence of a certain file descriptor.
|
||||
pub fn contains(&self, fd: RawFd) -> bool {
|
||||
assert_fd_valid(fd);
|
||||
unsafe { libc::FD_ISSET(fd, &self.0) }
|
||||
pub fn contains(&self, fd: BorrowedFd<'fd>) -> bool {
|
||||
assert_fd_valid(fd.as_raw_fd());
|
||||
unsafe { libc::FD_ISSET(fd.as_raw_fd(), &self.set) }
|
||||
}
|
||||
|
||||
/// Remove all file descriptors from this `FdSet`.
|
||||
pub fn clear(&mut self) {
|
||||
unsafe { libc::FD_ZERO(&mut self.0) };
|
||||
unsafe { libc::FD_ZERO(&mut self.set) };
|
||||
}
|
||||
|
||||
/// Finds the highest file descriptor in the set.
|
||||
@@ -66,15 +72,18 @@ impl FdSet {
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use std::os::unix::io::{AsRawFd, BorrowedFd};
|
||||
/// # use nix::sys::select::FdSet;
|
||||
/// let fd_four = unsafe {BorrowedFd::borrow_raw(4)};
|
||||
/// let fd_nine = unsafe {BorrowedFd::borrow_raw(9)};
|
||||
/// let mut set = FdSet::new();
|
||||
/// set.insert(4);
|
||||
/// set.insert(9);
|
||||
/// assert_eq!(set.highest(), Some(9));
|
||||
/// set.insert(fd_four);
|
||||
/// set.insert(fd_nine);
|
||||
/// assert_eq!(set.highest().map(|borrowed_fd|borrowed_fd.as_raw_fd()), Some(9));
|
||||
/// ```
|
||||
///
|
||||
/// [`select`]: fn.select.html
|
||||
pub fn highest(&self) -> Option<RawFd> {
|
||||
pub fn highest(&self) -> Option<BorrowedFd<'_>> {
|
||||
self.fds(None).next_back()
|
||||
}
|
||||
|
||||
@@ -88,11 +97,13 @@ impl FdSet {
|
||||
///
|
||||
/// ```
|
||||
/// # use nix::sys::select::FdSet;
|
||||
/// # use std::os::unix::io::RawFd;
|
||||
/// # use std::os::unix::io::{AsRawFd, BorrowedFd, RawFd};
|
||||
/// let mut set = FdSet::new();
|
||||
/// set.insert(4);
|
||||
/// set.insert(9);
|
||||
/// let fds: Vec<RawFd> = set.fds(None).collect();
|
||||
/// let fd_four = unsafe {BorrowedFd::borrow_raw(4)};
|
||||
/// let fd_nine = unsafe {BorrowedFd::borrow_raw(9)};
|
||||
/// set.insert(fd_four);
|
||||
/// set.insert(fd_nine);
|
||||
/// let fds: Vec<RawFd> = set.fds(None).map(|borrowed_fd|borrowed_fd.as_raw_fd()).collect();
|
||||
/// assert_eq!(fds, vec![4, 9]);
|
||||
/// ```
|
||||
#[inline]
|
||||
@@ -104,7 +115,7 @@ impl FdSet {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FdSet {
|
||||
impl Default for FdSet<'_> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
@@ -112,18 +123,19 @@ impl Default for FdSet {
|
||||
|
||||
/// Iterator over `FdSet`.
|
||||
#[derive(Debug)]
|
||||
pub struct Fds<'a> {
|
||||
set: &'a FdSet,
|
||||
pub struct Fds<'a, 'fd> {
|
||||
set: &'a FdSet<'fd>,
|
||||
range: Range<usize>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Fds<'a> {
|
||||
type Item = RawFd;
|
||||
impl<'fd> Iterator for Fds<'_, 'fd> {
|
||||
type Item = BorrowedFd<'fd>;
|
||||
|
||||
fn next(&mut self) -> Option<RawFd> {
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
for i in &mut self.range {
|
||||
if self.set.contains(i as RawFd) {
|
||||
return Some(i as RawFd);
|
||||
let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) };
|
||||
if self.set.contains(borrowed_i) {
|
||||
return Some(borrowed_i);
|
||||
}
|
||||
}
|
||||
None
|
||||
@@ -136,19 +148,20 @@ impl<'a> Iterator for Fds<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DoubleEndedIterator for Fds<'a> {
|
||||
impl<'fd> DoubleEndedIterator for Fds<'_, 'fd> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<RawFd> {
|
||||
fn next_back(&mut self) -> Option<BorrowedFd<'fd>> {
|
||||
while let Some(i) = self.range.next_back() {
|
||||
if self.set.contains(i as RawFd) {
|
||||
return Some(i as RawFd);
|
||||
let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) };
|
||||
if self.set.contains(borrowed_i) {
|
||||
return Some(borrowed_i);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FusedIterator for Fds<'a> {}
|
||||
impl FusedIterator for Fds<'_, '_> {}
|
||||
|
||||
/// Monitors file descriptors for readiness
|
||||
///
|
||||
@@ -173,7 +186,7 @@ impl<'a> FusedIterator for Fds<'a> {}
|
||||
/// [select(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html)
|
||||
///
|
||||
/// [`FdSet::highest`]: struct.FdSet.html#method.highest
|
||||
pub fn select<'a, N, R, W, E, T>(
|
||||
pub fn select<'a, 'fd, N, R, W, E, T>(
|
||||
nfds: N,
|
||||
readfds: R,
|
||||
writefds: W,
|
||||
@@ -181,10 +194,11 @@ pub fn select<'a, N, R, W, E, T>(
|
||||
timeout: T,
|
||||
) -> Result<c_int>
|
||||
where
|
||||
'fd: 'a,
|
||||
N: Into<Option<c_int>>,
|
||||
R: Into<Option<&'a mut FdSet>>,
|
||||
W: Into<Option<&'a mut FdSet>>,
|
||||
E: Into<Option<&'a mut FdSet>>,
|
||||
R: Into<Option<&'a mut FdSet<'fd>>>,
|
||||
W: Into<Option<&'a mut FdSet<'fd>>>,
|
||||
E: Into<Option<&'a mut FdSet<'fd>>>,
|
||||
T: Into<Option<&'a mut TimeVal>>,
|
||||
{
|
||||
let mut readfds = readfds.into();
|
||||
@@ -197,7 +211,11 @@ where
|
||||
.iter_mut()
|
||||
.chain(writefds.iter_mut())
|
||||
.chain(errorfds.iter_mut())
|
||||
.map(|set| set.highest().unwrap_or(-1))
|
||||
.map(|set| {
|
||||
set.highest()
|
||||
.map(|borrowed_fd| borrowed_fd.as_raw_fd())
|
||||
.unwrap_or(-1)
|
||||
})
|
||||
.max()
|
||||
.unwrap_or(-1)
|
||||
+ 1
|
||||
@@ -256,17 +274,18 @@ use crate::sys::signal::SigSet;
|
||||
/// [The new pselect() system call](https://lwn.net/Articles/176911/)
|
||||
///
|
||||
/// [`FdSet::highest`]: struct.FdSet.html#method.highest
|
||||
pub fn pselect<'a, N, R, W, E, T, S>(nfds: N,
|
||||
pub fn pselect<'a, 'fd, N, R, W, E, T, S>(nfds: N,
|
||||
readfds: R,
|
||||
writefds: W,
|
||||
errorfds: E,
|
||||
timeout: T,
|
||||
sigmask: S) -> Result<c_int>
|
||||
where
|
||||
'fd: 'a,
|
||||
N: Into<Option<c_int>>,
|
||||
R: Into<Option<&'a mut FdSet>>,
|
||||
W: Into<Option<&'a mut FdSet>>,
|
||||
E: Into<Option<&'a mut FdSet>>,
|
||||
R: Into<Option<&'a mut FdSet<'fd>>>,
|
||||
W: Into<Option<&'a mut FdSet<'fd>>>,
|
||||
E: Into<Option<&'a mut FdSet<'fd>>>,
|
||||
T: Into<Option<&'a TimeSpec>>,
|
||||
S: Into<Option<&'a SigSet>>,
|
||||
{
|
||||
@@ -280,7 +299,7 @@ where
|
||||
readfds.iter_mut()
|
||||
.chain(writefds.iter_mut())
|
||||
.chain(errorfds.iter_mut())
|
||||
.map(|set| set.highest().unwrap_or(-1))
|
||||
.map(|set| set.highest().map(|borrowed_fd|borrowed_fd.as_raw_fd()).unwrap_or(-1))
|
||||
.max()
|
||||
.unwrap_or(-1) + 1
|
||||
});
|
||||
@@ -298,158 +317,3 @@ where
|
||||
Errno::result(res)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::sys::time::{TimeVal, TimeValLike};
|
||||
use crate::unistd::{pipe, write};
|
||||
use std::os::unix::io::RawFd;
|
||||
|
||||
#[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));
|
||||
}
|
||||
}
|
||||
|
||||
+126
-52
@@ -1,7 +1,7 @@
|
||||
//! Send data from a file to a socket, bypassing userland.
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::os::unix::io::{AsFd, AsRawFd};
|
||||
use std::ptr;
|
||||
|
||||
use libc::{self, off_t};
|
||||
@@ -20,19 +20,26 @@ use crate::Result;
|
||||
///
|
||||
/// `in_fd` must support `mmap`-like operations and therefore cannot be a socket.
|
||||
///
|
||||
/// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html)
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn sendfile(
|
||||
out_fd: RawFd,
|
||||
in_fd: RawFd,
|
||||
/// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html) for Linux,
|
||||
/// see [the sendfile(2) man page.](https://docs.oracle.com/cd/E88353_01/html/E37843/sendfile-3c.html) for Solaris.
|
||||
#[cfg(any(linux_android, solarish))]
|
||||
pub fn sendfile<F1: AsFd, F2: AsFd>(
|
||||
out_fd: F1,
|
||||
in_fd: F2,
|
||||
offset: Option<&mut off_t>,
|
||||
count: usize,
|
||||
) -> Result<usize> {
|
||||
let offset = offset
|
||||
.map(|offset| offset as *mut _)
|
||||
.unwrap_or(ptr::null_mut());
|
||||
let ret = unsafe { libc::sendfile(out_fd, in_fd, offset, count) };
|
||||
let ret = unsafe {
|
||||
libc::sendfile(
|
||||
out_fd.as_fd().as_raw_fd(),
|
||||
in_fd.as_fd().as_raw_fd(),
|
||||
offset,
|
||||
count,
|
||||
)
|
||||
};
|
||||
Errno::result(ret).map(|r| r as usize)
|
||||
}
|
||||
|
||||
@@ -49,61 +56,103 @@ pub fn sendfile(
|
||||
///
|
||||
/// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html)
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn sendfile64(
|
||||
out_fd: RawFd,
|
||||
in_fd: RawFd,
|
||||
pub fn sendfile64<F1: AsFd, F2: AsFd>(
|
||||
out_fd: F1,
|
||||
in_fd: F2,
|
||||
offset: Option<&mut libc::off64_t>,
|
||||
count: usize,
|
||||
) -> Result<usize> {
|
||||
let offset = offset
|
||||
.map(|offset| offset as *mut _)
|
||||
.unwrap_or(ptr::null_mut());
|
||||
let ret = unsafe { libc::sendfile64(out_fd, in_fd, offset, count) };
|
||||
let ret = unsafe {
|
||||
libc::sendfile64(
|
||||
out_fd.as_fd().as_raw_fd(),
|
||||
in_fd.as_fd().as_raw_fd(),
|
||||
offset,
|
||||
count,
|
||||
)
|
||||
};
|
||||
Errno::result(ret).map(|r| r as usize)
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos"))] {
|
||||
if #[cfg(any(freebsdlike, apple_targets))] {
|
||||
use std::io::IoSlice;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct SendfileHeaderTrailer<'a>(
|
||||
libc::sf_hdtr,
|
||||
Option<Vec<IoSlice<'a>>>,
|
||||
Option<Vec<IoSlice<'a>>>,
|
||||
);
|
||||
struct SendfileHeaderTrailer<'a> {
|
||||
raw: libc::sf_hdtr,
|
||||
_headers: Option<Vec<IoSlice<'a>>>,
|
||||
_trailers: Option<Vec<IoSlice<'a>>>,
|
||||
}
|
||||
|
||||
impl<'a> SendfileHeaderTrailer<'a> {
|
||||
fn new(
|
||||
headers: Option<&'a [&'a [u8]]>,
|
||||
trailers: Option<&'a [&'a [u8]]>
|
||||
) -> SendfileHeaderTrailer<'a> {
|
||||
let header_iovecs: Option<Vec<IoSlice<'_>>> =
|
||||
let mut header_iovecs: Option<Vec<IoSlice<'_>>> =
|
||||
headers.map(|s| s.iter().map(|b| IoSlice::new(b)).collect());
|
||||
let trailer_iovecs: Option<Vec<IoSlice<'_>>> =
|
||||
let mut trailer_iovecs: Option<Vec<IoSlice<'_>>> =
|
||||
trailers.map(|s| s.iter().map(|b| IoSlice::new(b)).collect());
|
||||
SendfileHeaderTrailer(
|
||||
libc::sf_hdtr {
|
||||
|
||||
SendfileHeaderTrailer {
|
||||
raw: libc::sf_hdtr {
|
||||
headers: {
|
||||
header_iovecs
|
||||
.as_ref()
|
||||
.map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec
|
||||
.as_mut()
|
||||
.map_or(ptr::null_mut(), |v| v.as_mut_ptr())
|
||||
.cast()
|
||||
},
|
||||
hdr_cnt: header_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32,
|
||||
trailers: {
|
||||
trailer_iovecs
|
||||
.as_ref()
|
||||
.map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec
|
||||
.as_mut()
|
||||
.map_or(ptr::null_mut(), |v| v.as_mut_ptr())
|
||||
.cast()
|
||||
},
|
||||
trl_cnt: trailer_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32
|
||||
},
|
||||
header_iovecs,
|
||||
trailer_iovecs,
|
||||
)
|
||||
_headers: header_iovecs,
|
||||
_trailers: trailer_iovecs,
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if #[cfg(solarish)] {
|
||||
use std::os::unix::io::BorrowedFd;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
/// Mapping of the raw C sendfilevec_t struct
|
||||
pub struct SendfileVec<'fd> {
|
||||
raw: libc::sendfilevec_t,
|
||||
phantom: PhantomData<BorrowedFd<'fd>>
|
||||
}
|
||||
|
||||
impl<'fd> SendfileVec<'fd> {
|
||||
/// initialises SendfileVec to send data directly from the process's address space
|
||||
/// same in C with sfv_fd set to SFV_FD_SELF.
|
||||
pub fn newself(
|
||||
off: off_t,
|
||||
len: usize
|
||||
) -> Self {
|
||||
Self{raw: libc::sendfilevec_t{sfv_fd: libc::SFV_FD_SELF, sfv_flag: 0, sfv_off: off, sfv_len: len}, phantom: PhantomData}
|
||||
}
|
||||
|
||||
/// initialises SendfileVec to send data from `fd`.
|
||||
pub fn new(
|
||||
fd: BorrowedFd<'fd>,
|
||||
off: off_t,
|
||||
len: usize
|
||||
) -> SendfileVec<'fd> {
|
||||
Self{raw: libc::sendfilevec_t{sfv_fd: fd.as_raw_fd(), sfv_flag: 0, sfv_off:off, sfv_len: len}, phantom: PhantomData}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SendfileVec<'_>> for libc::sendfilevec_t {
|
||||
fn from<'fd>(vec: SendfileVec) -> libc::sendfilevec_t {
|
||||
vec.raw
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -156,9 +205,9 @@ cfg_if! {
|
||||
/// For more information, see
|
||||
/// [the sendfile(2) man page.](https://www.freebsd.org/cgi/man.cgi?query=sendfile&sektion=2)
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn sendfile(
|
||||
in_fd: RawFd,
|
||||
out_sock: RawFd,
|
||||
pub fn sendfile<F1: AsFd, F2: AsFd>(
|
||||
in_fd: F1,
|
||||
out_sock: F2,
|
||||
offset: off_t,
|
||||
count: Option<usize>,
|
||||
headers: Option<&[&[u8]]>,
|
||||
@@ -173,10 +222,10 @@ cfg_if! {
|
||||
let flags: u32 = (ra32 << 16) | (flags.bits() as u32);
|
||||
let mut bytes_sent: off_t = 0;
|
||||
let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers));
|
||||
let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr);
|
||||
let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.raw as *const libc::sf_hdtr);
|
||||
let return_code = unsafe {
|
||||
libc::sendfile(in_fd,
|
||||
out_sock,
|
||||
libc::sendfile(in_fd.as_fd().as_raw_fd(),
|
||||
out_sock.as_fd().as_raw_fd(),
|
||||
offset,
|
||||
count.unwrap_or(0),
|
||||
hdtr_ptr as *mut libc::sf_hdtr,
|
||||
@@ -206,9 +255,9 @@ cfg_if! {
|
||||
///
|
||||
/// For more information, see
|
||||
/// [the sendfile(2) man page.](https://leaf.dragonflybsd.org/cgi/web-man?command=sendfile§ion=2)
|
||||
pub fn sendfile(
|
||||
in_fd: RawFd,
|
||||
out_sock: RawFd,
|
||||
pub fn sendfile<F1: AsFd, F2: AsFd>(
|
||||
in_fd: F1,
|
||||
out_sock: F2,
|
||||
offset: off_t,
|
||||
count: Option<usize>,
|
||||
headers: Option<&[&[u8]]>,
|
||||
@@ -216,10 +265,10 @@ cfg_if! {
|
||||
) -> (Result<()>, off_t) {
|
||||
let mut bytes_sent: off_t = 0;
|
||||
let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers));
|
||||
let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr);
|
||||
let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.raw as *const libc::sf_hdtr);
|
||||
let return_code = unsafe {
|
||||
libc::sendfile(in_fd,
|
||||
out_sock,
|
||||
libc::sendfile(in_fd.as_fd().as_raw_fd(),
|
||||
out_sock.as_fd().as_raw_fd(),
|
||||
offset,
|
||||
count.unwrap_or(0),
|
||||
hdtr_ptr as *mut libc::sf_hdtr,
|
||||
@@ -228,7 +277,7 @@ cfg_if! {
|
||||
};
|
||||
(Errno::result(return_code).and(Ok(())), bytes_sent)
|
||||
}
|
||||
} else if #[cfg(any(target_os = "ios", target_os = "macos"))] {
|
||||
} else if #[cfg(apple_targets)] {
|
||||
/// Read bytes from `in_fd` starting at `offset` and write up to `count` bytes to
|
||||
/// `out_sock`.
|
||||
///
|
||||
@@ -252,9 +301,9 @@ cfg_if! {
|
||||
///
|
||||
/// For more information, see
|
||||
/// [the sendfile(2) man page.](https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man2/sendfile.2.html)
|
||||
pub fn sendfile(
|
||||
in_fd: RawFd,
|
||||
out_sock: RawFd,
|
||||
pub fn sendfile<F1: AsFd, F2: AsFd>(
|
||||
in_fd: F1,
|
||||
out_sock: F2,
|
||||
offset: off_t,
|
||||
count: Option<off_t>,
|
||||
headers: Option<&[&[u8]]>,
|
||||
@@ -262,10 +311,10 @@ cfg_if! {
|
||||
) -> (Result<()>, off_t) {
|
||||
let mut len = count.unwrap_or(0);
|
||||
let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers));
|
||||
let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr);
|
||||
let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.raw as *const libc::sf_hdtr);
|
||||
let return_code = unsafe {
|
||||
libc::sendfile(in_fd,
|
||||
out_sock,
|
||||
libc::sendfile(in_fd.as_fd().as_raw_fd(),
|
||||
out_sock.as_fd().as_raw_fd(),
|
||||
offset,
|
||||
&mut len as *mut off_t,
|
||||
hdtr_ptr as *mut libc::sf_hdtr,
|
||||
@@ -273,5 +322,30 @@ cfg_if! {
|
||||
};
|
||||
(Errno::result(return_code).and(Ok(())), len)
|
||||
}
|
||||
} else if #[cfg(solarish)] {
|
||||
/// Write data from the vec arrays to `out_sock` and returns a `Result` and a
|
||||
/// count of bytes written.
|
||||
///
|
||||
/// Each `SendfileVec` set needs to be instantiated either with `SendfileVec::new` or
|
||||
/// `SendfileVec::newself`.
|
||||
///
|
||||
/// The former allows to send data from a file descriptor through `fd`,
|
||||
/// from an offset `off` and for a given amount of data `len`.
|
||||
///
|
||||
/// The latter allows to send data from the process's address space, from an offset `off`
|
||||
/// and for a given amount of data `len`.
|
||||
///
|
||||
/// For more information, see
|
||||
/// [the sendfilev(3) man page.](https://illumos.org/man/3EXT/sendfilev)
|
||||
pub fn sendfilev<F: AsFd>(
|
||||
out_sock: F,
|
||||
vec: &[SendfileVec]
|
||||
) -> (Result<()>, usize) {
|
||||
let mut len = 0usize;
|
||||
let return_code = unsafe {
|
||||
libc::sendfilev(out_sock.as_fd().as_raw_fd(), vec.as_ptr() as *const libc::sendfilevec_t, vec.len() as i32, &mut len)
|
||||
};
|
||||
(Errno::result(return_code).and(Ok(())), len)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+435
-371
File diff suppressed because it is too large
Load Diff
+54
-55
@@ -17,12 +17,13 @@
|
||||
//! signal handlers.
|
||||
use crate::errno::Errno;
|
||||
pub use crate::sys::signal::{self, SigSet};
|
||||
use crate::unistd;
|
||||
use crate::Result;
|
||||
|
||||
/// Information of a received signal, the return type of [`SignalFd::read_signal()`].
|
||||
pub use libc::signalfd_siginfo as siginfo;
|
||||
|
||||
use std::mem;
|
||||
use std::os::unix::io::{AsRawFd, RawFd};
|
||||
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd};
|
||||
|
||||
libc_bitflags! {
|
||||
pub struct SfdFlags: libc::c_int {
|
||||
@@ -31,7 +32,6 @@ libc_bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
pub const SIGNALFD_NEW: RawFd = -1;
|
||||
#[deprecated(since = "0.23.0", note = "use mem::size_of::<siginfo>() instead")]
|
||||
pub const SIGNALFD_SIGINFO_SIZE: usize = mem::size_of::<siginfo>();
|
||||
|
||||
@@ -46,13 +46,24 @@ pub const SIGNALFD_SIGINFO_SIZE: usize = mem::size_of::<siginfo>();
|
||||
/// signalfd (the default handler will be invoked instead).
|
||||
///
|
||||
/// See [the signalfd man page for more information](https://man7.org/linux/man-pages/man2/signalfd.2.html)
|
||||
pub fn signalfd(fd: RawFd, mask: &SigSet, flags: SfdFlags) -> Result<RawFd> {
|
||||
#[deprecated(since = "0.27.0", note = "Use SignalFd instead")]
|
||||
pub fn signalfd<F: AsFd>(
|
||||
fd: Option<F>,
|
||||
mask: &SigSet,
|
||||
flags: SfdFlags,
|
||||
) -> Result<OwnedFd> {
|
||||
_signalfd(fd, mask, flags)
|
||||
}
|
||||
|
||||
fn _signalfd<F: AsFd>(
|
||||
fd: Option<F>,
|
||||
mask: &SigSet,
|
||||
flags: SfdFlags,
|
||||
) -> Result<OwnedFd> {
|
||||
let raw_fd = fd.map_or(-1, |x| x.as_fd().as_raw_fd());
|
||||
unsafe {
|
||||
Errno::result(libc::signalfd(
|
||||
fd as libc::c_int,
|
||||
mask.as_ref(),
|
||||
flags.bits(),
|
||||
))
|
||||
Errno::result(libc::signalfd(raw_fd, mask.as_ref(), flags.bits()))
|
||||
.map(|raw_fd| FromRawFd::from_raw_fd(raw_fd))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,8 +93,8 @@ pub fn signalfd(fd: RawFd, mask: &SigSet, flags: SfdFlags) -> Result<RawFd> {
|
||||
/// Err(err) => (), // some error happend
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug, Eq, Hash, PartialEq)]
|
||||
pub struct SignalFd(RawFd);
|
||||
#[derive(Debug)]
|
||||
pub struct SignalFd(OwnedFd);
|
||||
|
||||
impl SignalFd {
|
||||
pub fn new(mask: &SigSet) -> Result<SignalFd> {
|
||||
@@ -91,21 +102,21 @@ impl SignalFd {
|
||||
}
|
||||
|
||||
pub fn with_flags(mask: &SigSet, flags: SfdFlags) -> Result<SignalFd> {
|
||||
let fd = signalfd(SIGNALFD_NEW, mask, flags)?;
|
||||
let fd = _signalfd(None::<OwnedFd>, mask, flags)?;
|
||||
|
||||
Ok(SignalFd(fd))
|
||||
}
|
||||
|
||||
pub fn set_mask(&mut self, mask: &SigSet) -> Result<()> {
|
||||
signalfd(self.0, mask, SfdFlags::empty()).map(drop)
|
||||
pub fn set_mask(&self, mask: &SigSet) -> Result<()> {
|
||||
self.update(mask, SfdFlags::empty())
|
||||
}
|
||||
|
||||
pub fn read_signal(&mut self) -> Result<Option<siginfo>> {
|
||||
pub fn read_signal(&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)
|
||||
libc::read(self.0.as_raw_fd(), buffer.as_mut_ptr().cast(), size)
|
||||
})
|
||||
.map(|r| r as usize);
|
||||
match res {
|
||||
@@ -115,20 +126,39 @@ impl SignalFd {
|
||||
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!");
|
||||
};
|
||||
/// Constructs a `SignalFd` wrapping an existing `OwnedFd`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `OwnedFd` is a valid `SignalFd`.
|
||||
pub unsafe fn from_owned_fd(fd: OwnedFd) -> Self {
|
||||
Self(fd)
|
||||
}
|
||||
|
||||
fn update(&self, mask: &SigSet, flags: SfdFlags) -> Result<()> {
|
||||
let raw_fd = self.0.as_raw_fd();
|
||||
unsafe {
|
||||
Errno::result(libc::signalfd(raw_fd, mask.as_ref(), flags.bits()))
|
||||
.map(drop)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsFd for SignalFd {
|
||||
fn as_fd(&self) -> BorrowedFd {
|
||||
self.0.as_fd()
|
||||
}
|
||||
}
|
||||
impl AsRawFd for SignalFd {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SignalFd> for OwnedFd {
|
||||
fn from(value: SignalFd) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,34 +172,3 @@ impl Iterator for SignalFd {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn create_signalfd() {
|
||||
let mask = SigSet::empty();
|
||||
SignalFd::new(&mask).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_signalfd_with_opts() {
|
||||
let mask = SigSet::empty();
|
||||
SignalFd::with_flags(
|
||||
&mask,
|
||||
SfdFlags::SFD_CLOEXEC | SfdFlags::SFD_NONBLOCK,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_empty_signalfd() {
|
||||
let mask = SigSet::empty();
|
||||
let mut fd =
|
||||
SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap();
|
||||
|
||||
let res = fd.read_signal();
|
||||
assert!(res.unwrap().is_none());
|
||||
}
|
||||
}
|
||||
|
||||
+408
-1252
File diff suppressed because it is too large
Load Diff
+760
-685
File diff suppressed because it is too large
Load Diff
+853
-272
File diff suppressed because it is too large
Load Diff
+80
-74
@@ -1,20 +1,15 @@
|
||||
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))]
|
||||
#[cfg(any(apple_targets, target_os = "openbsd"))]
|
||||
pub use libc::c_uint;
|
||||
#[cfg(any(
|
||||
target_os = "netbsd",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly"
|
||||
))]
|
||||
#[cfg(any(target_os = "netbsd", freebsdlike))]
|
||||
pub use libc::c_ulong;
|
||||
pub use libc::stat as FileStat;
|
||||
pub use libc::{dev_t, mode_t};
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use crate::fcntl::{at_rawfd, AtFlags};
|
||||
use crate::fcntl::AtFlags;
|
||||
use crate::sys::time::{TimeSpec, TimeVal};
|
||||
use crate::{errno::Errno, NixPath, Result};
|
||||
use std::mem;
|
||||
use std::os::unix::io::RawFd;
|
||||
|
||||
libc_bitflags!(
|
||||
/// "File type" flags for `mknod` and related functions.
|
||||
@@ -43,7 +38,7 @@ libc_bitflags! {
|
||||
S_IXUSR;
|
||||
/// Read write and execute for group.
|
||||
S_IRWXG;
|
||||
/// Read fr group.
|
||||
/// Read for group.
|
||||
S_IRGRP;
|
||||
/// Write for group.
|
||||
S_IWGRP;
|
||||
@@ -65,26 +60,14 @@ libc_bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))]
|
||||
#[cfg(any(apple_targets, target_os = "openbsd"))]
|
||||
pub type type_of_file_flag = c_uint;
|
||||
#[cfg(any(
|
||||
target_os = "netbsd",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly"
|
||||
))]
|
||||
#[cfg(any(freebsdlike, target_os = "netbsd"))]
|
||||
pub type type_of_file_flag = c_ulong;
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "openbsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "macos",
|
||||
target_os = "ios"
|
||||
))]
|
||||
#[cfg(bsd)]
|
||||
libc_bitflags! {
|
||||
/// File flags.
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub struct FileFlag: type_of_file_flag {
|
||||
/// The file may only be appended to.
|
||||
SF_APPEND;
|
||||
@@ -101,7 +84,7 @@ libc_bitflags! {
|
||||
#[cfg(any(target_os = "dragonfly"))]
|
||||
SF_NOHISTORY;
|
||||
/// The file may not be renamed or deleted.
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
#[cfg(freebsdlike)]
|
||||
SF_NOUNLINK;
|
||||
/// Mask of superuser changeable flags
|
||||
SF_SETTABLE;
|
||||
@@ -121,14 +104,13 @@ libc_bitflags! {
|
||||
#[cfg(any(target_os = "dragonfly"))]
|
||||
UF_CACHE;
|
||||
/// File is compressed at the file system level.
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
#[cfg(apple_targets)]
|
||||
UF_COMPRESSED;
|
||||
/// The file may be hidden from directory listings at the application's
|
||||
/// discretion.
|
||||
#[cfg(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
apple_targets,
|
||||
))]
|
||||
UF_HIDDEN;
|
||||
/// The file may not be changed.
|
||||
@@ -138,7 +120,7 @@ libc_bitflags! {
|
||||
#[cfg(any(target_os = "dragonfly"))]
|
||||
UF_NOHISTORY;
|
||||
/// The file may not be renamed or deleted.
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
#[cfg(freebsdlike)]
|
||||
UF_NOUNLINK;
|
||||
/// The file is offline, or has the Windows and CIFS
|
||||
/// `FILE_ATTRIBUTE_OFFLINE` attribute.
|
||||
@@ -162,7 +144,7 @@ libc_bitflags! {
|
||||
#[cfg(any(target_os = "freebsd"))]
|
||||
UF_SYSTEM;
|
||||
/// File renames and deletes are tracked.
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
#[cfg(apple_targets)]
|
||||
UF_TRACKED;
|
||||
#[cfg(any(target_os = "dragonfly"))]
|
||||
UF_XLINK;
|
||||
@@ -177,32 +159,28 @@ pub fn mknod<P: ?Sized + NixPath>(
|
||||
dev: dev_t,
|
||||
) -> Result<()> {
|
||||
let res = path.with_nix_path(|cstr| unsafe {
|
||||
libc::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev)
|
||||
libc::mknod(cstr.as_ptr(), kind.bits() | perm.bits() as mode_t, dev)
|
||||
})?;
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
/// Create a special or ordinary file, relative to a given directory.
|
||||
#[cfg(not(any(
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "redox",
|
||||
target_os = "haiku"
|
||||
)))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn mknodat<P: ?Sized + NixPath>(
|
||||
dirfd: RawFd,
|
||||
#[cfg(not(any(apple_targets, target_os = "redox", target_os = "haiku")))]
|
||||
pub fn mknodat<Fd: std::os::fd::AsFd, P: ?Sized + NixPath>(
|
||||
dirfd: Fd,
|
||||
path: &P,
|
||||
kind: SFlag,
|
||||
perm: Mode,
|
||||
dev: dev_t,
|
||||
) -> Result<()> {
|
||||
use std::os::fd::AsRawFd;
|
||||
|
||||
let res = path.with_nix_path(|cstr| unsafe {
|
||||
libc::mknodat(
|
||||
dirfd,
|
||||
dirfd.as_fd().as_raw_fd(),
|
||||
cstr.as_ptr(),
|
||||
kind.bits | perm.bits() as mode_t,
|
||||
kind.bits() | perm.bits() as mode_t,
|
||||
dev,
|
||||
)
|
||||
})?;
|
||||
@@ -211,19 +189,16 @@ pub fn mknodat<P: ?Sized + NixPath>(
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub const fn major(dev: dev_t) -> u64 {
|
||||
((dev >> 32) & 0xffff_f000) | ((dev >> 8) & 0x0000_0fff)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub const fn minor(dev: dev_t) -> u64 {
|
||||
((dev >> 12) & 0xffff_ff00) | ((dev) & 0x0000_00ff)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub const fn makedev(major: u64, minor: u64) -> dev_t {
|
||||
((major & 0xffff_f000) << 32)
|
||||
| ((major & 0x0000_0fff) << 8)
|
||||
@@ -258,9 +233,11 @@ pub fn lstat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
|
||||
Ok(unsafe { dst.assume_init() })
|
||||
}
|
||||
|
||||
pub fn fstat(fd: RawFd) -> Result<FileStat> {
|
||||
pub fn fstat<Fd: std::os::fd::AsFd>(fd: Fd) -> Result<FileStat> {
|
||||
use std::os::fd::AsRawFd;
|
||||
|
||||
let mut dst = mem::MaybeUninit::uninit();
|
||||
let res = unsafe { libc::fstat(fd, dst.as_mut_ptr()) };
|
||||
let res = unsafe { libc::fstat(fd.as_fd().as_raw_fd(), dst.as_mut_ptr()) };
|
||||
|
||||
Errno::result(res)?;
|
||||
|
||||
@@ -268,16 +245,17 @@ pub fn fstat(fd: RawFd) -> Result<FileStat> {
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn fstatat<P: ?Sized + NixPath>(
|
||||
dirfd: RawFd,
|
||||
pub fn fstatat<Fd: std::os::fd::AsFd, P: ?Sized + NixPath>(
|
||||
dirfd: Fd,
|
||||
pathname: &P,
|
||||
f: AtFlags,
|
||||
) -> Result<FileStat> {
|
||||
use std::os::fd::AsRawFd;
|
||||
|
||||
let mut dst = mem::MaybeUninit::uninit();
|
||||
let res = pathname.with_nix_path(|cstr| unsafe {
|
||||
libc::fstatat(
|
||||
dirfd,
|
||||
dirfd.as_fd().as_raw_fd(),
|
||||
cstr.as_ptr(),
|
||||
dst.as_mut_ptr(),
|
||||
f.bits() as libc::c_int,
|
||||
@@ -294,8 +272,11 @@ pub fn fstatat<P: ?Sized + NixPath>(
|
||||
/// # 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) };
|
||||
pub fn fchmod<Fd: std::os::fd::AsFd>(fd: Fd, mode: Mode) -> Result<()> {
|
||||
use std::os::fd::AsRawFd;
|
||||
|
||||
let res =
|
||||
unsafe { libc::fchmod(fd.as_fd().as_raw_fd(), mode.bits() as mode_t) };
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
@@ -311,12 +292,12 @@ pub enum FchmodatFlags {
|
||||
///
|
||||
/// 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 `dirfd` is [`AT_FDCWD`](crate::fcntl::AT_FDCWD).
|
||||
///
|
||||
/// 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
|
||||
/// `fchmodat(AT_FDCWD, path, mode, FchmodatFlags::FollowSymlink)` is identical to
|
||||
/// a call `libc::chmod(path, mode)`. That's why `chmod` is unimplemented
|
||||
/// in the `nix` crate.
|
||||
///
|
||||
@@ -324,20 +305,21 @@ pub enum FchmodatFlags {
|
||||
///
|
||||
/// [fchmodat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html).
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn fchmodat<P: ?Sized + NixPath>(
|
||||
dirfd: Option<RawFd>,
|
||||
pub fn fchmodat<Fd: std::os::fd::AsFd, P: ?Sized + NixPath>(
|
||||
dirfd: Fd,
|
||||
path: &P,
|
||||
mode: Mode,
|
||||
flag: FchmodatFlags,
|
||||
) -> Result<()> {
|
||||
use std::os::fd::AsRawFd;
|
||||
|
||||
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),
|
||||
dirfd.as_fd().as_raw_fd(),
|
||||
cstr.as_ptr(),
|
||||
mode.bits() as mode_t,
|
||||
atflag.bits() as libc::c_int,
|
||||
@@ -383,12 +365,10 @@ pub fn utimes<P: ?Sized + NixPath>(
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
apple_targets,
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd"
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn lutimes<P: ?Sized + NixPath>(
|
||||
path: &P,
|
||||
atime: &TimeVal,
|
||||
@@ -404,13 +384,22 @@ pub fn lutimes<P: ?Sized + NixPath>(
|
||||
|
||||
/// Change the access and modification times of the file specified by a file descriptor.
|
||||
///
|
||||
/// If you want to set the timestamp to now, use `TimeSpec::UTIME_NOW`. Use
|
||||
/// `TimeSpec::UTIME_OMIT` if you don't want to change it.
|
||||
///
|
||||
/// # References
|
||||
///
|
||||
/// [futimens(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html).
|
||||
#[inline]
|
||||
pub fn futimens(fd: RawFd, atime: &TimeSpec, mtime: &TimeSpec) -> Result<()> {
|
||||
pub fn futimens<Fd: std::os::fd::AsFd>(
|
||||
fd: Fd,
|
||||
atime: &TimeSpec,
|
||||
mtime: &TimeSpec,
|
||||
) -> Result<()> {
|
||||
use std::os::fd::AsRawFd;
|
||||
|
||||
let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
|
||||
let res = unsafe { libc::futimens(fd, ×[0]) };
|
||||
let res = unsafe { libc::futimens(fd.as_fd().as_raw_fd(), ×[0]) };
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
@@ -427,27 +416,31 @@ pub enum UtimensatFlags {
|
||||
///
|
||||
/// 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 `dirfd` is [`AT_FDCWD`](crate::fcntl::AT_FDCWD).
|
||||
///
|
||||
/// 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
|
||||
/// `utimensat(AT_FDCWD, 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.
|
||||
///
|
||||
/// If you want to set the timestamp to now, use `TimeSpec::UTIME_NOW`. Use
|
||||
/// `TimeSpec::UTIME_OMIT` if you don't want to change it.
|
||||
///
|
||||
/// # References
|
||||
///
|
||||
/// [utimensat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimens.html).
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn utimensat<P: ?Sized + NixPath>(
|
||||
dirfd: Option<RawFd>,
|
||||
pub fn utimensat<Fd: std::os::fd::AsFd, P: ?Sized + NixPath>(
|
||||
dirfd: Fd,
|
||||
path: &P,
|
||||
atime: &TimeSpec,
|
||||
mtime: &TimeSpec,
|
||||
flag: UtimensatFlags,
|
||||
) -> Result<()> {
|
||||
use std::os::fd::AsRawFd;
|
||||
|
||||
let atflag = match flag {
|
||||
UtimensatFlags::FollowSymlink => AtFlags::empty(),
|
||||
UtimensatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
|
||||
@@ -455,7 +448,7 @@ pub fn utimensat<P: ?Sized + NixPath>(
|
||||
let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
|
||||
let res = path.with_nix_path(|cstr| unsafe {
|
||||
libc::utimensat(
|
||||
at_rawfd(dirfd),
|
||||
dirfd.as_fd().as_raw_fd(),
|
||||
cstr.as_ptr(),
|
||||
×[0],
|
||||
atflag.bits() as libc::c_int,
|
||||
@@ -465,15 +458,28 @@ pub fn utimensat<P: ?Sized + NixPath>(
|
||||
Errno::result(res).map(drop)
|
||||
}
|
||||
|
||||
/// Create a directory at the path specified by `dirfd` and `path`.
|
||||
///
|
||||
/// If `path` is a relative path, then it is interpreted relative to the directory
|
||||
/// referred to by the file descriptor `dirfd`. (One can use [`AT_FDCWD`][link] to
|
||||
/// specify the current working directory in `dirfd`). If `path` is absolute,
|
||||
/// then `dirfd` is ignored.
|
||||
///
|
||||
/// [link]: crate::fcntl::AT_FDCWD
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn mkdirat<P: ?Sized + NixPath>(
|
||||
fd: RawFd,
|
||||
pub fn mkdirat<Fd: std::os::fd::AsFd, P: ?Sized + NixPath>(
|
||||
dirfd: Fd,
|
||||
path: &P,
|
||||
mode: Mode,
|
||||
) -> Result<()> {
|
||||
use std::os::fd::AsRawFd;
|
||||
|
||||
let res = path.with_nix_path(|cstr| unsafe {
|
||||
libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t)
|
||||
libc::mkdirat(
|
||||
dirfd.as_fd().as_raw_fd(),
|
||||
cstr.as_ptr(),
|
||||
mode.bits() as mode_t,
|
||||
)
|
||||
})?;
|
||||
|
||||
Errno::result(res).map(drop)
|
||||
|
||||
+127
-289
@@ -1,24 +1,15 @@
|
||||
//! Get filesystem statistics, non-portably
|
||||
//!
|
||||
//! See [`statvfs`](crate::sys::statvfs) for a portable alternative.
|
||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||
#[cfg(not(any(linux_android, target_os = "cygwin")))]
|
||||
use std::ffi::CStr;
|
||||
use std::fmt::{self, Debug};
|
||||
use std::mem;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::os::unix::io::{AsFd, AsRawFd};
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
|
||||
#[cfg(all(
|
||||
feature = "mount",
|
||||
any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
)
|
||||
))]
|
||||
#[cfg(all(feature = "mount", bsd))]
|
||||
use crate::mount::MntFlags;
|
||||
#[cfg(target_os = "linux")]
|
||||
use crate::sys::statvfs::FsFlags;
|
||||
@@ -26,28 +17,29 @@ use crate::{errno::Errno, NixPath, Result};
|
||||
|
||||
/// Identifies a mounted file system
|
||||
#[cfg(target_os = "android")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub type fsid_t = libc::__fsid_t;
|
||||
/// Identifies a mounted file system
|
||||
#[cfg(not(target_os = "android"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(not(any(target_os = "android", target_os = "cygwin")))]
|
||||
pub type fsid_t = libc::fsid_t;
|
||||
/// Identifies a mounted file system
|
||||
#[cfg(target_os = "cygwin")]
|
||||
pub type fsid_t = libc::c_long;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] {
|
||||
if #[cfg(any(linux_android, target_os = "fuchsia"))] {
|
||||
type type_of_statfs = libc::statfs64;
|
||||
const LIBC_FSTATFS: unsafe extern fn
|
||||
const LIBC_FSTATFS: unsafe extern "C" fn
|
||||
(fd: libc::c_int, buf: *mut type_of_statfs) -> libc::c_int
|
||||
= libc::fstatfs64;
|
||||
const LIBC_STATFS: unsafe extern fn
|
||||
const LIBC_STATFS: unsafe extern "C" fn
|
||||
(path: *const libc::c_char, buf: *mut type_of_statfs) -> libc::c_int
|
||||
= libc::statfs64;
|
||||
} else {
|
||||
type type_of_statfs = libc::statfs;
|
||||
const LIBC_FSTATFS: unsafe extern fn
|
||||
const LIBC_FSTATFS: unsafe extern "C" fn
|
||||
(fd: libc::c_int, buf: *mut type_of_statfs) -> libc::c_int
|
||||
= libc::fstatfs;
|
||||
const LIBC_STATFS: unsafe extern fn
|
||||
const LIBC_STATFS: unsafe extern "C" fn
|
||||
(path: *const libc::c_char, buf: *mut type_of_statfs) -> libc::c_int
|
||||
= libc::statfs;
|
||||
}
|
||||
@@ -62,7 +54,11 @@ pub struct Statfs(type_of_statfs);
|
||||
type fs_type_t = u32;
|
||||
#[cfg(target_os = "android")]
|
||||
type fs_type_t = libc::c_ulong;
|
||||
#[cfg(all(target_os = "linux", target_arch = "s390x"))]
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
target_arch = "s390x",
|
||||
not(target_env = "musl")
|
||||
))]
|
||||
type fs_type_t = libc::c_uint;
|
||||
#[cfg(all(target_os = "linux", any(target_env = "musl", target_env = "ohos")))]
|
||||
type fs_type_t = libc::c_ulong;
|
||||
@@ -78,223 +74,224 @@ type fs_type_t = libc::c_int;
|
||||
))
|
||||
))]
|
||||
type fs_type_t = libc::__fsword_t;
|
||||
#[cfg(target_os = "cygwin")]
|
||||
type fs_type_t = libc::c_long;
|
||||
|
||||
/// 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", any(target_env = "musl", target_env = "ohos")),
|
||||
all(target_os = "linux", target_env = "musl"),
|
||||
all(target_os = "linux", target_env = "ohos"),
|
||||
all(
|
||||
target_os = "linux",
|
||||
not(any(target_arch = "s390x", target_env = "musl", target_env = "ohos"))
|
||||
not(any(target_arch = "s390x", target_env = "musl"))
|
||||
),
|
||||
target_os = "cygwin",
|
||||
))]
|
||||
#[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(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const ADFS_SUPER_MAGIC: FsType =
|
||||
FsType(libc::ADFS_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const AFFS_SUPER_MAGIC: FsType =
|
||||
FsType(libc::AFFS_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const AFS_SUPER_MAGIC: FsType = FsType(libc::AFS_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const AUTOFS_SUPER_MAGIC: FsType =
|
||||
FsType(libc::AUTOFS_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const BPF_FS_MAGIC: FsType = FsType(libc::BPF_FS_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const BTRFS_SUPER_MAGIC: FsType =
|
||||
FsType(libc::BTRFS_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const CGROUP2_SUPER_MAGIC: FsType =
|
||||
FsType(libc::CGROUP2_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const CGROUP_SUPER_MAGIC: FsType =
|
||||
FsType(libc::CGROUP_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const CODA_SUPER_MAGIC: FsType =
|
||||
FsType(libc::CODA_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const CRAMFS_MAGIC: FsType = FsType(libc::CRAMFS_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const DEBUGFS_MAGIC: FsType = FsType(libc::DEBUGFS_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const DEVPTS_SUPER_MAGIC: FsType =
|
||||
FsType(libc::DEVPTS_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const ECRYPTFS_SUPER_MAGIC: FsType =
|
||||
FsType(libc::ECRYPTFS_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const EFS_SUPER_MAGIC: FsType = FsType(libc::EFS_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const EXT2_SUPER_MAGIC: FsType =
|
||||
FsType(libc::EXT2_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const EXT3_SUPER_MAGIC: FsType =
|
||||
FsType(libc::EXT3_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const EXT4_SUPER_MAGIC: FsType =
|
||||
FsType(libc::EXT4_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const F2FS_SUPER_MAGIC: FsType =
|
||||
FsType(libc::F2FS_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const FUSE_SUPER_MAGIC: FsType =
|
||||
FsType(libc::FUSE_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const FUTEXFS_SUPER_MAGIC: FsType =
|
||||
FsType(libc::FUTEXFS_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const HOSTFS_SUPER_MAGIC: FsType =
|
||||
FsType(libc::HOSTFS_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const HPFS_SUPER_MAGIC: FsType =
|
||||
FsType(libc::HPFS_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const HUGETLBFS_MAGIC: FsType = FsType(libc::HUGETLBFS_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const ISOFS_SUPER_MAGIC: FsType =
|
||||
FsType(libc::ISOFS_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const JFFS2_SUPER_MAGIC: FsType =
|
||||
FsType(libc::JFFS2_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const MINIX2_SUPER_MAGIC2: FsType =
|
||||
FsType(libc::MINIX2_SUPER_MAGIC2 as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const MINIX2_SUPER_MAGIC: FsType =
|
||||
FsType(libc::MINIX2_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const MINIX3_SUPER_MAGIC: FsType =
|
||||
FsType(libc::MINIX3_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const MINIX_SUPER_MAGIC2: FsType =
|
||||
FsType(libc::MINIX_SUPER_MAGIC2 as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const MINIX_SUPER_MAGIC: FsType =
|
||||
FsType(libc::MINIX_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const MSDOS_SUPER_MAGIC: FsType =
|
||||
FsType(libc::MSDOS_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const NCP_SUPER_MAGIC: FsType = FsType(libc::NCP_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const NFS_SUPER_MAGIC: FsType = FsType(libc::NFS_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const NILFS_SUPER_MAGIC: FsType =
|
||||
FsType(libc::NILFS_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const OCFS2_SUPER_MAGIC: FsType =
|
||||
FsType(libc::OCFS2_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const OPENPROM_SUPER_MAGIC: FsType =
|
||||
FsType(libc::OPENPROM_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const OVERLAYFS_SUPER_MAGIC: FsType =
|
||||
FsType(libc::OVERLAYFS_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const PROC_SUPER_MAGIC: FsType =
|
||||
FsType(libc::PROC_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const QNX4_SUPER_MAGIC: FsType =
|
||||
FsType(libc::QNX4_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const QNX6_SUPER_MAGIC: FsType =
|
||||
FsType(libc::QNX6_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const RDTGROUP_SUPER_MAGIC: FsType =
|
||||
FsType(libc::RDTGROUP_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const REISERFS_SUPER_MAGIC: FsType =
|
||||
FsType(libc::REISERFS_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const SECURITYFS_MAGIC: FsType =
|
||||
FsType(libc::SECURITYFS_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const SELINUX_MAGIC: FsType = FsType(libc::SELINUX_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const SMACK_MAGIC: FsType = FsType(libc::SMACK_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const SMB_SUPER_MAGIC: FsType = FsType(libc::SMB_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const SYSFS_MAGIC: FsType = FsType(libc::SYSFS_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const TMPFS_MAGIC: FsType = FsType(libc::TMPFS_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const TRACEFS_MAGIC: FsType = FsType(libc::TRACEFS_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const UDF_SUPER_MAGIC: FsType = FsType(libc::UDF_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const USBDEVICE_SUPER_MAGIC: FsType =
|
||||
FsType(libc::USBDEVICE_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const XENFS_SUPER_MAGIC: FsType =
|
||||
FsType(libc::XENFS_SUPER_MAGIC as fs_type_t);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[allow(missing_docs)]
|
||||
pub const NSFS_MAGIC: FsType = FsType(libc::NSFS_MAGIC as fs_type_t);
|
||||
#[cfg(all(
|
||||
any(target_os = "linux", target_os = "android"),
|
||||
not(any(target_env = "musl", target_env = "ohos"))
|
||||
))]
|
||||
#[cfg(all(linux_android, not(target_env = "musl"), not(target_env = "ohos")))]
|
||||
#[allow(missing_docs)]
|
||||
pub const XFS_SUPER_MAGIC: FsType = FsType(libc::XFS_SUPER_MAGIC as fs_type_t);
|
||||
|
||||
@@ -303,39 +300,37 @@ impl Statfs {
|
||||
#[cfg(not(any(
|
||||
target_os = "openbsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "ios",
|
||||
target_os = "macos"
|
||||
apple_targets,
|
||||
)))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn filesystem_type(&self) -> FsType {
|
||||
FsType(self.0.f_type)
|
||||
}
|
||||
|
||||
/// Magic code defining system type
|
||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(not(any(linux_android, target_os = "cygwin")))]
|
||||
pub fn filesystem_type_name(&self) -> &str {
|
||||
let c_str = unsafe { CStr::from_ptr(self.0.f_fstypename.as_ptr()) };
|
||||
c_str.to_str().unwrap()
|
||||
}
|
||||
|
||||
/// Optimal transfer block size
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(apple_targets)]
|
||||
pub fn optimal_transfer_size(&self) -> i32 {
|
||||
self.0.f_iosize
|
||||
}
|
||||
|
||||
/// Optimal transfer block size
|
||||
#[cfg(target_os = "openbsd")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn optimal_transfer_size(&self) -> u32 {
|
||||
self.0.f_iosize
|
||||
}
|
||||
|
||||
/// Optimal transfer block size
|
||||
#[cfg(all(target_os = "linux", target_arch = "s390x"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
target_arch = "s390x",
|
||||
not(target_env = "musl")
|
||||
))]
|
||||
pub fn optimal_transfer_size(&self) -> u32 {
|
||||
self.0.f_bsize
|
||||
}
|
||||
@@ -343,9 +338,9 @@ impl Statfs {
|
||||
/// Optimal transfer block size
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
all(target_os = "linux", any(target_env = "musl", target_env = "ohos"))
|
||||
all(target_os = "linux", target_env = "musl"),
|
||||
all(target_os = "linux", target_env = "ohos")
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn optimal_transfer_size(&self) -> libc::c_ulong {
|
||||
self.0.f_bsize
|
||||
}
|
||||
@@ -360,51 +355,55 @@ impl Statfs {
|
||||
target_env = "uclibc"
|
||||
))
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn optimal_transfer_size(&self) -> libc::__fsword_t {
|
||||
self.0.f_bsize
|
||||
}
|
||||
|
||||
/// Optimal transfer block size
|
||||
#[cfg(all(target_os = "linux", target_env = "uclibc"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn optimal_transfer_size(&self) -> libc::c_int {
|
||||
self.0.f_bsize
|
||||
}
|
||||
|
||||
/// Optimal transfer block size
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn optimal_transfer_size(&self) -> libc::c_long {
|
||||
self.0.f_iosize
|
||||
}
|
||||
|
||||
/// Optimal transfer block size
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn optimal_transfer_size(&self) -> u64 {
|
||||
self.0.f_iosize
|
||||
}
|
||||
|
||||
/// Size of a block
|
||||
#[cfg(any(target_os = "ios", target_os = "macos", target_os = "openbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(apple_targets, target_os = "openbsd"))]
|
||||
pub fn block_size(&self) -> u32 {
|
||||
self.0.f_bsize
|
||||
}
|
||||
|
||||
/// Size of a block
|
||||
// f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
|
||||
#[cfg(all(target_os = "linux", target_arch = "s390x"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
target_arch = "s390x",
|
||||
not(target_env = "musl")
|
||||
))]
|
||||
pub fn block_size(&self) -> u32 {
|
||||
self.0.f_bsize
|
||||
}
|
||||
|
||||
/// 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", any(target_env = "musl", target_env = "ohos")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[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", target_env = "ohos"))]
|
||||
pub fn block_size(&self) -> libc::c_ulong {
|
||||
self.0.f_bsize
|
||||
}
|
||||
@@ -412,7 +411,6 @@ impl Statfs {
|
||||
/// Size of a block
|
||||
// f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
|
||||
#[cfg(all(target_os = "linux", target_env = "uclibc"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn block_size(&self) -> libc::c_int {
|
||||
self.0.f_bsize
|
||||
}
|
||||
@@ -428,44 +426,30 @@ impl Statfs {
|
||||
target_env = "uclibc"
|
||||
))
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn block_size(&self) -> libc::__fsword_t {
|
||||
self.0.f_bsize
|
||||
}
|
||||
|
||||
/// Size of a block
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn block_size(&self) -> u64 {
|
||||
self.0.f_bsize
|
||||
}
|
||||
|
||||
/// Size of a block
|
||||
#[cfg(target_os = "android")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn block_size(&self) -> libc::c_ulong {
|
||||
self.0.f_bsize
|
||||
}
|
||||
|
||||
/// Size of a block
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "cygwin"))]
|
||||
pub fn block_size(&self) -> libc::c_long {
|
||||
self.0.f_bsize
|
||||
}
|
||||
|
||||
/// Get the mount flags
|
||||
#[cfg(all(
|
||||
feature = "mount",
|
||||
any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
)
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(all(feature = "mount", bsd))]
|
||||
#[allow(clippy::unnecessary_cast)] // Not unnecessary on all arches
|
||||
pub fn flags(&self) -> MntFlags {
|
||||
MntFlags::from_bits_truncate(self.0.f_flags as i32)
|
||||
@@ -475,35 +459,34 @@ impl Statfs {
|
||||
// The f_flags field exists on Android and Fuchsia too, but without man
|
||||
// pages I can't tell if it can be cast to FsFlags.
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn flags(&self) -> FsFlags {
|
||||
FsFlags::from_bits_truncate(self.0.f_flags as libc::c_ulong)
|
||||
}
|
||||
|
||||
/// Maximum length of filenames
|
||||
#[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn maximum_name_length(&self) -> u32 {
|
||||
self.0.f_namemax
|
||||
}
|
||||
|
||||
/// Maximum length of filenames
|
||||
#[cfg(all(target_os = "linux", target_arch = "s390x"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
target_arch = "s390x",
|
||||
not(target_env = "musl")
|
||||
))]
|
||||
pub fn maximum_name_length(&self) -> u32 {
|
||||
self.0.f_namelen
|
||||
}
|
||||
|
||||
/// Maximum length of filenames
|
||||
#[cfg(all(target_os = "linux", any(target_env = "musl", target_env = "ohos")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[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", target_env = "uclibc"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn maximum_name_length(&self) -> libc::c_int {
|
||||
self.0.f_namelen
|
||||
}
|
||||
@@ -518,170 +501,137 @@ impl Statfs {
|
||||
target_env = "uclibc"
|
||||
))
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn maximum_name_length(&self) -> libc::__fsword_t {
|
||||
self.0.f_namelen
|
||||
}
|
||||
|
||||
/// Maximum length of filenames
|
||||
#[cfg(target_os = "android")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn maximum_name_length(&self) -> libc::c_ulong {
|
||||
self.0.f_namelen
|
||||
}
|
||||
|
||||
/// Total data blocks in filesystem
|
||||
#[cfg(any(
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "android",
|
||||
apple_targets,
|
||||
linux_android,
|
||||
target_os = "freebsd",
|
||||
target_os = "fuchsia",
|
||||
target_os = "openbsd",
|
||||
target_os = "linux",
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn blocks(&self) -> u64 {
|
||||
self.0.f_blocks
|
||||
}
|
||||
|
||||
/// Total data blocks in filesystem
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "cygwin"))]
|
||||
pub fn blocks(&self) -> libc::c_long {
|
||||
self.0.f_blocks
|
||||
}
|
||||
|
||||
/// Total data blocks in filesystem
|
||||
#[cfg(target_os = "emscripten")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn blocks(&self) -> u32 {
|
||||
self.0.f_blocks
|
||||
}
|
||||
|
||||
/// Free blocks in filesystem
|
||||
#[cfg(any(
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "android",
|
||||
apple_targets,
|
||||
linux_android,
|
||||
target_os = "freebsd",
|
||||
target_os = "fuchsia",
|
||||
target_os = "openbsd",
|
||||
target_os = "linux",
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn blocks_free(&self) -> u64 {
|
||||
self.0.f_bfree
|
||||
}
|
||||
|
||||
/// Free blocks in filesystem
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "cygwin"))]
|
||||
pub fn blocks_free(&self) -> libc::c_long {
|
||||
self.0.f_bfree
|
||||
}
|
||||
|
||||
/// Free blocks in filesystem
|
||||
#[cfg(target_os = "emscripten")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn blocks_free(&self) -> u32 {
|
||||
self.0.f_bfree
|
||||
}
|
||||
|
||||
/// Free blocks available to unprivileged user
|
||||
#[cfg(any(
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "android",
|
||||
target_os = "fuchsia",
|
||||
target_os = "linux",
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(apple_targets, linux_android, target_os = "fuchsia"))]
|
||||
pub fn blocks_available(&self) -> u64 {
|
||||
self.0.f_bavail
|
||||
}
|
||||
|
||||
/// Free blocks available to unprivileged user
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "cygwin"))]
|
||||
pub fn blocks_available(&self) -> libc::c_long {
|
||||
self.0.f_bavail
|
||||
}
|
||||
|
||||
/// Free blocks available to unprivileged user
|
||||
#[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn blocks_available(&self) -> i64 {
|
||||
self.0.f_bavail
|
||||
}
|
||||
|
||||
/// Free blocks available to unprivileged user
|
||||
#[cfg(target_os = "emscripten")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn blocks_available(&self) -> u32 {
|
||||
self.0.f_bavail
|
||||
}
|
||||
|
||||
/// Total file nodes in filesystem
|
||||
#[cfg(any(
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "android",
|
||||
apple_targets,
|
||||
linux_android,
|
||||
target_os = "freebsd",
|
||||
target_os = "fuchsia",
|
||||
target_os = "openbsd",
|
||||
target_os = "linux",
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn files(&self) -> u64 {
|
||||
self.0.f_files
|
||||
}
|
||||
|
||||
/// Total file nodes in filesystem
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "cygwin"))]
|
||||
pub fn files(&self) -> libc::c_long {
|
||||
self.0.f_files
|
||||
}
|
||||
|
||||
/// Total file nodes in filesystem
|
||||
#[cfg(target_os = "emscripten")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn files(&self) -> u32 {
|
||||
self.0.f_files
|
||||
}
|
||||
|
||||
/// Free file nodes in filesystem
|
||||
#[cfg(any(
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "android",
|
||||
apple_targets,
|
||||
linux_android,
|
||||
target_os = "fuchsia",
|
||||
target_os = "openbsd",
|
||||
target_os = "linux",
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn files_free(&self) -> u64 {
|
||||
self.0.f_ffree
|
||||
}
|
||||
|
||||
/// Free file nodes in filesystem
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "cygwin"))]
|
||||
pub fn files_free(&self) -> libc::c_long {
|
||||
self.0.f_ffree
|
||||
}
|
||||
|
||||
/// Free file nodes in filesystem
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn files_free(&self) -> i64 {
|
||||
self.0.f_ffree
|
||||
}
|
||||
|
||||
/// Free file nodes in filesystem
|
||||
#[cfg(target_os = "emscripten")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn files_free(&self) -> u32 {
|
||||
self.0.f_ffree
|
||||
}
|
||||
@@ -695,6 +645,7 @@ impl Statfs {
|
||||
impl Debug for Statfs {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut ds = f.debug_struct("Statfs");
|
||||
#[cfg(not(target_os = "cygwin"))]
|
||||
ds.field("optimal_transfer_size", &self.optimal_transfer_size());
|
||||
ds.field("block_size", &self.block_size());
|
||||
ds.field("blocks", &self.blocks());
|
||||
@@ -703,16 +654,7 @@ impl Debug for Statfs {
|
||||
ds.field("files", &self.files());
|
||||
ds.field("files_free", &self.files_free());
|
||||
ds.field("filesystem_id", &self.filesystem_id());
|
||||
#[cfg(all(
|
||||
feature = "mount",
|
||||
any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
)
|
||||
))]
|
||||
#[cfg(all(feature = "mount", bsd))]
|
||||
ds.field("flags", &self.flags());
|
||||
ds.finish()
|
||||
}
|
||||
@@ -744,114 +686,10 @@ pub fn statfs<P: ?Sized + NixPath>(path: &P) -> Result<Statfs> {
|
||||
/// # Arguments
|
||||
///
|
||||
/// `fd` - File descriptor of any open file within the file system to describe
|
||||
pub fn fstatfs<T: AsRawFd>(fd: &T) -> Result<Statfs> {
|
||||
pub fn fstatfs<Fd: AsFd>(fd: Fd) -> Result<Statfs> {
|
||||
unsafe {
|
||||
let mut stat = mem::MaybeUninit::<type_of_statfs>::uninit();
|
||||
Errno::result(LIBC_FSTATFS(fd.as_raw_fd(), stat.as_mut_ptr()))
|
||||
Errno::result(LIBC_FSTATFS(fd.as_fd().as_raw_fd(), stat.as_mut_ptr()))
|
||||
.map(|_| Statfs(stat.assume_init()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::fs::File;
|
||||
|
||||
use crate::sys::statfs::*;
|
||||
use crate::sys::statvfs::*;
|
||||
use std::path::Path;
|
||||
|
||||
#[test]
|
||||
fn statfs_call() {
|
||||
check_statfs("/tmp");
|
||||
check_statfs("/dev");
|
||||
check_statfs("/run");
|
||||
check_statfs("/");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fstatfs_call() {
|
||||
check_fstatfs("/tmp");
|
||||
check_fstatfs("/dev");
|
||||
check_fstatfs("/run");
|
||||
check_fstatfs("/");
|
||||
}
|
||||
|
||||
fn check_fstatfs(path: &str) {
|
||||
if !Path::new(path).exists() {
|
||||
return;
|
||||
}
|
||||
let vfs = statvfs(path.as_bytes()).unwrap();
|
||||
let file = File::open(path).unwrap();
|
||||
let fs = fstatfs(&file).unwrap();
|
||||
assert_fs_equals(fs, vfs);
|
||||
}
|
||||
|
||||
fn check_statfs(path: &str) {
|
||||
if !Path::new(path).exists() {
|
||||
return;
|
||||
}
|
||||
let vfs = statvfs(path.as_bytes()).unwrap();
|
||||
let fs = statfs(path.as_bytes()).unwrap();
|
||||
assert_fs_equals(fs, vfs);
|
||||
}
|
||||
|
||||
// The cast is not unnecessary on all platforms.
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
fn assert_fs_equals(fs: Statfs, vfs: Statvfs) {
|
||||
assert_eq!(fs.files() as u64, vfs.files() as u64);
|
||||
assert_eq!(fs.blocks() as u64, vfs.blocks() as u64);
|
||||
assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64);
|
||||
}
|
||||
|
||||
// This test is ignored because files_free/blocks_free can change after statvfs call and before
|
||||
// statfs call.
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn statfs_call_strict() {
|
||||
check_statfs_strict("/tmp");
|
||||
check_statfs_strict("/dev");
|
||||
check_statfs_strict("/run");
|
||||
check_statfs_strict("/");
|
||||
}
|
||||
|
||||
// This test is ignored because files_free/blocks_free can change after statvfs call and before
|
||||
// fstatfs call.
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn fstatfs_call_strict() {
|
||||
check_fstatfs_strict("/tmp");
|
||||
check_fstatfs_strict("/dev");
|
||||
check_fstatfs_strict("/run");
|
||||
check_fstatfs_strict("/");
|
||||
}
|
||||
|
||||
fn check_fstatfs_strict(path: &str) {
|
||||
if !Path::new(path).exists() {
|
||||
return;
|
||||
}
|
||||
let vfs = statvfs(path.as_bytes());
|
||||
let file = File::open(path).unwrap();
|
||||
let fs = fstatfs(&file);
|
||||
assert_fs_equals_strict(fs.unwrap(), vfs.unwrap())
|
||||
}
|
||||
|
||||
fn check_statfs_strict(path: &str) {
|
||||
if !Path::new(path).exists() {
|
||||
return;
|
||||
}
|
||||
let vfs = statvfs(path.as_bytes());
|
||||
let fs = statfs(path.as_bytes());
|
||||
assert_fs_equals_strict(fs.unwrap(), vfs.unwrap())
|
||||
}
|
||||
|
||||
// The cast is not unnecessary on all platforms.
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
fn assert_fs_equals_strict(fs: Statfs, vfs: Statvfs) {
|
||||
assert_eq!(fs.files_free() as u64, vfs.files_free() as u64);
|
||||
assert_eq!(fs.blocks_free() as u64, vfs.blocks_free() as u64);
|
||||
assert_eq!(fs.blocks_available() as u64, vfs.blocks_available() as u64);
|
||||
assert_eq!(fs.files() as u64, vfs.files() as u64);
|
||||
assert_eq!(fs.blocks() as u64, vfs.blocks() as u64);
|
||||
assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64);
|
||||
}
|
||||
}
|
||||
|
||||
+16
-39
@@ -3,7 +3,7 @@
|
||||
//! See [the man pages](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatvfs.html)
|
||||
//! for more details.
|
||||
use std::mem;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::os::unix::io::{AsFd, AsRawFd};
|
||||
|
||||
use libc::{self, c_ulong};
|
||||
|
||||
@@ -12,7 +12,6 @@ use crate::{errno::Errno, NixPath, Result};
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
libc_bitflags!(
|
||||
/// File system mount Flags
|
||||
#[repr(C)]
|
||||
#[derive(Default)]
|
||||
pub struct FsFlags: c_ulong {
|
||||
/// Read Only
|
||||
@@ -22,44 +21,34 @@ libc_bitflags!(
|
||||
#[cfg(not(target_os = "haiku"))]
|
||||
ST_NOSUID;
|
||||
/// Do not interpret character or block-special devices
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
ST_NODEV;
|
||||
/// Do not allow execution of binaries on the filesystem
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
ST_NOEXEC;
|
||||
/// All IO should be done synchronously
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
ST_SYNCHRONOUS;
|
||||
/// Allow mandatory locks on the filesystem
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
ST_MANDLOCK;
|
||||
/// Write on file/directory/symlink
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
ST_WRITE;
|
||||
/// Append-only file
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
ST_APPEND;
|
||||
/// Immutable file
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
ST_IMMUTABLE;
|
||||
/// Do not update access times on files
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
ST_NOATIME;
|
||||
/// Do not update access times on files
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
ST_NODIRATIME;
|
||||
/// Update access time relative to modify/change time
|
||||
#[cfg(any(target_os = "android", all(target_os = "linux", not(any(target_env = "musl", target_env = "ohos")))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(target_os = "android", all(target_os = "linux", not(target_env = "musl"), not(target_env = "ohos"))))]
|
||||
ST_RELATIME;
|
||||
}
|
||||
);
|
||||
@@ -115,13 +104,18 @@ impl Statvfs {
|
||||
}
|
||||
|
||||
/// Get the file system id
|
||||
#[cfg(not(target_os = "hurd"))]
|
||||
pub fn filesystem_id(&self) -> c_ulong {
|
||||
self.0.f_fsid
|
||||
}
|
||||
/// Get the file system id
|
||||
#[cfg(target_os = "hurd")]
|
||||
pub fn filesystem_id(&self) -> u64 {
|
||||
self.0.f_fsid
|
||||
}
|
||||
|
||||
/// Get the mount flags
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn flags(&self) -> FsFlags {
|
||||
FsFlags::from_bits_truncate(self.0.f_flag)
|
||||
}
|
||||
@@ -146,28 +140,11 @@ pub fn statvfs<P: ?Sized + NixPath>(path: &P) -> Result<Statvfs> {
|
||||
}
|
||||
|
||||
/// Return a `Statvfs` object with information about `fd`
|
||||
pub fn fstatvfs<T: AsRawFd>(fd: &T) -> Result<Statvfs> {
|
||||
pub fn fstatvfs<Fd: AsFd>(fd: Fd) -> Result<Statvfs> {
|
||||
unsafe {
|
||||
Errno::clear();
|
||||
let mut stat = mem::MaybeUninit::<libc::statvfs>::uninit();
|
||||
Errno::result(libc::fstatvfs(fd.as_raw_fd(), stat.as_mut_ptr()))
|
||||
Errno::result(libc::fstatvfs(fd.as_fd().as_raw_fd(), stat.as_mut_ptr()))
|
||||
.map(|_| Statvfs(stat.assume_init()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::sys::statvfs::*;
|
||||
use std::fs::File;
|
||||
|
||||
#[test]
|
||||
fn statvfs_call() {
|
||||
statvfs(&b"/"[..]).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fstatvfs_call() {
|
||||
let root = File::open("/").unwrap();
|
||||
fstatvfs(&root).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
use libc::{self, SI_LOAD_SHIFT};
|
||||
use libc::SI_LOAD_SHIFT;
|
||||
use std::time::Duration;
|
||||
use std::{cmp, mem};
|
||||
|
||||
|
||||
+162
-464
@@ -85,28 +85,8 @@
|
||||
//!
|
||||
//! On non-BSDs, `cfgetispeed()` and `cfgetospeed()` both return a `BaudRate`:
|
||||
//!
|
||||
#![cfg_attr(
|
||||
any(
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
),
|
||||
doc = " ```rust,ignore"
|
||||
)]
|
||||
#![cfg_attr(
|
||||
not(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
)),
|
||||
doc = " ```rust"
|
||||
)]
|
||||
#![cfg_attr(bsd, doc = " ```rust,ignore")]
|
||||
#![cfg_attr(not(bsd), doc = " ```rust")]
|
||||
//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios};
|
||||
//! # fn main() {
|
||||
//! # let mut t: Termios = unsafe { std::mem::zeroed() };
|
||||
@@ -118,28 +98,8 @@
|
||||
//!
|
||||
//! But on the BSDs, `cfgetispeed()` and `cfgetospeed()` both return `u32`s:
|
||||
//!
|
||||
#![cfg_attr(
|
||||
any(
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
),
|
||||
doc = " ```rust"
|
||||
)]
|
||||
#![cfg_attr(
|
||||
not(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
)),
|
||||
doc = " ```rust,ignore"
|
||||
)]
|
||||
#![cfg_attr(bsd, doc = " ```rust")]
|
||||
#![cfg_attr(not(bsd), doc = " ```rust,ignore")]
|
||||
//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios};
|
||||
//! # fn main() {
|
||||
//! # let mut t: Termios = unsafe { std::mem::zeroed() };
|
||||
@@ -151,28 +111,8 @@
|
||||
//!
|
||||
//! It's trivial to convert from a `BaudRate` to a `u32` on BSDs:
|
||||
//!
|
||||
#![cfg_attr(
|
||||
any(
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
),
|
||||
doc = " ```rust"
|
||||
)]
|
||||
#![cfg_attr(
|
||||
not(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
)),
|
||||
doc = " ```rust,ignore"
|
||||
)]
|
||||
#![cfg_attr(bsd, doc = " ```rust")]
|
||||
#![cfg_attr(not(bsd), doc = " ```rust,ignore")]
|
||||
//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfsetspeed, Termios};
|
||||
//! # fn main() {
|
||||
//! # let mut t: Termios = unsafe { std::mem::zeroed() };
|
||||
@@ -185,28 +125,8 @@
|
||||
//! And on BSDs you can specify arbitrary baud rates (**note** this depends on hardware support)
|
||||
//! by specifying baud rates directly using `u32`s:
|
||||
//!
|
||||
#![cfg_attr(
|
||||
any(
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
),
|
||||
doc = " ```rust"
|
||||
)]
|
||||
#![cfg_attr(
|
||||
not(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
)),
|
||||
doc = " ```rust,ignore"
|
||||
)]
|
||||
#![cfg_attr(bsd, doc = " ```rust")]
|
||||
#![cfg_attr(not(bsd), doc = " ```rust,ignore")]
|
||||
//! # use nix::sys::termios::{cfsetispeed, cfsetospeed, cfsetspeed, Termios};
|
||||
//! # fn main() {
|
||||
//! # let mut t: Termios = unsafe { std::mem::zeroed() };
|
||||
@@ -222,7 +142,7 @@ use libc::{self, c_int, tcflag_t};
|
||||
use std::cell::{Ref, RefCell};
|
||||
use std::convert::From;
|
||||
use std::mem;
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::os::unix::io::{AsFd, AsRawFd};
|
||||
|
||||
#[cfg(feature = "process")]
|
||||
use crate::unistd::Pid;
|
||||
@@ -246,7 +166,7 @@ pub struct Termios {
|
||||
/// Control characters (see `termios.c_cc` documentation)
|
||||
pub control_chars: [libc::cc_t; NCCS],
|
||||
/// Line discipline (see `termios.c_line` documentation)
|
||||
#[cfg(any(target_os = "linux", target_os = "android",))]
|
||||
#[cfg(linux_android)]
|
||||
pub line_discipline: libc::cc_t,
|
||||
/// Line discipline (see `termios.c_line` documentation)
|
||||
#[cfg(target_os = "haiku")]
|
||||
@@ -266,11 +186,7 @@ impl Termios {
|
||||
termios.c_cflag = self.control_flags.bits();
|
||||
termios.c_lflag = self.local_flags.bits();
|
||||
termios.c_cc = self.control_chars;
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "haiku",
|
||||
))]
|
||||
#[cfg(any(linux_android, target_os = "haiku"))]
|
||||
{
|
||||
termios.c_line = self.line_discipline;
|
||||
}
|
||||
@@ -292,11 +208,7 @@ impl Termios {
|
||||
termios.c_cflag = self.control_flags.bits();
|
||||
termios.c_lflag = self.local_flags.bits();
|
||||
termios.c_cc = self.control_chars;
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "haiku",
|
||||
))]
|
||||
#[cfg(any(linux_android, target_os = "haiku"))]
|
||||
{
|
||||
termios.c_line = self.line_discipline;
|
||||
}
|
||||
@@ -309,14 +221,10 @@ impl Termios {
|
||||
let termios = *self.inner.borrow_mut();
|
||||
self.input_flags = InputFlags::from_bits_truncate(termios.c_iflag);
|
||||
self.output_flags = OutputFlags::from_bits_truncate(termios.c_oflag);
|
||||
self.control_flags = ControlFlags::from_bits_truncate(termios.c_cflag);
|
||||
self.control_flags = ControlFlags::from_bits_retain(termios.c_cflag);
|
||||
self.local_flags = LocalFlags::from_bits_truncate(termios.c_lflag);
|
||||
self.control_chars = termios.c_cc;
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "haiku",
|
||||
))]
|
||||
#[cfg(any(linux_android, target_os = "haiku"))]
|
||||
{
|
||||
self.line_discipline = termios.c_line;
|
||||
}
|
||||
@@ -332,11 +240,7 @@ impl From<libc::termios> for Termios {
|
||||
control_flags: ControlFlags::from_bits_truncate(termios.c_cflag),
|
||||
local_flags: LocalFlags::from_bits_truncate(termios.c_lflag),
|
||||
control_chars: termios.c_cc,
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "haiku",
|
||||
))]
|
||||
#[cfg(any(linux_android, target_os = "haiku"))]
|
||||
line_discipline: termios.c_line,
|
||||
}
|
||||
}
|
||||
@@ -355,9 +259,14 @@ libc_enum! {
|
||||
/// enum.
|
||||
///
|
||||
/// B0 is special and will disable the port.
|
||||
#[cfg_attr(all(any(target_os = "haiku"), target_pointer_width = "64"), repr(u8))]
|
||||
#[cfg_attr(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64"), repr(u64))]
|
||||
#[cfg_attr(not(all(any(target_os = "ios", target_os = "macos", target_os = "haiku"), target_pointer_width = "64")), repr(u32))]
|
||||
#[cfg_attr(target_os = "haiku", repr(u8))]
|
||||
#[cfg_attr(target_os = "hurd", repr(i32))]
|
||||
#[cfg_attr(all(apple_targets, target_pointer_width = "64"), repr(u64))]
|
||||
#[cfg_attr(all(
|
||||
not(all(apple_targets, target_pointer_width = "64")),
|
||||
not(target_os = "haiku"),
|
||||
not(target_os = "hurd")
|
||||
), repr(u32))]
|
||||
#[non_exhaustive]
|
||||
pub enum BaudRate {
|
||||
B0,
|
||||
@@ -373,104 +282,62 @@ libc_enum! {
|
||||
B1800,
|
||||
B2400,
|
||||
B4800,
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(bsd)]
|
||||
B7200,
|
||||
B9600,
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(bsd)]
|
||||
B14400,
|
||||
B19200,
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(bsd)]
|
||||
B28800,
|
||||
B38400,
|
||||
#[cfg(not(target_os = "aix"))]
|
||||
B57600,
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(bsd)]
|
||||
B76800,
|
||||
#[cfg(not(target_os = "aix"))]
|
||||
B115200,
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(solarish)]
|
||||
B153600,
|
||||
#[cfg(not(target_os = "aix"))]
|
||||
B230400,
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(solarish)]
|
||||
B307200,
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
solarish,
|
||||
target_os = "freebsd",
|
||||
target_os = "illumos",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
target_os = "netbsd"))]
|
||||
B460800,
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
B500000,
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
B576000,
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
solarish,
|
||||
target_os = "freebsd",
|
||||
target_os = "illumos",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
target_os = "netbsd"))]
|
||||
B921600,
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
B1000000,
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
B1152000,
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
B1500000,
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
B2000000,
|
||||
#[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
B2500000,
|
||||
#[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
B3000000,
|
||||
#[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
B3500000,
|
||||
#[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
B4000000,
|
||||
}
|
||||
impl TryFrom<libc::speed_t>
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
#[cfg(bsd)]
|
||||
impl From<BaudRate> for u32 {
|
||||
fn from(b: BaudRate) -> u32 {
|
||||
b as u32
|
||||
@@ -536,74 +403,57 @@ libc_enum! {
|
||||
}
|
||||
|
||||
// TODO: Make this usable directly as a slice index.
|
||||
#[cfg(not(target_os = "haiku"))]
|
||||
libc_enum! {
|
||||
/// Indices into the `termios.c_cc` array for special characters.
|
||||
#[repr(usize)]
|
||||
#[non_exhaustive]
|
||||
pub enum SpecialCharacterIndices {
|
||||
#[cfg(not(any(target_os = "aix", target_os = "haiku")))]
|
||||
VDISCARD,
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "illumos",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(bsd,
|
||||
solarish,
|
||||
target_os = "aix"))]
|
||||
VDSUSP,
|
||||
VEOF,
|
||||
VEOL,
|
||||
VEOL2,
|
||||
VERASE,
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "illumos",
|
||||
target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(freebsdlike, target_os = "illumos"))]
|
||||
VERASE2,
|
||||
VINTR,
|
||||
VKILL,
|
||||
#[cfg(not(target_os = "haiku"))]
|
||||
VLNEXT,
|
||||
#[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"),
|
||||
target_os = "illumos", target_os = "solaris")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
solarish, target_os = "aix", target_os = "haiku")))]
|
||||
VMIN,
|
||||
VQUIT,
|
||||
#[cfg(not(target_os = "haiku"))]
|
||||
VREPRINT,
|
||||
VSTART,
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "illumos",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(bsd, target_os = "illumos"))]
|
||||
VSTATUS,
|
||||
VSTOP,
|
||||
VSUSP,
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
VSWTC,
|
||||
#[cfg(any(target_os = "haiku", target_os = "illumos", target_os = "solaris"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(solarish, target_os = "haiku"))]
|
||||
VSWTCH,
|
||||
#[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"),
|
||||
target_os = "illumos", target_os = "solaris")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
solarish, target_os = "aix", target_os = "haiku")))]
|
||||
VTIME,
|
||||
#[cfg(not(any(target_os = "aix", target_os = "haiku")))]
|
||||
VWERASE,
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
VCHECKPT,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
all(target_os = "linux", target_arch = "sparc64"),
|
||||
target_os = "illumos",
|
||||
target_os = "solaris"
|
||||
solarish,
|
||||
target_os = "aix",
|
||||
target_os = "haiku",
|
||||
))]
|
||||
impl SpecialCharacterIndices {
|
||||
pub const VMIN: SpecialCharacterIndices = SpecialCharacterIndices::VEOF;
|
||||
@@ -611,16 +461,7 @@ impl SpecialCharacterIndices {
|
||||
}
|
||||
|
||||
pub use libc::NCCS;
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(bsd, linux_android, target_os = "aix", target_os = "solaris"))]
|
||||
pub use libc::_POSIX_VDISABLE;
|
||||
|
||||
libc_bitflags! {
|
||||
@@ -638,13 +479,10 @@ libc_bitflags! {
|
||||
IXON;
|
||||
IXOFF;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IXANY;
|
||||
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
IMAXBEL;
|
||||
#[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(linux_android, apple_targets))]
|
||||
IUTF8;
|
||||
}
|
||||
}
|
||||
@@ -653,209 +491,119 @@ libc_bitflags! {
|
||||
/// Flags for configuring the output mode of a terminal
|
||||
pub struct OutputFlags: tcflag_t {
|
||||
OPOST;
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "haiku",
|
||||
target_os = "linux",
|
||||
target_os = "openbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
OLCUC;
|
||||
ONLCR;
|
||||
OCRNL as tcflag_t;
|
||||
ONOCR as tcflag_t;
|
||||
ONLRET as tcflag_t;
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
OFILL as tcflag_t;
|
||||
#[cfg(any(target_os = "android",
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
apple_targets))]
|
||||
OFDEL as tcflag_t;
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
apple_targets))]
|
||||
NL0 as tcflag_t;
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
apple_targets))]
|
||||
NL1 as tcflag_t;
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
apple_targets))]
|
||||
CR0 as tcflag_t;
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
apple_targets))]
|
||||
CR1 as tcflag_t;
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
apple_targets))]
|
||||
CR2 as tcflag_t;
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
apple_targets))]
|
||||
CR3 as tcflag_t;
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "freebsd",
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
apple_targets))]
|
||||
TAB0 as tcflag_t;
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
apple_targets))]
|
||||
TAB1 as tcflag_t;
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
apple_targets))]
|
||||
TAB2 as tcflag_t;
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "freebsd",
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
apple_targets))]
|
||||
TAB3 as tcflag_t;
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
XTABS;
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
apple_targets))]
|
||||
BS0 as tcflag_t;
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
apple_targets))]
|
||||
BS1 as tcflag_t;
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
apple_targets))]
|
||||
VT0 as tcflag_t;
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
apple_targets))]
|
||||
VT1 as tcflag_t;
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
apple_targets))]
|
||||
FF0 as tcflag_t;
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
apple_targets))]
|
||||
FF1 as tcflag_t;
|
||||
#[cfg(any(target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(bsd)]
|
||||
OXTABS;
|
||||
#[cfg(any(target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(bsd)]
|
||||
ONOEOT as tcflag_t;
|
||||
|
||||
// Bitmasks for use with OutputFlags to select specific settings
|
||||
// These should be moved to be a mask once https://github.com/rust-lang-nursery/bitflags/issues/110
|
||||
// is resolved.
|
||||
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
apple_targets))]
|
||||
NLDLY as tcflag_t; // FIXME: Datatype needs to be corrected in libc for mac
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
apple_targets))]
|
||||
CRDLY as tcflag_t;
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "freebsd",
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
apple_targets))]
|
||||
TABDLY as tcflag_t;
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
apple_targets))]
|
||||
BSDLY as tcflag_t;
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
apple_targets))]
|
||||
VTDLY as tcflag_t;
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
apple_targets))]
|
||||
FFDLY as tcflag_t;
|
||||
}
|
||||
}
|
||||
@@ -863,13 +611,7 @@ libc_bitflags! {
|
||||
libc_bitflags! {
|
||||
/// Flags for setting the control mode of a terminal
|
||||
pub struct ControlFlags: tcflag_t {
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(bsd)]
|
||||
CIGNORE;
|
||||
CS5;
|
||||
CS6;
|
||||
@@ -881,55 +623,31 @@ libc_bitflags! {
|
||||
PARODD;
|
||||
HUPCL;
|
||||
CLOCAL;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(not(any(target_os = "redox", target_os = "aix")))]
|
||||
CRTSCTS;
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
CBAUD;
|
||||
#[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "mips"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
CMSPAR;
|
||||
#[cfg(any(target_os = "android",
|
||||
all(target_os = "linux",
|
||||
not(any(target_arch = "powerpc", target_arch = "powerpc64")))))]
|
||||
CIBAUD;
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
CBAUDEX;
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(bsd)]
|
||||
MDMBUF;
|
||||
#[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(netbsdlike)]
|
||||
CHWFLOW;
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(freebsdlike, netbsdlike))]
|
||||
CCTS_OFLOW;
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(freebsdlike, netbsdlike))]
|
||||
CRTS_IFLOW;
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
CDTR_IFLOW;
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
CDSR_OFLOW;
|
||||
#[cfg(any(target_os = "dragonfly",
|
||||
target_os = "freebsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
CCAR_OFLOW;
|
||||
|
||||
// Bitmasks for use with ControlFlags to select specific settings
|
||||
@@ -944,58 +662,35 @@ libc_bitflags! {
|
||||
/// Flags for setting any local modes
|
||||
pub struct LocalFlags: tcflag_t {
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
ECHOKE;
|
||||
ECHOE;
|
||||
ECHOK;
|
||||
ECHO;
|
||||
ECHONL;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(not(any(target_os = "redox", target_os = "cygwin")))]
|
||||
ECHOPRT;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
ECHOCTL;
|
||||
ISIG;
|
||||
ICANON;
|
||||
#[cfg(any(target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(bsd)]
|
||||
ALTWERASE;
|
||||
IEXTEN;
|
||||
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(not(any(target_os = "redox", target_os = "haiku", target_os = "aix", target_os = "cygwin")))]
|
||||
EXTPROC;
|
||||
TOSTOP;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
FLUSHO;
|
||||
#[cfg(any(target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(bsd)]
|
||||
NOKERNINFO;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(not(any(target_os = "redox", target_os = "cygwin")))]
|
||||
PENDIN;
|
||||
NOFLSH;
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"))] {
|
||||
if #[cfg(bsd)] {
|
||||
/// Get input baud rate (see
|
||||
/// [cfgetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)).
|
||||
///
|
||||
@@ -1128,7 +823,6 @@ pub fn cfmakeraw(termios: &mut Termios) {
|
||||
///
|
||||
/// Note that this is a non-standard function, available on FreeBSD.
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn cfmakesane(termios: &mut Termios) {
|
||||
let inner_termios = unsafe { termios.get_libc_termios_mut() };
|
||||
unsafe {
|
||||
@@ -1143,10 +837,12 @@ pub fn cfmakesane(termios: &mut Termios) {
|
||||
/// `tcgetattr()` returns a `Termios` structure with the current configuration for a port. Modifying
|
||||
/// this structure *will not* reconfigure the port, instead the modifications should be done to
|
||||
/// the `Termios` structure and then the port should be reconfigured using `tcsetattr()`.
|
||||
pub fn tcgetattr(fd: RawFd) -> Result<Termios> {
|
||||
pub fn tcgetattr<Fd: AsFd>(fd: Fd) -> Result<Termios> {
|
||||
let mut termios = mem::MaybeUninit::uninit();
|
||||
|
||||
let res = unsafe { libc::tcgetattr(fd, termios.as_mut_ptr()) };
|
||||
let res = unsafe {
|
||||
libc::tcgetattr(fd.as_fd().as_raw_fd(), termios.as_mut_ptr())
|
||||
};
|
||||
|
||||
Errno::result(res)?;
|
||||
|
||||
@@ -1159,18 +855,26 @@ pub fn tcgetattr(fd: RawFd) -> Result<Termios> {
|
||||
/// `tcsetattr()` reconfigures the given port based on a given `Termios` structure. This change
|
||||
/// takes affect at a time specified by `actions`. Note that this function may return success if
|
||||
/// *any* of the parameters were successfully set, not only if all were set successfully.
|
||||
pub fn tcsetattr(fd: RawFd, actions: SetArg, termios: &Termios) -> Result<()> {
|
||||
pub fn tcsetattr<Fd: AsFd>(
|
||||
fd: Fd,
|
||||
actions: SetArg,
|
||||
termios: &Termios,
|
||||
) -> Result<()> {
|
||||
let inner_termios = termios.get_libc_termios();
|
||||
Errno::result(unsafe {
|
||||
libc::tcsetattr(fd, actions as c_int, &*inner_termios)
|
||||
libc::tcsetattr(
|
||||
fd.as_fd().as_raw_fd(),
|
||||
actions as c_int,
|
||||
&*inner_termios,
|
||||
)
|
||||
})
|
||||
.map(drop)
|
||||
}
|
||||
|
||||
/// Block until all output data is written (see
|
||||
/// [tcdrain(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcdrain.html)).
|
||||
pub fn tcdrain(fd: RawFd) -> Result<()> {
|
||||
Errno::result(unsafe { libc::tcdrain(fd) }).map(drop)
|
||||
pub fn tcdrain<Fd: AsFd>(fd: Fd) -> Result<()> {
|
||||
Errno::result(unsafe { libc::tcdrain(fd.as_fd().as_raw_fd()) }).map(drop)
|
||||
}
|
||||
|
||||
/// Suspend or resume the transmission or reception of data (see
|
||||
@@ -1178,8 +882,11 @@ pub fn tcdrain(fd: RawFd) -> Result<()> {
|
||||
///
|
||||
/// `tcflow()` suspends of resumes the transmission or reception of data for the given port
|
||||
/// depending on the value of `action`.
|
||||
pub fn tcflow(fd: RawFd, action: FlowArg) -> Result<()> {
|
||||
Errno::result(unsafe { libc::tcflow(fd, action as c_int) }).map(drop)
|
||||
pub fn tcflow<Fd: AsFd>(fd: Fd, action: FlowArg) -> Result<()> {
|
||||
Errno::result(unsafe {
|
||||
libc::tcflow(fd.as_fd().as_raw_fd(), action as c_int)
|
||||
})
|
||||
.map(drop)
|
||||
}
|
||||
|
||||
/// Discard data in the output or input queue (see
|
||||
@@ -1187,8 +894,11 @@ pub fn tcflow(fd: RawFd, action: FlowArg) -> Result<()> {
|
||||
///
|
||||
/// `tcflush()` will discard data for a terminal port in the input queue, output queue, or both
|
||||
/// depending on the value of `action`.
|
||||
pub fn tcflush(fd: RawFd, action: FlushArg) -> Result<()> {
|
||||
Errno::result(unsafe { libc::tcflush(fd, action as c_int) }).map(drop)
|
||||
pub fn tcflush<Fd: AsFd>(fd: Fd, action: FlushArg) -> Result<()> {
|
||||
Errno::result(unsafe {
|
||||
libc::tcflush(fd.as_fd().as_raw_fd(), action as c_int)
|
||||
})
|
||||
.map(drop)
|
||||
}
|
||||
|
||||
/// Send a break for a specific duration (see
|
||||
@@ -1196,32 +906,20 @@ pub fn tcflush(fd: RawFd, action: FlushArg) -> Result<()> {
|
||||
///
|
||||
/// When using asynchronous data transmission `tcsendbreak()` will transmit a continuous stream
|
||||
/// of zero-valued bits for an implementation-defined duration.
|
||||
pub fn tcsendbreak(fd: RawFd, duration: c_int) -> Result<()> {
|
||||
Errno::result(unsafe { libc::tcsendbreak(fd, duration) }).map(drop)
|
||||
pub fn tcsendbreak<Fd: AsFd>(fd: Fd, duration: c_int) -> Result<()> {
|
||||
Errno::result(unsafe {
|
||||
libc::tcsendbreak(fd.as_fd().as_raw_fd(), duration)
|
||||
})
|
||||
.map(drop)
|
||||
}
|
||||
|
||||
feature! {
|
||||
#![feature = "process"]
|
||||
/// Get the session controlled by the given terminal (see
|
||||
/// [tcgetsid(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetsid.html)).
|
||||
pub fn tcgetsid(fd: RawFd) -> Result<Pid> {
|
||||
let res = unsafe { libc::tcgetsid(fd) };
|
||||
pub fn tcgetsid<Fd: AsFd>(fd: Fd) -> Result<Pid> {
|
||||
let res = unsafe { libc::tcgetsid(fd.as_fd().as_raw_fd()) };
|
||||
|
||||
Errno::result(res).map(Pid::from_raw)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
#[test]
|
||||
fn try_from() {
|
||||
assert_eq!(Ok(BaudRate::B0), BaudRate::try_from(libc::B0));
|
||||
#[cfg(not(target_os = "haiku"))]
|
||||
BaudRate::try_from(999999999).expect_err("assertion failed");
|
||||
#[cfg(target_os = "haiku")]
|
||||
BaudRate::try_from(99).expect_err("assertion failed");
|
||||
}
|
||||
}
|
||||
|
||||
+76
-135
@@ -1,8 +1,10 @@
|
||||
#[cfg_attr(any(target_env = "musl", target_env = "ohos"), allow(deprecated))]
|
||||
#[cfg_attr(
|
||||
any(target_env = "musl", target_env = "ohos"),
|
||||
allow(deprecated)
|
||||
)]
|
||||
// https://github.com/rust-lang/libc/issues/1848
|
||||
pub use libc::{suseconds_t, time_t};
|
||||
use libc::{timespec, timeval};
|
||||
use std::convert::From;
|
||||
use std::time::Duration;
|
||||
use std::{cmp, fmt, ops};
|
||||
|
||||
@@ -18,7 +20,7 @@ const fn zero_init_timespec() -> timespec {
|
||||
all(
|
||||
any(
|
||||
target_os = "freebsd",
|
||||
target_os = "illumos",
|
||||
solarish,
|
||||
target_os = "linux",
|
||||
target_os = "netbsd"
|
||||
),
|
||||
@@ -88,21 +90,19 @@ pub(crate) mod timer {
|
||||
Interval(TimeSpec),
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
bitflags! {
|
||||
/// Flags that are used for arming the timer.
|
||||
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct TimerSetTimeFlags: libc::c_int {
|
||||
const TFD_TIMER_ABSTIME = libc::TFD_TIMER_ABSTIME;
|
||||
const TFD_TIMER_CANCEL_ON_SET = libc::TFD_TIMER_CANCEL_ON_SET;
|
||||
}
|
||||
}
|
||||
#[cfg(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "illumos"
|
||||
))]
|
||||
#[cfg(any(freebsdlike, target_os = "netbsd", solarish))]
|
||||
bitflags! {
|
||||
/// Flags that are used for arming the timer.
|
||||
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct TimerSetTimeFlags: libc::c_int {
|
||||
const TFD_TIMER_ABSTIME = libc::TIMER_ABSTIME;
|
||||
}
|
||||
@@ -256,13 +256,15 @@ impl PartialOrd for TimeSpec {
|
||||
|
||||
impl TimeValLike for TimeSpec {
|
||||
#[inline]
|
||||
#[cfg_attr(any(target_env = "musl", target_env = "ohos"), allow(deprecated))]
|
||||
#[cfg_attr(
|
||||
any(target_env = "musl", target_env = "ohos"),
|
||||
allow(deprecated)
|
||||
)]
|
||||
// https://github.com/rust-lang/libc/issues/1848
|
||||
fn seconds(seconds: i64) -> TimeSpec {
|
||||
assert!(
|
||||
(TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&seconds),
|
||||
"TimeSpec out of bounds; seconds={}",
|
||||
seconds
|
||||
"TimeSpec out of bounds; seconds={seconds}",
|
||||
);
|
||||
let mut ts = zero_init_timespec();
|
||||
ts.tv_sec = seconds as time_t;
|
||||
@@ -290,7 +292,10 @@ impl TimeValLike for TimeSpec {
|
||||
|
||||
/// Makes a new `TimeSpec` with given number of nanoseconds.
|
||||
#[inline]
|
||||
#[cfg_attr(any(target_env = "musl", target_env = "ohos"), allow(deprecated))]
|
||||
#[cfg_attr(
|
||||
any(target_env = "musl", target_env = "ohos"),
|
||||
allow(deprecated)
|
||||
)]
|
||||
// https://github.com/rust-lang/libc/issues/1848
|
||||
fn nanoseconds(nanoseconds: i64) -> TimeSpec {
|
||||
let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC);
|
||||
@@ -332,8 +337,22 @@ impl TimeValLike for TimeSpec {
|
||||
}
|
||||
|
||||
impl TimeSpec {
|
||||
/// Leave the timestamp unchanged.
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
// At the time of writing this PR, redox does not support this feature
|
||||
pub const UTIME_OMIT: TimeSpec =
|
||||
TimeSpec::new(0, libc::UTIME_OMIT as timespec_tv_nsec_t);
|
||||
/// Update the timestamp to `Now`
|
||||
// At the time of writing this PR, redox does not support this feature
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
pub const UTIME_NOW: TimeSpec =
|
||||
TimeSpec::new(0, libc::UTIME_NOW as timespec_tv_nsec_t);
|
||||
|
||||
/// Construct a new `TimeSpec` from its components
|
||||
#[cfg_attr(any(target_env = "musl", target_env = "ohos"), allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
|
||||
#[cfg_attr(
|
||||
any(target_env = "musl", target_env = "ohos"),
|
||||
allow(deprecated)
|
||||
)] // https://github.com/rust-lang/libc/issues/1848
|
||||
pub const fn new(seconds: time_t, nanoseconds: timespec_tv_nsec_t) -> Self {
|
||||
let mut ts = zero_init_timespec();
|
||||
ts.tv_sec = seconds;
|
||||
@@ -349,7 +368,10 @@ impl TimeSpec {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(any(target_env = "musl", target_env = "ohos"), allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
|
||||
#[cfg_attr(
|
||||
any(target_env = "musl", target_env = "ohos"),
|
||||
allow(deprecated)
|
||||
)] // https://github.com/rust-lang/libc/issues/1848
|
||||
pub const fn tv_sec(&self) -> time_t {
|
||||
self.0.tv_sec
|
||||
}
|
||||
@@ -358,7 +380,10 @@ impl TimeSpec {
|
||||
self.0.tv_nsec
|
||||
}
|
||||
|
||||
#[cfg_attr(any(target_env = "musl", target_env = "ohos"), allow(deprecated))]
|
||||
#[cfg_attr(
|
||||
any(target_env = "musl", target_env = "ohos"),
|
||||
allow(deprecated)
|
||||
)]
|
||||
// https://github.com/rust-lang/libc/issues/1848
|
||||
pub const fn from_duration(duration: Duration) -> Self {
|
||||
let mut ts = zero_init_timespec();
|
||||
@@ -428,20 +453,20 @@ impl fmt::Display for TimeSpec {
|
||||
|
||||
let sec = abs.tv_sec();
|
||||
|
||||
write!(f, "{}", sign)?;
|
||||
write!(f, "{sign}")?;
|
||||
|
||||
if abs.tv_nsec() == 0 {
|
||||
if abs.tv_sec() == 1 {
|
||||
write!(f, "{} second", sec)?;
|
||||
if sec == 1 {
|
||||
write!(f, "1 second")?;
|
||||
} else {
|
||||
write!(f, "{} seconds", sec)?;
|
||||
write!(f, "{sec} seconds")?;
|
||||
}
|
||||
} else if abs.tv_nsec() % 1_000_000 == 0 {
|
||||
write!(f, "{}.{:03} seconds", sec, abs.tv_nsec() / 1_000_000)?;
|
||||
write!(f, "{sec}.{:03} seconds", abs.tv_nsec() / 1_000_000)?;
|
||||
} else if abs.tv_nsec() % 1_000 == 0 {
|
||||
write!(f, "{}.{:06} seconds", sec, abs.tv_nsec() / 1_000)?;
|
||||
write!(f, "{sec}.{:06} seconds", abs.tv_nsec() / 1_000)?;
|
||||
} else {
|
||||
write!(f, "{}.{:09} seconds", sec, abs.tv_nsec())?;
|
||||
write!(f, "{sec}.{:09} seconds", abs.tv_nsec())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -497,10 +522,12 @@ impl TimeValLike for TimeVal {
|
||||
fn seconds(seconds: i64) -> TimeVal {
|
||||
assert!(
|
||||
(TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&seconds),
|
||||
"TimeVal out of bounds; seconds={}",
|
||||
seconds
|
||||
"TimeVal out of bounds; seconds={seconds}"
|
||||
);
|
||||
#[cfg_attr(any(target_env = "musl", target_env = "ohos"), allow(deprecated))]
|
||||
#[cfg_attr(
|
||||
any(target_env = "musl", target_env = "ohos"),
|
||||
allow(deprecated)
|
||||
)]
|
||||
// https://github.com/rust-lang/libc/issues/1848
|
||||
TimeVal(timeval {
|
||||
tv_sec: seconds as time_t,
|
||||
@@ -525,7 +552,10 @@ impl TimeValLike for TimeVal {
|
||||
(TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs),
|
||||
"TimeVal out of bounds"
|
||||
);
|
||||
#[cfg_attr(any(target_env = "musl", target_env = "ohos"), allow(deprecated))]
|
||||
#[cfg_attr(
|
||||
any(target_env = "musl", target_env = "ohos"),
|
||||
allow(deprecated)
|
||||
)]
|
||||
// https://github.com/rust-lang/libc/issues/1848
|
||||
TimeVal(timeval {
|
||||
tv_sec: secs as time_t,
|
||||
@@ -543,7 +573,10 @@ impl TimeValLike for TimeVal {
|
||||
(TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs),
|
||||
"TimeVal out of bounds"
|
||||
);
|
||||
#[cfg_attr(any(target_env = "musl", target_env = "ohos"), allow(deprecated))]
|
||||
#[cfg_attr(
|
||||
any(target_env = "musl", target_env = "ohos"),
|
||||
allow(deprecated)
|
||||
)]
|
||||
// https://github.com/rust-lang/libc/issues/1848
|
||||
TimeVal(timeval {
|
||||
tv_sec: secs as time_t,
|
||||
@@ -580,7 +613,10 @@ impl TimeValLike for TimeVal {
|
||||
|
||||
impl TimeVal {
|
||||
/// Construct a new `TimeVal` from its components
|
||||
#[cfg_attr(any(target_env = "musl", target_env = "ohos"), allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
|
||||
#[cfg_attr(
|
||||
any(target_env = "musl", target_env = "ohos"),
|
||||
allow(deprecated)
|
||||
)] // https://github.com/rust-lang/libc/issues/1848
|
||||
pub const fn new(seconds: time_t, microseconds: suseconds_t) -> Self {
|
||||
Self(timeval {
|
||||
tv_sec: seconds,
|
||||
@@ -596,7 +632,10 @@ impl TimeVal {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(any(target_env = "musl", target_env = "ohos"), allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
|
||||
#[cfg_attr(
|
||||
any(target_env = "musl", target_env = "ohos"),
|
||||
allow(deprecated)
|
||||
)] // https://github.com/rust-lang/libc/issues/1848
|
||||
pub const fn tv_sec(&self) -> time_t {
|
||||
self.0.tv_sec
|
||||
}
|
||||
@@ -662,18 +701,18 @@ impl fmt::Display for TimeVal {
|
||||
|
||||
let sec = abs.tv_sec();
|
||||
|
||||
write!(f, "{}", sign)?;
|
||||
write!(f, "{sign}")?;
|
||||
|
||||
if abs.tv_usec() == 0 {
|
||||
if abs.tv_sec() == 1 {
|
||||
write!(f, "{} second", sec)?;
|
||||
if sec == 1 {
|
||||
write!(f, "1 second")?;
|
||||
} else {
|
||||
write!(f, "{} seconds", sec)?;
|
||||
write!(f, "{sec} seconds")?;
|
||||
}
|
||||
} else if abs.tv_usec() % 1000 == 0 {
|
||||
write!(f, "{}.{:03} seconds", sec, abs.tv_usec() / 1000)?;
|
||||
write!(f, "{sec}.{:03} seconds", abs.tv_usec() / 1000)?;
|
||||
} else {
|
||||
write!(f, "{}.{:06} seconds", sec, abs.tv_usec())?;
|
||||
write!(f, "{sec}.{:06} seconds", abs.tv_usec())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -711,101 +750,3 @@ fn mod_floor_64(this: i64, other: i64) -> i64 {
|
||||
fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
|
||||
(this / other, this % other)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{TimeSpec, TimeVal, TimeValLike};
|
||||
use std::time::Duration;
|
||||
|
||||
#[test]
|
||||
pub fn test_timespec() {
|
||||
assert_ne!(TimeSpec::seconds(1), TimeSpec::zero());
|
||||
assert_eq!(
|
||||
TimeSpec::seconds(1) + TimeSpec::seconds(2),
|
||||
TimeSpec::seconds(3)
|
||||
);
|
||||
assert_eq!(
|
||||
TimeSpec::minutes(3) + TimeSpec::seconds(2),
|
||||
TimeSpec::seconds(182)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_timespec_from() {
|
||||
let duration = Duration::new(123, 123_456_789);
|
||||
let timespec = TimeSpec::nanoseconds(123_123_456_789);
|
||||
|
||||
assert_eq!(TimeSpec::from(duration), timespec);
|
||||
assert_eq!(Duration::from(timespec), duration);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_timespec_neg() {
|
||||
let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123);
|
||||
let b = TimeSpec::seconds(-1) + TimeSpec::nanoseconds(-123);
|
||||
|
||||
assert_eq!(a, -b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_timespec_ord() {
|
||||
assert_eq!(TimeSpec::seconds(1), TimeSpec::nanoseconds(1_000_000_000));
|
||||
assert!(TimeSpec::seconds(1) < TimeSpec::nanoseconds(1_000_000_001));
|
||||
assert!(TimeSpec::seconds(1) > TimeSpec::nanoseconds(999_999_999));
|
||||
assert!(TimeSpec::seconds(-1) < TimeSpec::nanoseconds(-999_999_999));
|
||||
assert!(TimeSpec::seconds(-1) > TimeSpec::nanoseconds(-1_000_000_001));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_timespec_fmt() {
|
||||
assert_eq!(TimeSpec::zero().to_string(), "0 seconds");
|
||||
assert_eq!(TimeSpec::seconds(42).to_string(), "42 seconds");
|
||||
assert_eq!(TimeSpec::milliseconds(42).to_string(), "0.042 seconds");
|
||||
assert_eq!(TimeSpec::microseconds(42).to_string(), "0.000042 seconds");
|
||||
assert_eq!(
|
||||
TimeSpec::nanoseconds(42).to_string(),
|
||||
"0.000000042 seconds"
|
||||
);
|
||||
assert_eq!(TimeSpec::seconds(-86401).to_string(), "-86401 seconds");
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_timeval() {
|
||||
assert_ne!(TimeVal::seconds(1), TimeVal::zero());
|
||||
assert_eq!(
|
||||
TimeVal::seconds(1) + TimeVal::seconds(2),
|
||||
TimeVal::seconds(3)
|
||||
);
|
||||
assert_eq!(
|
||||
TimeVal::minutes(3) + TimeVal::seconds(2),
|
||||
TimeVal::seconds(182)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_timeval_ord() {
|
||||
assert_eq!(TimeVal::seconds(1), TimeVal::microseconds(1_000_000));
|
||||
assert!(TimeVal::seconds(1) < TimeVal::microseconds(1_000_001));
|
||||
assert!(TimeVal::seconds(1) > TimeVal::microseconds(999_999));
|
||||
assert!(TimeVal::seconds(-1) < TimeVal::microseconds(-999_999));
|
||||
assert!(TimeVal::seconds(-1) > TimeVal::microseconds(-1_000_001));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_timeval_neg() {
|
||||
let a = TimeVal::seconds(1) + TimeVal::microseconds(123);
|
||||
let b = TimeVal::seconds(-1) + TimeVal::microseconds(-123);
|
||||
|
||||
assert_eq!(a, -b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_timeval_fmt() {
|
||||
assert_eq!(TimeVal::zero().to_string(), "0 seconds");
|
||||
assert_eq!(TimeVal::seconds(42).to_string(), "42 seconds");
|
||||
assert_eq!(TimeVal::milliseconds(42).to_string(), "0.042 seconds");
|
||||
assert_eq!(TimeVal::microseconds(42).to_string(), "0.000042 seconds");
|
||||
assert_eq!(TimeVal::nanoseconds(1402).to_string(), "0.000001 seconds");
|
||||
assert_eq!(TimeVal::seconds(-86401).to_string(), "-86401 seconds");
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -95,7 +95,7 @@ impl Timer {
|
||||
/// There are 3 types of alarms you can set:
|
||||
///
|
||||
/// - one shot: the alarm will trigger once after the specified amount of
|
||||
/// time.
|
||||
/// time.
|
||||
/// Example: I want an alarm to go off in 60s and then disable itself.
|
||||
///
|
||||
/// - interval: the alarm will trigger every specified interval of time.
|
||||
|
||||
+47
-21
@@ -33,24 +33,34 @@ pub use crate::sys::time::timer::{Expiration, TimerSetTimeFlags};
|
||||
use crate::unistd::read;
|
||||
use crate::{errno::Errno, Result};
|
||||
use libc::c_int;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd};
|
||||
|
||||
/// A timerfd instance. This is also a file descriptor, you can feed it to
|
||||
/// other interfaces consuming file descriptors, epoll for example.
|
||||
/// other interfaces taking file descriptors as arguments, [`epoll`] for example.
|
||||
///
|
||||
/// [`epoll`]: crate::sys::epoll
|
||||
#[derive(Debug)]
|
||||
pub struct TimerFd {
|
||||
fd: RawFd,
|
||||
fd: OwnedFd,
|
||||
}
|
||||
|
||||
impl AsRawFd for TimerFd {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.fd
|
||||
impl AsFd for TimerFd {
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
self.fd.as_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for TimerFd {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||
TimerFd { fd }
|
||||
TimerFd {
|
||||
fd: unsafe { OwnedFd::from_raw_fd(fd) },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TimerFd> for OwnedFd {
|
||||
fn from(value: TimerFd) -> Self {
|
||||
value.fd
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +107,9 @@ impl TimerFd {
|
||||
Errno::result(unsafe {
|
||||
libc::timerfd_create(clockid as i32, flags.bits())
|
||||
})
|
||||
.map(|fd| Self { fd })
|
||||
.map(|fd| Self {
|
||||
fd: unsafe { OwnedFd::from_raw_fd(fd) },
|
||||
})
|
||||
}
|
||||
|
||||
/// Sets a new alarm on the timer.
|
||||
@@ -107,7 +119,7 @@ impl TimerFd {
|
||||
/// There are 3 types of alarms you can set:
|
||||
///
|
||||
/// - one shot: the alarm will trigger once after the specified amount of
|
||||
/// time.
|
||||
/// time.
|
||||
/// Example: I want an alarm to go off in 60s and then disable itself.
|
||||
///
|
||||
/// - interval: the alarm will trigger every specified interval of time.
|
||||
@@ -129,6 +141,13 @@ impl TimerFd {
|
||||
/// Then the one shot TimeSpec and the delay TimeSpec of the delayed
|
||||
/// interval are going to be interpreted as absolute.
|
||||
///
|
||||
/// # Cancel on a clock change
|
||||
///
|
||||
/// If you set a `TFD_TIMER_CANCEL_ON_SET` alongside `TFD_TIMER_ABSTIME`
|
||||
/// and the clock for this timer is `CLOCK_REALTIME` or `CLOCK_REALTIME_ALARM`,
|
||||
/// then this timer is marked as cancelable if the real-time clock undergoes
|
||||
/// a discontinuous change.
|
||||
///
|
||||
/// # Disabling alarms
|
||||
///
|
||||
/// Note: Only one alarm can be set for any given timer. Setting a new alarm
|
||||
@@ -145,7 +164,7 @@ impl TimerFd {
|
||||
let timerspec: TimerSpec = expiration.into();
|
||||
Errno::result(unsafe {
|
||||
libc::timerfd_settime(
|
||||
self.fd,
|
||||
self.fd.as_fd().as_raw_fd(),
|
||||
flags.bits(),
|
||||
timerspec.as_ref(),
|
||||
std::ptr::null_mut(),
|
||||
@@ -159,7 +178,10 @@ impl TimerFd {
|
||||
pub fn get(&self) -> Result<Option<Expiration>> {
|
||||
let mut timerspec = TimerSpec::none();
|
||||
Errno::result(unsafe {
|
||||
libc::timerfd_gettime(self.fd, timerspec.as_mut())
|
||||
libc::timerfd_gettime(
|
||||
self.fd.as_fd().as_raw_fd(),
|
||||
timerspec.as_mut(),
|
||||
)
|
||||
})
|
||||
.map(|_| {
|
||||
if timerspec.as_ref().it_interval.tv_sec == 0
|
||||
@@ -179,7 +201,7 @@ impl TimerFd {
|
||||
pub fn unset(&self) -> Result<()> {
|
||||
Errno::result(unsafe {
|
||||
libc::timerfd_settime(
|
||||
self.fd,
|
||||
self.fd.as_fd().as_raw_fd(),
|
||||
TimerSetTimeFlags::empty().bits(),
|
||||
TimerSpec::none().as_ref(),
|
||||
std::ptr::null_mut(),
|
||||
@@ -192,7 +214,10 @@ impl TimerFd {
|
||||
///
|
||||
/// Note: If the alarm is unset, then you will wait forever.
|
||||
pub fn wait(&self) -> Result<()> {
|
||||
while let Err(e) = read(self.fd, &mut [0u8; 8]) {
|
||||
while let Err(e) = read(&self.fd, &mut [0u8; 8]) {
|
||||
if e == Errno::ECANCELED {
|
||||
break;
|
||||
}
|
||||
if e != Errno::EINTR {
|
||||
return Err(e);
|
||||
}
|
||||
@@ -200,15 +225,16 @@ impl TimerFd {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TimerFd {
|
||||
fn drop(&mut self) {
|
||||
if !std::thread::panicking() {
|
||||
let result = Errno::result(unsafe { libc::close(self.fd) });
|
||||
if let Err(Errno::EBADF) = result {
|
||||
panic!("close of TimerFd encountered EBADF");
|
||||
}
|
||||
|
||||
/// Constructs a `TimerFd` wrapping an existing `OwnedFd`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `OwnedFd` is a valid `TimerFd`.
|
||||
pub unsafe fn from_owned_fd(fd: OwnedFd) -> Self {
|
||||
Self {
|
||||
fd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+40
-103
@@ -2,15 +2,14 @@
|
||||
|
||||
use crate::errno::Errno;
|
||||
use crate::Result;
|
||||
use libc::{self, c_int, c_void, off_t, size_t};
|
||||
use libc::{self, c_int, off_t, size_t};
|
||||
use std::io::{IoSlice, IoSliceMut};
|
||||
use std::marker::PhantomData;
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::os::unix::io::{AsFd, AsRawFd};
|
||||
|
||||
/// Low-level vectored write to a raw file descriptor
|
||||
///
|
||||
/// See also [writev(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/writev.html)
|
||||
pub fn writev(fd: RawFd, iov: &[IoSlice<'_>]) -> Result<usize> {
|
||||
pub fn writev<Fd: AsFd>(fd: Fd, iov: &[IoSlice<'_>]) -> Result<usize> {
|
||||
// SAFETY: to quote the documentation for `IoSlice`:
|
||||
//
|
||||
// [IoSlice] is semantically a wrapper around a &[u8], but is
|
||||
@@ -19,7 +18,11 @@ pub fn writev(fd: RawFd, iov: &[IoSlice<'_>]) -> Result<usize> {
|
||||
//
|
||||
// Because it is ABI compatible, a pointer cast here is valid
|
||||
let res = unsafe {
|
||||
libc::writev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int)
|
||||
libc::writev(
|
||||
fd.as_fd().as_raw_fd(),
|
||||
iov.as_ptr().cast(),
|
||||
iov.len() as c_int,
|
||||
)
|
||||
};
|
||||
|
||||
Errno::result(res).map(|r| r as usize)
|
||||
@@ -31,10 +34,14 @@ pub fn writev(fd: RawFd, iov: &[IoSlice<'_>]) -> Result<usize> {
|
||||
// Clippy doesn't know that we need to pass iov mutably only because the
|
||||
// mutation happens after converting iov to a pointer
|
||||
#[allow(clippy::needless_pass_by_ref_mut)]
|
||||
pub fn readv(fd: RawFd, iov: &mut [IoSliceMut<'_>]) -> Result<usize> {
|
||||
pub fn readv<Fd: AsFd>(fd: Fd, iov: &mut [IoSliceMut<'_>]) -> Result<usize> {
|
||||
// SAFETY: same as in writev(), IoSliceMut is ABI-compatible with iovec
|
||||
let res = unsafe {
|
||||
libc::readv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int)
|
||||
libc::readv(
|
||||
fd.as_fd().as_raw_fd(),
|
||||
iov.as_ptr().cast(),
|
||||
iov.len() as c_int,
|
||||
)
|
||||
};
|
||||
|
||||
Errno::result(res).map(|r| r as usize)
|
||||
@@ -46,17 +53,20 @@ pub fn readv(fd: RawFd, iov: &mut [IoSliceMut<'_>]) -> Result<usize> {
|
||||
/// or an error occurs. The file offset is not changed.
|
||||
///
|
||||
/// See also: [`writev`](fn.writev.html) and [`pwrite`](fn.pwrite.html)
|
||||
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn pwritev(fd: RawFd, iov: &[IoSlice<'_>], offset: off_t) -> Result<usize> {
|
||||
#[cfg(not(any(target_os = "redox", target_os = "haiku", target_os = "solaris", target_os = "cygwin")))]
|
||||
pub fn pwritev<Fd: AsFd>(
|
||||
fd: Fd,
|
||||
iov: &[IoSlice<'_>],
|
||||
offset: off_t,
|
||||
) -> Result<usize> {
|
||||
#[cfg(target_env = "uclibc")]
|
||||
let offset = offset as libc::off64_t; // uclibc doesn't use off_t
|
||||
|
||||
// SAFETY: same as in writev()
|
||||
let res = unsafe {
|
||||
libc::pwritev(
|
||||
fd,
|
||||
iov.as_ptr() as *const libc::iovec,
|
||||
fd.as_fd().as_raw_fd(),
|
||||
iov.as_ptr().cast(),
|
||||
iov.len() as c_int,
|
||||
offset,
|
||||
)
|
||||
@@ -72,13 +82,12 @@ pub fn pwritev(fd: RawFd, iov: &[IoSlice<'_>], offset: off_t) -> Result<usize> {
|
||||
/// changed.
|
||||
///
|
||||
/// See also: [`readv`](fn.readv.html) and [`pread`](fn.pread.html)
|
||||
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(not(any(target_os = "redox", target_os = "haiku", target_os = "solaris", target_os = "cygwin")))]
|
||||
// Clippy doesn't know that we need to pass iov mutably only because the
|
||||
// mutation happens after converting iov to a pointer
|
||||
#[allow(clippy::needless_pass_by_ref_mut)]
|
||||
pub fn preadv(
|
||||
fd: RawFd,
|
||||
pub fn preadv<Fd: AsFd>(
|
||||
fd: Fd,
|
||||
iov: &mut [IoSliceMut<'_>],
|
||||
offset: off_t,
|
||||
) -> Result<usize> {
|
||||
@@ -88,8 +97,8 @@ pub fn preadv(
|
||||
// SAFETY: same as in readv()
|
||||
let res = unsafe {
|
||||
libc::preadv(
|
||||
fd,
|
||||
iov.as_ptr() as *const libc::iovec,
|
||||
fd.as_fd().as_raw_fd(),
|
||||
iov.as_ptr().cast(),
|
||||
iov.len() as c_int,
|
||||
offset,
|
||||
)
|
||||
@@ -102,11 +111,11 @@ pub fn preadv(
|
||||
///
|
||||
/// See also [pwrite(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html)
|
||||
// TODO: move to unistd
|
||||
pub fn pwrite(fd: RawFd, buf: &[u8], offset: off_t) -> Result<usize> {
|
||||
pub fn pwrite<Fd: AsFd>(fd: Fd, buf: &[u8], offset: off_t) -> Result<usize> {
|
||||
let res = unsafe {
|
||||
libc::pwrite(
|
||||
fd,
|
||||
buf.as_ptr() as *const c_void,
|
||||
fd.as_fd().as_raw_fd(),
|
||||
buf.as_ptr().cast(),
|
||||
buf.len() as size_t,
|
||||
offset,
|
||||
)
|
||||
@@ -119,11 +128,11 @@ pub fn pwrite(fd: RawFd, buf: &[u8], offset: off_t) -> Result<usize> {
|
||||
///
|
||||
/// See also [pread(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html)
|
||||
// TODO: move to unistd
|
||||
pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result<usize> {
|
||||
pub fn pread<Fd: AsFd>(fd: Fd, buf: &mut [u8], offset: off_t) -> Result<usize> {
|
||||
let res = unsafe {
|
||||
libc::pread(
|
||||
fd,
|
||||
buf.as_mut_ptr() as *mut c_void,
|
||||
fd.as_fd().as_raw_fd(),
|
||||
buf.as_mut_ptr().cast(),
|
||||
buf.len() as size_t,
|
||||
offset,
|
||||
)
|
||||
@@ -140,8 +149,7 @@ pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result<usize> {
|
||||
/// therefore not represented in Rust by an actual slice as `IoSlice` is. It
|
||||
/// is used with [`process_vm_readv`](fn.process_vm_readv.html)
|
||||
/// and [`process_vm_writev`](fn.process_vm_writev.html).
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct RemoteIoVec {
|
||||
@@ -151,77 +159,6 @@ pub struct RemoteIoVec {
|
||||
pub len: usize,
|
||||
}
|
||||
|
||||
/// A vector of buffers.
|
||||
///
|
||||
/// Vectored I/O methods like [`writev`] and [`readv`] use this structure for
|
||||
/// both reading and writing. Each `IoVec` specifies the base address and
|
||||
/// length of an area in memory.
|
||||
#[deprecated(
|
||||
since = "0.24.0",
|
||||
note = "`IoVec` is no longer used in the public interface, use `IoSlice` or `IoSliceMut` instead"
|
||||
)]
|
||||
#[repr(transparent)]
|
||||
#[allow(renamed_and_removed_lints)]
|
||||
#[allow(clippy::unknown_clippy_lints)]
|
||||
// Clippy false positive: https://github.com/rust-lang/rust-clippy/issues/8867
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct IoVec<T>(pub(crate) libc::iovec, PhantomData<T>);
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> IoVec<T> {
|
||||
/// View the `IoVec` as a Rust slice.
|
||||
#[deprecated(
|
||||
since = "0.24.0",
|
||||
note = "Use the `Deref` impl of `IoSlice` or `IoSliceMut` instead"
|
||||
)]
|
||||
#[inline]
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
use std::slice;
|
||||
|
||||
unsafe {
|
||||
slice::from_raw_parts(self.0.iov_base as *const u8, self.0.iov_len)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<'a> IoVec<&'a [u8]> {
|
||||
/// Create an `IoVec` from a Rust slice.
|
||||
#[deprecated(since = "0.24.0", note = "Use `IoSlice::new` instead")]
|
||||
pub fn from_slice(buf: &'a [u8]) -> IoVec<&'a [u8]> {
|
||||
IoVec(
|
||||
libc::iovec {
|
||||
iov_base: buf.as_ptr() as *mut c_void,
|
||||
iov_len: buf.len() as size_t,
|
||||
},
|
||||
PhantomData,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<'a> IoVec<&'a mut [u8]> {
|
||||
/// Create an `IoVec` from a mutable Rust slice.
|
||||
#[deprecated(since = "0.24.0", note = "Use `IoSliceMut::new` instead")]
|
||||
pub fn from_mut_slice(buf: &'a mut [u8]) -> IoVec<&'a mut [u8]> {
|
||||
IoVec(
|
||||
libc::iovec {
|
||||
iov_base: buf.as_mut_ptr() as *mut c_void,
|
||||
iov_len: buf.len() as size_t,
|
||||
},
|
||||
PhantomData,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// The only reason IoVec isn't automatically Send+Sync is because libc::iovec
|
||||
// contains raw pointers.
|
||||
#[allow(deprecated)]
|
||||
unsafe impl<T> Send for IoVec<T> where T: Send {}
|
||||
#[allow(deprecated)]
|
||||
unsafe impl<T> Sync for IoVec<T> where T: Sync {}
|
||||
|
||||
feature! {
|
||||
#![feature = "process"]
|
||||
|
||||
@@ -245,7 +182,7 @@ feature! {
|
||||
/// [ptrace]: ../ptrace/index.html
|
||||
/// [`IoSlice`]: https://doc.rust-lang.org/std/io/struct.IoSlice.html
|
||||
/// [`RemoteIoVec`]: struct.RemoteIoVec.html
|
||||
#[cfg(all(any(target_os = "linux", target_os = "android"), not(target_env = "uclibc")))]
|
||||
#[cfg(all(linux_android, not(target_env = "uclibc")))]
|
||||
pub fn process_vm_writev(
|
||||
pid: crate::unistd::Pid,
|
||||
local_iov: &[IoSlice<'_>],
|
||||
@@ -253,8 +190,8 @@ pub fn process_vm_writev(
|
||||
{
|
||||
let res = unsafe {
|
||||
libc::process_vm_writev(pid.into(),
|
||||
local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong,
|
||||
remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0)
|
||||
local_iov.as_ptr().cast(), local_iov.len() as libc::c_ulong,
|
||||
remote_iov.as_ptr().cast(), remote_iov.len() as libc::c_ulong, 0)
|
||||
};
|
||||
|
||||
Errno::result(res).map(|r| r as usize)
|
||||
@@ -280,7 +217,7 @@ pub fn process_vm_writev(
|
||||
/// [`ptrace`]: ../ptrace/index.html
|
||||
/// [`IoSliceMut`]: https://doc.rust-lang.org/std/io/struct.IoSliceMut.html
|
||||
/// [`RemoteIoVec`]: struct.RemoteIoVec.html
|
||||
#[cfg(all(any(target_os = "linux", target_os = "android"), not(target_env = "uclibc")))]
|
||||
#[cfg(all(linux_android, not(target_env = "uclibc")))]
|
||||
pub fn process_vm_readv(
|
||||
pid: crate::unistd::Pid,
|
||||
local_iov: &mut [IoSliceMut<'_>],
|
||||
@@ -288,8 +225,8 @@ pub fn process_vm_readv(
|
||||
{
|
||||
let res = unsafe {
|
||||
libc::process_vm_readv(pid.into(),
|
||||
local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong,
|
||||
remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0)
|
||||
local_iov.as_ptr().cast(), local_iov.len() as libc::c_ulong,
|
||||
remote_iov.as_ptr().cast(), remote_iov.len() as libc::c_ulong, 0)
|
||||
};
|
||||
|
||||
Errno::result(res).map(|r| r as usize)
|
||||
|
||||
+1
-22
@@ -37,7 +37,7 @@ impl UtsName {
|
||||
}
|
||||
|
||||
/// NIS or YP domain name of this machine.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
pub fn domainname(&self) -> &OsStr {
|
||||
cast_and_trim(&self.0.domainname)
|
||||
}
|
||||
@@ -62,24 +62,3 @@ fn cast_and_trim(slice: &[c_char]) -> &OsStr {
|
||||
|
||||
OsStr::from_bytes(bytes)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[cfg(target_os = "linux")]
|
||||
#[test]
|
||||
pub fn test_uname_linux() {
|
||||
assert_eq!(super::uname().unwrap().sysname(), "Linux");
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
#[test]
|
||||
pub fn test_uname_darwin() {
|
||||
assert_eq!(super::uname().unwrap().sysname(), "Darwin");
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[test]
|
||||
pub fn test_uname_freebsd() {
|
||||
assert_eq!(super::uname().unwrap().sysname(), "FreeBSD");
|
||||
}
|
||||
}
|
||||
|
||||
+32
-39
@@ -10,7 +10,7 @@ use std::convert::TryFrom;
|
||||
target_os = "android",
|
||||
all(target_os = "linux", not(target_env = "uclibc")),
|
||||
))]
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::os::unix::io::{AsRawFd, BorrowedFd};
|
||||
|
||||
libc_bitflags!(
|
||||
/// Controls the behavior of [`waitpid`].
|
||||
@@ -24,53 +24,41 @@ libc_bitflags!(
|
||||
/// [`SIGSTOP`](crate::sys::signal::Signal::SIGSTOP) signal.
|
||||
WUNTRACED;
|
||||
/// Report the status of selected processes which have terminated.
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
apple_targets,
|
||||
target_os = "freebsd",
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "redox",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
WEXITED;
|
||||
/// Report the status of selected processes that have continued from a
|
||||
/// job control stop by receiving a
|
||||
/// [`SIGCONT`](crate::sys::signal::Signal::SIGCONT) signal.
|
||||
WCONTINUED;
|
||||
/// An alias for WUNTRACED.
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
apple_targets,
|
||||
target_os = "freebsd",
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "redox",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
WSTOPPED;
|
||||
/// Don't reap, just poll status.
|
||||
#[cfg(any(target_os = "android",
|
||||
#[cfg(any(linux_android,
|
||||
apple_targets,
|
||||
target_os = "freebsd",
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "redox",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
WNOWAIT;
|
||||
/// Don't wait on children of other threads in this group
|
||||
#[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(linux_android, target_os = "redox"))]
|
||||
__WNOTHREAD;
|
||||
/// Wait on all children, regardless of type
|
||||
#[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(linux_android, target_os = "redox"))]
|
||||
__WALL;
|
||||
/// Wait for "clone" children only.
|
||||
#[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(linux_android, target_os = "redox"))]
|
||||
__WCLONE;
|
||||
}
|
||||
);
|
||||
@@ -107,16 +95,14 @@ pub enum WaitStatus {
|
||||
///
|
||||
/// [`nix::sys::ptrace`]: ../ptrace/index.html
|
||||
/// [`ptrace`(2)]: https://man7.org/linux/man-pages/man2/ptrace.2.html
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
PtraceEvent(Pid, Signal, c_int),
|
||||
/// The traced process was stopped by execution of a system call,
|
||||
/// and `PTRACE_O_TRACESYSGOOD` is in effect. See [`ptrace`(2)] for
|
||||
/// more information.
|
||||
///
|
||||
/// [`ptrace`(2)]: https://man7.org/linux/man-pages/man2/ptrace.2.html
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(linux_android)]
|
||||
PtraceSyscall(Pid),
|
||||
/// The process was previously stopped but has resumed execution
|
||||
/// after receiving a `SIGCONT` signal. This is only reported if
|
||||
@@ -139,7 +125,7 @@ impl WaitStatus {
|
||||
Some(p)
|
||||
}
|
||||
StillAlive => None,
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
PtraceEvent(p, _, _) | PtraceSyscall(p) => Some(p),
|
||||
}
|
||||
}
|
||||
@@ -173,7 +159,7 @@ fn stop_signal(status: i32) -> Result<Signal> {
|
||||
Signal::try_from(libc::WSTOPSIG(status))
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
fn syscall_stop(status: i32) -> bool {
|
||||
// From ptrace(2), setting PTRACE_O_TRACESYSGOOD has the effect
|
||||
// of delivering SIGTRAP | 0x80 as the signal number for syscall
|
||||
@@ -182,7 +168,7 @@ fn syscall_stop(status: i32) -> bool {
|
||||
libc::WSTOPSIG(status) == libc::SIGTRAP | 0x80
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
fn stop_additional(status: i32) -> c_int {
|
||||
(status >> 16) as c_int
|
||||
}
|
||||
@@ -216,7 +202,7 @@ impl WaitStatus {
|
||||
WaitStatus::Signaled(pid, term_signal(status)?, dumped_core(status))
|
||||
} else if stopped(status) {
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "android", target_os = "linux"))] {
|
||||
if #[cfg(linux_android)] {
|
||||
fn decode_stopped(pid: Pid, status: i32) -> Result<WaitStatus> {
|
||||
let status_additional = stop_additional(status);
|
||||
Ok(if syscall_stop(status) {
|
||||
@@ -259,7 +245,7 @@ impl WaitStatus {
|
||||
all(target_os = "linux", not(target_env = "uclibc")),
|
||||
))]
|
||||
unsafe fn from_siginfo(siginfo: &libc::siginfo_t) -> Result<WaitStatus> {
|
||||
let si_pid = siginfo.si_pid();
|
||||
let si_pid = unsafe { siginfo.si_pid() };
|
||||
if si_pid == 0 {
|
||||
return Ok(WaitStatus::StillAlive);
|
||||
}
|
||||
@@ -267,7 +253,7 @@ impl WaitStatus {
|
||||
assert_eq!(siginfo.si_signo, libc::SIGCHLD);
|
||||
|
||||
let pid = Pid::from_raw(si_pid);
|
||||
let si_status = siginfo.si_status();
|
||||
let si_status = unsafe { siginfo.si_status() };
|
||||
|
||||
let status = match siginfo.si_code {
|
||||
libc::CLD_EXITED => WaitStatus::Exited(pid, si_status),
|
||||
@@ -280,7 +266,7 @@ impl WaitStatus {
|
||||
WaitStatus::Stopped(pid, Signal::try_from(si_status)?)
|
||||
}
|
||||
libc::CLD_CONTINUED => WaitStatus::Continued(pid),
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
libc::CLD_TRAPPED => {
|
||||
if si_status == libc::SIGTRAP | 0x80 {
|
||||
WaitStatus::PtraceSyscall(pid)
|
||||
@@ -343,8 +329,8 @@ pub fn wait() -> Result<WaitStatus> {
|
||||
target_os = "haiku",
|
||||
all(target_os = "linux", not(target_env = "uclibc")),
|
||||
))]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum Id {
|
||||
#[derive(Debug)]
|
||||
pub enum Id<'fd> {
|
||||
/// Wait for any child
|
||||
All,
|
||||
/// Wait for the child whose process ID matches the given PID
|
||||
@@ -354,8 +340,12 @@ pub enum Id {
|
||||
/// If the PID is zero, the caller's process group is used since Linux 5.4.
|
||||
PGid(Pid),
|
||||
/// Wait for the child referred to by the given PID file descriptor
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
PIDFd(RawFd),
|
||||
#[cfg(linux_android)]
|
||||
PIDFd(BorrowedFd<'fd>),
|
||||
/// A helper variant to resolve the unused parameter (`'fd`) problem on platforms
|
||||
/// other than Linux and Android.
|
||||
#[doc(hidden)]
|
||||
_Unreachable(std::marker::PhantomData<&'fd std::convert::Infallible>),
|
||||
}
|
||||
|
||||
/// Wait for a process to change status
|
||||
@@ -372,8 +362,11 @@ pub fn waitid(id: Id, flags: WaitPidFlag) -> Result<WaitStatus> {
|
||||
Id::All => (libc::P_ALL, 0),
|
||||
Id::Pid(pid) => (libc::P_PID, pid.as_raw() as libc::id_t),
|
||||
Id::PGid(pid) => (libc::P_PGID, pid.as_raw() as libc::id_t),
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
Id::PIDFd(fd) => (libc::P_PIDFD, fd as libc::id_t),
|
||||
#[cfg(linux_android)]
|
||||
Id::PIDFd(fd) => (libc::P_PIDFD, fd.as_raw_fd() as libc::id_t),
|
||||
Id::_Unreachable(_) => {
|
||||
unreachable!("This variant could never be constructed")
|
||||
}
|
||||
};
|
||||
|
||||
let siginfo = unsafe {
|
||||
|
||||
+293
@@ -0,0 +1,293 @@
|
||||
//! Interfaces for controlling system log.
|
||||
|
||||
use crate::{NixPath, Result};
|
||||
use std::ffi::OsStr;
|
||||
use std::ptr;
|
||||
|
||||
/// Logging options of subsequent [`syslog`] calls can be set by calling [`openlog`].
|
||||
///
|
||||
/// The parameter `ident` is a string that will be prepended to every message. The `logopt`
|
||||
/// argument specifies logging options. The `facility` parameter encodes a default facility to be
|
||||
/// assigned to all messages that do not have an explicit facility encoded.
|
||||
//
|
||||
// On Linux, the `ident` argument needs to have static lifetime according to the
|
||||
// man page:
|
||||
//
|
||||
// The argument ident in the call of openlog() is probably stored as-is. Thus,
|
||||
// if the string it points to is changed, syslog() may start prepending the changed
|
||||
// string, and if the string it points to ceases to exist, the results are
|
||||
// undefined. Most portable is to use a string constant.
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn openlog(
|
||||
ident: Option<&'static std::ffi::CStr>,
|
||||
logopt: LogFlags,
|
||||
facility: Facility,
|
||||
) -> Result<()> {
|
||||
let logopt = logopt.bits();
|
||||
let facility = facility as libc::c_int;
|
||||
match ident {
|
||||
None => unsafe {
|
||||
libc::openlog(ptr::null(), logopt, facility);
|
||||
},
|
||||
Some(ident) => ident.with_nix_path(|ident| unsafe {
|
||||
libc::openlog(ident.as_ptr(), logopt, facility);
|
||||
})?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Logging options of subsequent [`syslog`] calls can be set by calling [`openlog`].
|
||||
///
|
||||
/// The parameter `ident` is a string that will be prepended to every message. The `logopt`
|
||||
/// argument specifies logging options. The `facility` parameter encodes a default facility to be
|
||||
/// assigned to all messages that do not have an explicit facility encoded.
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
pub fn openlog<S: AsRef<OsStr> + ?Sized>(
|
||||
ident: Option<&S>,
|
||||
logopt: LogFlags,
|
||||
facility: Facility,
|
||||
) -> Result<()> {
|
||||
let logopt = logopt.bits();
|
||||
let facility = facility as libc::c_int;
|
||||
match ident.map(OsStr::new) {
|
||||
None => unsafe {
|
||||
libc::openlog(ptr::null(), logopt, facility);
|
||||
},
|
||||
Some(ident) => ident.with_nix_path(|ident| unsafe {
|
||||
libc::openlog(ident.as_ptr(), logopt, facility);
|
||||
})?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Writes message to the system message logger.
|
||||
///
|
||||
/// The message is then written to the system console, log files, logged-in users, or forwarded
|
||||
/// to other machines as appropriate.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use nix::syslog::{openlog, syslog, Facility, LogFlags, Severity, Priority};
|
||||
///
|
||||
/// let priority = Priority::new(Severity::LOG_EMERG, Facility::LOG_USER);
|
||||
/// syslog(priority, "Hello, nix!").unwrap();
|
||||
///
|
||||
/// // use `format!` to format the message
|
||||
/// let name = "syslog";
|
||||
/// syslog(priority, &format!("Hello, {name}!")).unwrap();
|
||||
/// ```
|
||||
pub fn syslog<P, S>(priority: P, message: &S) -> Result<()>
|
||||
where
|
||||
P: Into<Priority>,
|
||||
S: AsRef<OsStr> + ?Sized,
|
||||
{
|
||||
let priority = priority.into();
|
||||
let formatter = OsStr::new("%s");
|
||||
let message = OsStr::new(message);
|
||||
formatter.with_nix_path(|formatter| {
|
||||
message.with_nix_path(|message| unsafe {
|
||||
libc::syslog(priority.0, formatter.as_ptr(), message.as_ptr())
|
||||
})
|
||||
})??;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the process-wide priority mask to `mask` and return the previous mask
|
||||
/// value.
|
||||
///
|
||||
/// Calls to `syslog()` with a priority level not set in `mask` are ignored. The
|
||||
/// default is to log all priorities.
|
||||
///
|
||||
/// If the `mask` argument is `None`, the current logmask is not modified, this
|
||||
/// can be used to query the current log mask.
|
||||
pub fn setlogmask(mask: Option<LogMask>) -> LogMask {
|
||||
let mask = match mask {
|
||||
Some(mask) => mask.0,
|
||||
None => 0,
|
||||
};
|
||||
let prev_mask = unsafe { libc::setlogmask(mask) };
|
||||
LogMask(prev_mask)
|
||||
}
|
||||
|
||||
/// Closes the log file.
|
||||
pub fn closelog() {
|
||||
unsafe { libc::closelog() }
|
||||
}
|
||||
|
||||
/// System log priority mask.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct LogMask(libc::c_int);
|
||||
|
||||
impl LogMask {
|
||||
/// Creates a mask of all priorities up to and including `priority`.
|
||||
#[doc(alias("LOG_UPTO"))]
|
||||
pub fn up_to(priority: Severity) -> Self {
|
||||
let pri = priority as libc::c_int;
|
||||
Self((1 << (pri + 1)) - 1)
|
||||
}
|
||||
|
||||
/// Creates a mask for the specified priority.
|
||||
#[doc(alias("LOG_MASK"))]
|
||||
pub fn of_priority(priority: Severity) -> Self {
|
||||
let pri = priority as libc::c_int;
|
||||
Self(1 << pri)
|
||||
}
|
||||
|
||||
/// Returns if the mask for the specified `priority` is set.
|
||||
pub fn contains(&self, priority: Severity) -> bool {
|
||||
let priority = Self::of_priority(priority);
|
||||
let and_result = *self & priority;
|
||||
and_result.0 != 0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitOr for LogMask {
|
||||
type Output = Self;
|
||||
fn bitor(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 | rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitAnd for LogMask {
|
||||
type Output = Self;
|
||||
fn bitand(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 & rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitOrAssign for LogMask {
|
||||
fn bitor_assign(&mut self, rhs: Self) {
|
||||
self.0 |= rhs.0;
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitAndAssign for LogMask {
|
||||
fn bitand_assign(&mut self, rhs: Self) {
|
||||
self.0 &= rhs.0;
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Not for LogMask {
|
||||
type Output = Self;
|
||||
fn not(self) -> Self::Output {
|
||||
Self(!self.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// The priority for a log message.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Priority(libc::c_int);
|
||||
|
||||
impl Priority {
|
||||
/// Create a new priority from a facility and severity level.
|
||||
pub fn new(severity: Severity, facility: Facility) -> Self {
|
||||
let priority = (facility as libc::c_int) | (severity as libc::c_int);
|
||||
Priority(priority)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Severity> for Priority {
|
||||
fn from(severity: Severity) -> Self {
|
||||
let priority = severity as libc::c_int;
|
||||
Priority(priority)
|
||||
}
|
||||
}
|
||||
|
||||
libc_bitflags! {
|
||||
/// Options for system logging.
|
||||
pub struct LogFlags: libc::c_int {
|
||||
/// Log the process id with each message: useful for identifying instantiations of
|
||||
/// daemons.
|
||||
LOG_PID;
|
||||
/// If syslog() cannot pass the message to syslogd(8) it will attempt to write the
|
||||
/// message to the console ("/dev/console").
|
||||
LOG_CONS;
|
||||
/// The converse of [`LOG_NDELAY`][LogFlags::LOG_NDELAY]; opening of the connection is
|
||||
/// delayed until `syslog` is called.
|
||||
///
|
||||
/// This is the default, and need not be specified.
|
||||
LOG_ODELAY;
|
||||
/// Open the connection to syslogd(8) immediately. Normally the open is delayed until
|
||||
/// the first message is logged. Useful for programs that need to manage the order in
|
||||
/// which file descriptors are allocated.
|
||||
LOG_NDELAY;
|
||||
/// Write the message to standard error output as well to the system log.
|
||||
#[cfg(not(any(solarish, target_os = "redox", target_os = "cygwin")))]
|
||||
LOG_PERROR;
|
||||
}
|
||||
}
|
||||
|
||||
libc_enum! {
|
||||
/// Severity levels for log messages.
|
||||
#[repr(i32)]
|
||||
#[non_exhaustive]
|
||||
pub enum Severity {
|
||||
/// A panic condition.
|
||||
///
|
||||
/// This is normally broadcast to all users.
|
||||
LOG_EMERG,
|
||||
/// A condition that should be corrected immediately, such as a corrupted system database.
|
||||
LOG_ALERT,
|
||||
/// Critical conditions, e.g., hard device errors.
|
||||
LOG_CRIT,
|
||||
/// Errors.
|
||||
LOG_ERR,
|
||||
/// Warning messages.
|
||||
LOG_WARNING,
|
||||
/// Conditions that are not error conditions, but should possibly be handled specially.
|
||||
LOG_NOTICE,
|
||||
/// Informational messages.
|
||||
LOG_INFO,
|
||||
/// Messages that contain information normally of use only when debugging a program.
|
||||
LOG_DEBUG,
|
||||
}
|
||||
}
|
||||
|
||||
libc_enum! {
|
||||
/// Facilities for log messages.
|
||||
#[repr(i32)]
|
||||
#[non_exhaustive]
|
||||
pub enum Facility {
|
||||
/// Messages generated by the kernel.
|
||||
///
|
||||
/// These cannot be generated by any user processes.
|
||||
LOG_KERN,
|
||||
/// Messages generated by random user processes.
|
||||
///
|
||||
/// This is the default facility identifier if none is specified.
|
||||
LOG_USER,
|
||||
/// The mail system.
|
||||
LOG_MAIL,
|
||||
/// System daemons, such as routed(8), that are not provided for explicitly by other facilities.
|
||||
LOG_DAEMON,
|
||||
/// The authorization system: login(1), su(1), getty(8), etc.
|
||||
LOG_AUTH,
|
||||
/// Messages generated internally by syslogd(8).
|
||||
LOG_SYSLOG,
|
||||
/// The line printer spooling system: cups-lpd(8), cupsd(8), etc.
|
||||
LOG_LPR,
|
||||
/// The network news system.
|
||||
LOG_NEWS,
|
||||
/// The uucp system.
|
||||
LOG_UUCP,
|
||||
/// Reserved for local use.
|
||||
LOG_LOCAL0,
|
||||
/// Reserved for local use.
|
||||
LOG_LOCAL1,
|
||||
/// Reserved for local use.
|
||||
LOG_LOCAL2,
|
||||
/// Reserved for local use.
|
||||
LOG_LOCAL3,
|
||||
/// Reserved for local use.
|
||||
LOG_LOCAL4,
|
||||
/// Reserved for local use.
|
||||
LOG_LOCAL5,
|
||||
/// Reserved for local use.
|
||||
LOG_LOCAL6,
|
||||
/// Reserved for local use.
|
||||
LOG_LOCAL7,
|
||||
}
|
||||
}
|
||||
+123
-118
@@ -1,11 +1,6 @@
|
||||
//! Sleep, query system clocks, and set system clock
|
||||
use crate::sys::time::TimeSpec;
|
||||
#[cfg(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
))]
|
||||
#[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))]
|
||||
#[cfg(feature = "process")]
|
||||
use crate::unistd::Pid;
|
||||
use crate::{Errno, Result};
|
||||
@@ -14,8 +9,7 @@ use std::mem::MaybeUninit;
|
||||
|
||||
/// Clock identifier
|
||||
///
|
||||
/// Newtype pattern around `clockid_t` (which is just alias). It prevents bugs caused by
|
||||
/// accidentally passing wrong value.
|
||||
/// Newtype pattern around [`libc::clockid_t`].
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
pub struct ClockId(clockid_t);
|
||||
|
||||
@@ -28,14 +22,7 @@ impl ClockId {
|
||||
feature! {
|
||||
#![feature = "process"]
|
||||
/// Returns `ClockId` of a `pid` CPU-time clock
|
||||
#[cfg(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))]
|
||||
pub fn pid_cpu_clock_id(pid: Pid) -> Result<Self> {
|
||||
clock_getcpuclockid(pid)
|
||||
}
|
||||
@@ -43,7 +30,6 @@ impl ClockId {
|
||||
|
||||
/// Returns resolution of the clock id
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn res(self) -> Result<TimeSpec> {
|
||||
clock_getres(self)
|
||||
}
|
||||
@@ -55,12 +41,12 @@ impl ClockId {
|
||||
|
||||
/// Sets time to `timespec` on the clock id
|
||||
#[cfg(not(any(
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "tvos",
|
||||
target_os = "watchos",
|
||||
target_os = "redox",
|
||||
target_os = "hermit",
|
||||
target_os = "hermit"
|
||||
)))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn set_time(self, timespec: TimeSpec) -> Result<()> {
|
||||
clock_settime(self, timespec)
|
||||
}
|
||||
@@ -70,135 +56,106 @@ impl ClockId {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_os = "linux"
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
|
||||
/// Starts at zero when the kernel boots and increments monotonically in SI seconds while the
|
||||
/// machine is running.
|
||||
pub const CLOCK_BOOTTIME: ClockId = ClockId(libc::CLOCK_BOOTTIME);
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_os = "linux"
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
/// Like [`CLOCK_BOOTTIME`](ClockId::CLOCK_BOOTTIME), but will wake the system if it is
|
||||
/// suspended..
|
||||
#[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
|
||||
pub const CLOCK_BOOTTIME_ALARM: ClockId =
|
||||
ClockId(libc::CLOCK_BOOTTIME_ALARM);
|
||||
/// Increments in SI seconds.
|
||||
pub const CLOCK_MONOTONIC: ClockId = ClockId(libc::CLOCK_MONOTONIC);
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_os = "linux"
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
/// Like [`CLOCK_MONOTONIC`](ClockId::CLOCK_MONOTONIC), but optimized for execution time at the expense of accuracy.
|
||||
#[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
|
||||
pub const CLOCK_MONOTONIC_COARSE: ClockId =
|
||||
ClockId(libc::CLOCK_MONOTONIC_COARSE);
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
/// Like [`CLOCK_MONOTONIC`](ClockId::CLOCK_MONOTONIC), but optimized for execution time at the expense of accuracy.
|
||||
pub const CLOCK_MONOTONIC_FAST: ClockId =
|
||||
ClockId(libc::CLOCK_MONOTONIC_FAST);
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
/// Like [`CLOCK_MONOTONIC`](ClockId::CLOCK_MONOTONIC), but optimized for accuracy at the expense of execution time.
|
||||
pub const CLOCK_MONOTONIC_PRECISE: ClockId =
|
||||
ClockId(libc::CLOCK_MONOTONIC_PRECISE);
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_os = "linux"
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
/// Similar to [`CLOCK_MONOTONIC`](ClockId::CLOCK_MONOTONIC), but provides access to a raw
|
||||
/// hardware-based time that is not subject to NTP adjustments.
|
||||
#[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
|
||||
pub const CLOCK_MONOTONIC_RAW: ClockId = ClockId(libc::CLOCK_MONOTONIC_RAW);
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
linux_android,
|
||||
apple_targets,
|
||||
freebsdlike,
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "redox",
|
||||
target_os = "linux"
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
/// Returns the execution time of the calling process.
|
||||
pub const CLOCK_PROCESS_CPUTIME_ID: ClockId =
|
||||
ClockId(libc::CLOCK_PROCESS_CPUTIME_ID);
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
/// Increments when the CPU is running in user or kernel mode
|
||||
pub const CLOCK_PROF: ClockId = ClockId(libc::CLOCK_PROF);
|
||||
/// Increments as a wall clock should.
|
||||
pub const CLOCK_REALTIME: ClockId = ClockId(libc::CLOCK_REALTIME);
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_os = "linux"
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
/// Like [`CLOCK_REALTIME`](ClockId::CLOCK_REALTIME), but not settable.
|
||||
#[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
|
||||
pub const CLOCK_REALTIME_ALARM: ClockId =
|
||||
ClockId(libc::CLOCK_REALTIME_ALARM);
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_os = "linux"
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
/// Like [`CLOCK_REALTIME`](ClockId::CLOCK_REALTIME), but optimized for execution time at the expense of accuracy.
|
||||
#[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
|
||||
pub const CLOCK_REALTIME_COARSE: ClockId =
|
||||
ClockId(libc::CLOCK_REALTIME_COARSE);
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
/// Like [`CLOCK_REALTIME`](ClockId::CLOCK_REALTIME), but optimized for execution time at the expense of accuracy.
|
||||
pub const CLOCK_REALTIME_FAST: ClockId = ClockId(libc::CLOCK_REALTIME_FAST);
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
/// Like [`CLOCK_REALTIME`](ClockId::CLOCK_REALTIME), but optimized for accuracy at the expense of execution time.
|
||||
pub const CLOCK_REALTIME_PRECISE: ClockId =
|
||||
ClockId(libc::CLOCK_REALTIME_PRECISE);
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
/// Returns the current second without performing a full time counter query, using an in-kernel
|
||||
/// cached value of the current second.
|
||||
pub const CLOCK_SECOND: ClockId = ClockId(libc::CLOCK_SECOND);
|
||||
#[allow(missing_docs)] // Undocumented on Linux!
|
||||
#[cfg(any(
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
all(target_os = "linux", any(target_env = "musl", target_env = "ohos"))
|
||||
all(
|
||||
target_os = "linux",
|
||||
any(target_env = "musl", target_env = "ohos")
|
||||
)
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub const CLOCK_SGI_CYCLE: ClockId = ClockId(libc::CLOCK_SGI_CYCLE);
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_os = "linux"
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
/// International Atomic Time.
|
||||
///
|
||||
/// A nonsettable system-wide clock derived from wall-clock time but ignoring leap seconds.
|
||||
#[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
|
||||
pub const CLOCK_TAI: ClockId = ClockId(libc::CLOCK_TAI);
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
linux_android,
|
||||
apple_targets,
|
||||
freebsdlike,
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "linux"
|
||||
))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
/// Returns the execution time of the calling thread.
|
||||
pub const CLOCK_THREAD_CPUTIME_ID: ClockId =
|
||||
ClockId(libc::CLOCK_THREAD_CPUTIME_ID);
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
/// Starts at zero when the kernel boots and increments monotonically in SI seconds while the
|
||||
/// machine is running.
|
||||
pub const CLOCK_UPTIME: ClockId = ClockId(libc::CLOCK_UPTIME);
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
/// Like [`CLOCK_UPTIME`](ClockId::CLOCK_UPTIME), but optimized for execution time at the expense of accuracy.
|
||||
pub const CLOCK_UPTIME_FAST: ClockId = ClockId(libc::CLOCK_UPTIME_FAST);
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
/// Like [`CLOCK_UPTIME`](ClockId::CLOCK_UPTIME), but optimized for accuracy at the expense of execution time.
|
||||
pub const CLOCK_UPTIME_PRECISE: ClockId =
|
||||
ClockId(libc::CLOCK_UPTIME_PRECISE);
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
#[cfg(freebsdlike)]
|
||||
/// Increments only when the CPU is running in user mode on behalf of the calling process.
|
||||
pub const CLOCK_VIRTUAL: ClockId = ClockId(libc::CLOCK_VIRTUAL);
|
||||
}
|
||||
|
||||
@@ -223,7 +180,6 @@ impl std::fmt::Display for ClockId {
|
||||
/// Get the resolution of the specified clock, (see
|
||||
/// [clock_getres(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_getres.html)).
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn clock_getres(clock_id: ClockId) -> Result<TimeSpec> {
|
||||
let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
|
||||
let ret =
|
||||
@@ -247,12 +203,12 @@ pub fn clock_gettime(clock_id: ClockId) -> Result<TimeSpec> {
|
||||
/// Set the time of the specified clock, (see
|
||||
/// [clock_settime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_settime.html)).
|
||||
#[cfg(not(any(
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "tvos",
|
||||
target_os = "watchos",
|
||||
target_os = "redox",
|
||||
target_os = "hermit",
|
||||
target_os = "hermit"
|
||||
)))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all())))]
|
||||
pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> {
|
||||
let ret =
|
||||
unsafe { libc::clock_settime(clock_id.as_raw(), timespec.as_ref()) };
|
||||
@@ -261,13 +217,7 @@ pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> {
|
||||
|
||||
/// Get the clock id of the specified process id, (see
|
||||
/// [clock_getcpuclockid(3)](https://pubs.opengroup.org/onlinepubs/009695399/functions/clock_getcpuclockid.html)).
|
||||
#[cfg(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
))]
|
||||
#[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))]
|
||||
#[cfg(feature = "process")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "process")))]
|
||||
pub fn clock_getcpuclockid(pid: Pid) -> Result<ClockId> {
|
||||
@@ -278,6 +228,61 @@ pub fn clock_getcpuclockid(pid: Pid) -> Result<ClockId> {
|
||||
let res = unsafe { clk_id.assume_init() };
|
||||
Ok(ClockId::from(res))
|
||||
} else {
|
||||
Err(Errno::from_i32(ret))
|
||||
Err(Errno::from_raw(ret))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
linux_android,
|
||||
solarish,
|
||||
freebsdlike,
|
||||
target_os = "netbsd",
|
||||
target_os = "hurd",
|
||||
target_os = "aix"
|
||||
))]
|
||||
libc_bitflags! {
|
||||
/// Flags that are used for arming the timer.
|
||||
pub struct ClockNanosleepFlags: libc::c_int {
|
||||
/// Indicates that a requested time value should be treated as absolute instead of
|
||||
/// relative.
|
||||
TIMER_ABSTIME;
|
||||
}
|
||||
}
|
||||
|
||||
/// Suspend execution of this thread for the amount of time specified by `request`
|
||||
/// and measured against the clock speficied by `clock_id`.
|
||||
///
|
||||
/// If `flags` is [`TIMER_ABSTIME`](ClockNanosleepFlags::TIMER_ABSTIME), this function will suspend
|
||||
/// execution until the time value of clock_id reaches the absolute time specified by `request`. If
|
||||
/// a signal is caught by a signal-catching function, or a signal causes the process to terminate,
|
||||
/// this sleep is interrrupted.
|
||||
///
|
||||
/// see also [man 3 clock_nanosleep](https://pubs.opengroup.org/onlinepubs/009695399/functions/clock_nanosleep.html)
|
||||
#[cfg(any(
|
||||
linux_android,
|
||||
solarish,
|
||||
freebsdlike,
|
||||
target_os = "netbsd",
|
||||
target_os = "hurd",
|
||||
target_os = "aix"
|
||||
))]
|
||||
pub fn clock_nanosleep(
|
||||
clock_id: ClockId,
|
||||
flags: ClockNanosleepFlags,
|
||||
request: &TimeSpec,
|
||||
) -> Result<TimeSpec> {
|
||||
let mut remain = TimeSpec::new(0, 0);
|
||||
let ret = unsafe {
|
||||
libc::clock_nanosleep(
|
||||
clock_id.as_raw(),
|
||||
flags.bits(),
|
||||
request.as_ref() as *const _,
|
||||
remain.as_mut() as *mut _,
|
||||
)
|
||||
};
|
||||
if ret == 0 {
|
||||
Ok(remain)
|
||||
} else {
|
||||
Err(Errno::from_raw(ret))
|
||||
}
|
||||
}
|
||||
|
||||
+1541
-914
File diff suppressed because it is too large
Load Diff
+7
-7
@@ -2,18 +2,18 @@ use cfg_if::cfg_if;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! skip {
|
||||
($($reason: expr),+) => {
|
||||
($($reason: expr),+) => {{
|
||||
use ::std::io::{self, Write};
|
||||
|
||||
let stderr = io::stderr();
|
||||
let mut handle = stderr.lock();
|
||||
writeln!(handle, $($reason),+).unwrap();
|
||||
return;
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "android", target_os = "linux"))] {
|
||||
if #[cfg(linux_android)] {
|
||||
#[macro_export] macro_rules! require_capability {
|
||||
($name:expr, $capname:ident) => {
|
||||
use ::caps::{Capability, CapSet, has_cap};
|
||||
@@ -37,8 +37,8 @@ cfg_if! {
|
||||
#[macro_export]
|
||||
macro_rules! require_mount {
|
||||
($name:expr) => {
|
||||
use ::sysctl::{CtlValue, Sysctl};
|
||||
use nix::unistd::Uid;
|
||||
use sysctl::{CtlValue, Sysctl};
|
||||
|
||||
let ctl = ::sysctl::Ctl::new("vfs.usermount").unwrap();
|
||||
if !Uid::current().is_root() && CtlValue::Int(0) == ctl.value().unwrap()
|
||||
@@ -51,7 +51,7 @@ macro_rules! require_mount {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
#[macro_export]
|
||||
macro_rules! skip_if_cirrus {
|
||||
($reason:expr) => {
|
||||
@@ -65,7 +65,7 @@ macro_rules! skip_if_cirrus {
|
||||
#[macro_export]
|
||||
macro_rules! skip_if_jailed {
|
||||
($name:expr) => {
|
||||
use ::sysctl::{CtlValue, Sysctl};
|
||||
use sysctl::{CtlValue, Sysctl};
|
||||
|
||||
let ctl = ::sysctl::Ctl::new("security.jail.jailed").unwrap();
|
||||
if let CtlValue::Int(1) = ctl.value().unwrap() {
|
||||
@@ -87,7 +87,7 @@ macro_rules! skip_if_not_root {
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "android", target_os = "linux"))] {
|
||||
if #[cfg(linux_android)] {
|
||||
#[macro_export] macro_rules! skip_if_seccomp {
|
||||
($name:expr) => {
|
||||
if let Ok(s) = std::fs::read_to_string("/proc/self/status") {
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#[cfg(target_os = "linux")]
|
||||
mod test_mount;
|
||||
#[cfg(apple_targets)]
|
||||
mod test_mount_apple;
|
||||
#[cfg(target_os = "freebsd")]
|
||||
mod test_nmount;
|
||||
@@ -0,0 +1,189 @@
|
||||
use std::fs::{self, File};
|
||||
use std::io::{Read, Write};
|
||||
use std::os::unix::fs::OpenOptionsExt;
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::process::Command;
|
||||
|
||||
use libc::{EACCES, EROFS};
|
||||
|
||||
use nix::mount::{mount, umount, MsFlags};
|
||||
use nix::sys::stat::{self, Mode};
|
||||
|
||||
use crate::*;
|
||||
|
||||
static SCRIPT_CONTENTS: &[u8] = b"#!/bin/sh
|
||||
exit 23";
|
||||
|
||||
const EXPECTED_STATUS: i32 = 23;
|
||||
|
||||
const NONE: Option<&'static [u8]> = None;
|
||||
|
||||
#[test]
|
||||
fn test_mount_tmpfs_without_flags_allows_rwx() {
|
||||
require_capability!(
|
||||
"test_mount_tmpfs_without_flags_allows_rwx",
|
||||
CAP_SYS_ADMIN
|
||||
);
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
|
||||
mount(
|
||||
NONE,
|
||||
tempdir.path(),
|
||||
Some(b"tmpfs".as_ref()),
|
||||
MsFlags::empty(),
|
||||
NONE,
|
||||
)
|
||||
.unwrap_or_else(|e| panic!("mount failed: {e}"));
|
||||
|
||||
let test_path = tempdir.path().join("test");
|
||||
|
||||
// Verify write.
|
||||
fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
|
||||
.open(&test_path)
|
||||
.and_then(|mut f| f.write(SCRIPT_CONTENTS))
|
||||
.unwrap_or_else(|e| panic!("write failed: {e}"));
|
||||
|
||||
// Verify read.
|
||||
let mut buf = Vec::new();
|
||||
File::open(&test_path)
|
||||
.and_then(|mut f| f.read_to_end(&mut buf))
|
||||
.unwrap_or_else(|e| panic!("read failed: {e}"));
|
||||
assert_eq!(buf, SCRIPT_CONTENTS);
|
||||
|
||||
// while forking and unmounting prevent other child processes
|
||||
let _m = FORK_MTX.lock();
|
||||
// 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}"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mount_rdonly_disallows_write() {
|
||||
require_capability!("test_mount_rdonly_disallows_write", CAP_SYS_ADMIN);
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
|
||||
mount(
|
||||
NONE,
|
||||
tempdir.path(),
|
||||
Some(b"tmpfs".as_ref()),
|
||||
MsFlags::MS_RDONLY,
|
||||
NONE,
|
||||
)
|
||||
.unwrap_or_else(|e| panic!("mount failed: {e}"));
|
||||
|
||||
// EROFS: Read-only file system
|
||||
assert_eq!(
|
||||
EROFS,
|
||||
File::create(tempdir.path().join("test"))
|
||||
.unwrap_err()
|
||||
.raw_os_error()
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mount_noexec_disallows_exec() {
|
||||
require_capability!("test_mount_noexec_disallows_exec", CAP_SYS_ADMIN);
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
|
||||
mount(
|
||||
NONE,
|
||||
tempdir.path(),
|
||||
Some(b"tmpfs".as_ref()),
|
||||
MsFlags::MS_NOEXEC,
|
||||
NONE,
|
||||
)
|
||||
.unwrap_or_else(|e| panic!("mount failed: {e}"));
|
||||
|
||||
let test_path = tempdir.path().join("test");
|
||||
|
||||
fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
|
||||
.open(&test_path)
|
||||
.and_then(|mut f| f.write(SCRIPT_CONTENTS))
|
||||
.unwrap_or_else(|e| panic!("write failed: {e}"));
|
||||
|
||||
// Verify that we cannot execute despite a+x permissions being set.
|
||||
let mode = stat::Mode::from_bits_truncate(
|
||||
fs::metadata(&test_path)
|
||||
.map(|md| md.permissions().mode())
|
||||
.unwrap_or_else(|e| panic!("metadata failed: {e}")),
|
||||
);
|
||||
|
||||
assert!(
|
||||
mode.contains(Mode::S_IXUSR | Mode::S_IXGRP | Mode::S_IXOTH),
|
||||
"{:?} did not have execute permissions",
|
||||
&test_path
|
||||
);
|
||||
|
||||
// while forking and unmounting prevent other child processes
|
||||
let _m = FORK_MTX.lock();
|
||||
// EACCES: Permission denied
|
||||
assert_eq!(
|
||||
EACCES,
|
||||
Command::new(&test_path)
|
||||
.status()
|
||||
.unwrap_err()
|
||||
.raw_os_error()
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mount_bind() {
|
||||
require_capability!("test_mount_bind", CAP_SYS_ADMIN);
|
||||
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}"));
|
||||
|
||||
// wait for child processes to prevent EBUSY
|
||||
let _m = FORK_MTX.lock();
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
use nix::errno::Errno;
|
||||
use nix::mount::{mount, MntFlags};
|
||||
|
||||
#[test]
|
||||
fn test_mount() {
|
||||
let res = mount::<str, str, str>("", "", MntFlags::empty(), None);
|
||||
assert_eq!(res, Err(Errno::ENOENT));
|
||||
}
|
||||
+54
-16
@@ -7,16 +7,20 @@ mod test_signal;
|
||||
// cases on DragonFly.
|
||||
#[cfg(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
all(target_os = "linux", not(target_env = "uclibc")),
|
||||
target_os = "macos",
|
||||
apple_targets,
|
||||
all(
|
||||
target_os = "linux",
|
||||
not(any(target_env = "uclibc", target_env = "ohos"))
|
||||
),
|
||||
target_os = "netbsd"
|
||||
))]
|
||||
mod test_aio;
|
||||
#[cfg(not(any(
|
||||
target_os = "redox",
|
||||
target_os = "fuchsia",
|
||||
target_os = "haiku"
|
||||
target_os = "haiku",
|
||||
target_os = "hurd",
|
||||
target_os = "cygwin"
|
||||
)))]
|
||||
mod test_ioctl;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
@@ -30,7 +34,7 @@ mod test_socket;
|
||||
#[cfg(not(any(target_os = "redox")))]
|
||||
mod test_sockopt;
|
||||
mod test_stat;
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
mod test_sysinfo;
|
||||
#[cfg(not(any(
|
||||
target_os = "redox",
|
||||
@@ -41,20 +45,54 @@ mod test_termios;
|
||||
mod test_uio;
|
||||
mod test_wait;
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
mod test_epoll;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod test_fanotify;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod test_inotify;
|
||||
mod test_pthread;
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
|
||||
#[cfg(any(linux_android, freebsdlike, netbsdlike, apple_targets))]
|
||||
mod test_ptrace;
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
mod test_timerfd;
|
||||
|
||||
#[cfg(all(
|
||||
any(
|
||||
target_os = "freebsd",
|
||||
solarish,
|
||||
target_os = "linux",
|
||||
target_os = "netbsd"
|
||||
),
|
||||
feature = "time",
|
||||
feature = "signal"
|
||||
))]
|
||||
mod test_timer;
|
||||
|
||||
#[cfg(bsd)]
|
||||
mod test_event;
|
||||
mod test_statvfs;
|
||||
mod test_time;
|
||||
mod test_utsname;
|
||||
|
||||
#[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "openbsd"))]
|
||||
mod test_statfs;
|
||||
|
||||
#[cfg(not(any(
|
||||
target_os = "redox",
|
||||
target_os = "fuchsia",
|
||||
solarish,
|
||||
target_os = "haiku"
|
||||
)))]
|
||||
mod test_resource;
|
||||
|
||||
// This test module should be enabled for both linux_android and freebsd, but
|
||||
// the `memfd_create(2)` symbol is not available under Linux QEMU,
|
||||
//
|
||||
// https://github.com/nix-rust/nix/actions/runs/9427112650/job/25970870477
|
||||
//
|
||||
// and I haven't found a way to stop the linker from linking that symbol, so
|
||||
// only enable this for FreeBSD for now.
|
||||
#[cfg(target_os = "freebsd")]
|
||||
mod test_memfd;
|
||||
|
||||
+153
-94
@@ -1,7 +1,7 @@
|
||||
use std::{
|
||||
io::{Read, Seek, Write},
|
||||
ops::Deref,
|
||||
os::unix::io::AsRawFd,
|
||||
os::unix::io::{AsFd, AsRawFd, BorrowedFd},
|
||||
pin::Pin,
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
thread, time,
|
||||
@@ -21,9 +21,7 @@ use nix::{
|
||||
};
|
||||
use tempfile::tempfile;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref SIGNALED: AtomicBool = AtomicBool::new(false);
|
||||
}
|
||||
pub static SIGNALED: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
extern "C" fn sigfunc(_: c_int) {
|
||||
SIGNALED.store(true, Ordering::Relaxed);
|
||||
@@ -47,8 +45,9 @@ mod aio_fsync {
|
||||
|
||||
#[test]
|
||||
fn test_accessors() {
|
||||
let f = tempfile().unwrap();
|
||||
let aiocb = AioFsync::new(
|
||||
1001,
|
||||
f.as_fd(),
|
||||
AioFsyncMode::O_SYNC,
|
||||
42,
|
||||
SigevNotify::SigevSignal {
|
||||
@@ -56,7 +55,7 @@ mod aio_fsync {
|
||||
si_value: 99,
|
||||
},
|
||||
);
|
||||
assert_eq!(1001, aiocb.fd());
|
||||
assert_eq!(f.as_raw_fd(), aiocb.fd().as_raw_fd());
|
||||
assert_eq!(AioFsyncMode::O_SYNC, aiocb.mode());
|
||||
assert_eq!(42, aiocb.priority());
|
||||
let sev = aiocb.sigevent().sigevent();
|
||||
@@ -69,21 +68,17 @@ mod aio_fsync {
|
||||
// Skip on Linux, because Linux's AIO implementation can't detect errors
|
||||
// synchronously
|
||||
#[test]
|
||||
#[cfg(any(target_os = "freebsd", target_os = "macos"))]
|
||||
#[cfg_attr(any(target_os = "android", target_os = "linux"), ignore)]
|
||||
fn error() {
|
||||
use std::mem;
|
||||
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
// Create an invalid AioFsyncMode
|
||||
let mode = unsafe { mem::transmute(666) };
|
||||
let mode = unsafe { mem::transmute::<i32, AioFsyncMode>(666) };
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
let mut aiof = Box::pin(AioFsync::new(
|
||||
f.as_raw_fd(),
|
||||
mode,
|
||||
0,
|
||||
SigevNotify::SigevNone,
|
||||
));
|
||||
let mut aiof =
|
||||
Box::pin(AioFsync::new(f.as_fd(), mode, 0, SigevNotify::SigevNone));
|
||||
let err = aiof.as_mut().submit();
|
||||
err.expect_err("assertion failed");
|
||||
}
|
||||
@@ -94,9 +89,8 @@ mod aio_fsync {
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
let fd = f.as_raw_fd();
|
||||
let mut aiof = Box::pin(AioFsync::new(
|
||||
fd,
|
||||
f.as_fd(),
|
||||
AioFsyncMode::O_SYNC,
|
||||
0,
|
||||
SigevNotify::SigevNone,
|
||||
@@ -112,9 +106,10 @@ mod aio_read {
|
||||
|
||||
#[test]
|
||||
fn test_accessors() {
|
||||
let f = tempfile().unwrap();
|
||||
let mut rbuf = vec![0; 4];
|
||||
let aiocb = AioRead::new(
|
||||
1001,
|
||||
f.as_fd(),
|
||||
2, //offset
|
||||
&mut rbuf,
|
||||
42, //priority
|
||||
@@ -123,7 +118,7 @@ mod aio_read {
|
||||
si_value: 99,
|
||||
},
|
||||
);
|
||||
assert_eq!(1001, aiocb.fd());
|
||||
assert_eq!(f.as_raw_fd(), aiocb.fd().as_raw_fd());
|
||||
assert_eq!(4, aiocb.nbytes());
|
||||
assert_eq!(2, aiocb.offset());
|
||||
assert_eq!(42, aiocb.priority());
|
||||
@@ -142,7 +137,7 @@ mod aio_read {
|
||||
let mut rbuf = vec![0; 4];
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
let fd = f.as_raw_fd();
|
||||
let fd = f.as_fd();
|
||||
let mut aior =
|
||||
Box::pin(AioRead::new(fd, 2, &mut rbuf, 0, SigevNotify::SigevNone));
|
||||
aior.as_mut().submit().unwrap();
|
||||
@@ -159,14 +154,14 @@ mod aio_read {
|
||||
// Skip on Linux, because Linux's AIO implementation can't detect errors
|
||||
// synchronously
|
||||
#[test]
|
||||
#[cfg(any(target_os = "freebsd", target_os = "macos"))]
|
||||
#[cfg(any(target_os = "freebsd", apple_targets))]
|
||||
fn error() {
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
let mut rbuf = vec![0; 4];
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
let mut aior = Box::pin(AioRead::new(
|
||||
f.as_raw_fd(),
|
||||
f.as_fd(),
|
||||
-1, //an invalid offset
|
||||
&mut rbuf,
|
||||
0, //priority
|
||||
@@ -186,7 +181,7 @@ mod aio_read {
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
{
|
||||
let fd = f.as_raw_fd();
|
||||
let fd = f.as_fd();
|
||||
let mut aior = Box::pin(AioRead::new(
|
||||
fd,
|
||||
2,
|
||||
@@ -213,7 +208,7 @@ mod aio_read {
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
{
|
||||
let fd = f.as_raw_fd();
|
||||
let fd = f.as_fd();
|
||||
let mut aior =
|
||||
AioRead::new(fd, 2, &mut rbuf, 0, SigevNotify::SigevNone);
|
||||
let mut aior = unsafe { Pin::new_unchecked(&mut aior) };
|
||||
@@ -236,12 +231,13 @@ mod aio_readv {
|
||||
|
||||
#[test]
|
||||
fn test_accessors() {
|
||||
let f = tempfile().unwrap();
|
||||
let mut rbuf0 = vec![0; 4];
|
||||
let mut rbuf1 = vec![0; 8];
|
||||
let mut rbufs =
|
||||
[IoSliceMut::new(&mut rbuf0), IoSliceMut::new(&mut rbuf1)];
|
||||
let aiocb = AioReadv::new(
|
||||
1001,
|
||||
f.as_fd(),
|
||||
2, //offset
|
||||
&mut rbufs,
|
||||
42, //priority
|
||||
@@ -250,7 +246,7 @@ mod aio_readv {
|
||||
si_value: 99,
|
||||
},
|
||||
);
|
||||
assert_eq!(1001, aiocb.fd());
|
||||
assert_eq!(f.as_raw_fd(), aiocb.fd().as_raw_fd());
|
||||
assert_eq!(2, aiocb.iovlen());
|
||||
assert_eq!(2, aiocb.offset());
|
||||
assert_eq!(42, aiocb.priority());
|
||||
@@ -272,7 +268,7 @@ mod aio_readv {
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
{
|
||||
let fd = f.as_raw_fd();
|
||||
let fd = f.as_fd();
|
||||
let mut aior = Box::pin(AioReadv::new(
|
||||
fd,
|
||||
2,
|
||||
@@ -299,9 +295,10 @@ mod aio_write {
|
||||
|
||||
#[test]
|
||||
fn test_accessors() {
|
||||
let f = tempfile().unwrap();
|
||||
let wbuf = vec![0; 4];
|
||||
let aiocb = AioWrite::new(
|
||||
1001,
|
||||
f.as_fd(),
|
||||
2, //offset
|
||||
&wbuf,
|
||||
42, //priority
|
||||
@@ -310,7 +307,7 @@ mod aio_write {
|
||||
si_value: 99,
|
||||
},
|
||||
);
|
||||
assert_eq!(1001, aiocb.fd());
|
||||
assert_eq!(f.as_raw_fd(), aiocb.fd().as_raw_fd());
|
||||
assert_eq!(4, aiocb.nbytes());
|
||||
assert_eq!(2, aiocb.offset());
|
||||
assert_eq!(42, aiocb.priority());
|
||||
@@ -329,7 +326,7 @@ mod aio_write {
|
||||
|
||||
let f = tempfile().unwrap();
|
||||
let mut aiow = Box::pin(AioWrite::new(
|
||||
f.as_raw_fd(),
|
||||
f.as_fd(),
|
||||
0,
|
||||
wbuf,
|
||||
0,
|
||||
@@ -358,18 +355,20 @@ mod aio_write {
|
||||
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
let mut aiow = Box::pin(AioWrite::new(
|
||||
f.as_raw_fd(),
|
||||
2,
|
||||
&wbuf,
|
||||
0,
|
||||
SigevNotify::SigevNone,
|
||||
));
|
||||
aiow.as_mut().submit().unwrap();
|
||||
{
|
||||
let mut aiow = Box::pin(AioWrite::new(
|
||||
f.as_fd(),
|
||||
2,
|
||||
&wbuf,
|
||||
0,
|
||||
SigevNotify::SigevNone,
|
||||
));
|
||||
aiow.as_mut().submit().unwrap();
|
||||
|
||||
let err = poll_aio!(&mut aiow);
|
||||
assert_eq!(err, Ok(()));
|
||||
assert_eq!(aiow.as_mut().aio_return().unwrap(), wbuf.len());
|
||||
let err = poll_aio!(&mut aiow);
|
||||
assert_eq!(err, Ok(()));
|
||||
assert_eq!(aiow.as_mut().aio_return().unwrap(), wbuf.len());
|
||||
}
|
||||
|
||||
f.rewind().unwrap();
|
||||
let len = f.read_to_end(&mut rbuf).unwrap();
|
||||
@@ -388,19 +387,21 @@ mod aio_write {
|
||||
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
let mut aiow = AioWrite::new(
|
||||
f.as_raw_fd(),
|
||||
2, //offset
|
||||
&wbuf,
|
||||
0, //priority
|
||||
SigevNotify::SigevNone,
|
||||
);
|
||||
let mut aiow = unsafe { Pin::new_unchecked(&mut aiow) };
|
||||
aiow.as_mut().submit().unwrap();
|
||||
{
|
||||
let mut aiow = AioWrite::new(
|
||||
f.as_fd(),
|
||||
2, //offset
|
||||
&wbuf,
|
||||
0, //priority
|
||||
SigevNotify::SigevNone,
|
||||
);
|
||||
let mut aiow = unsafe { Pin::new_unchecked(&mut aiow) };
|
||||
aiow.as_mut().submit().unwrap();
|
||||
|
||||
let err = poll_aio!(&mut aiow);
|
||||
assert_eq!(err, Ok(()));
|
||||
assert_eq!(aiow.as_mut().aio_return().unwrap(), wbuf.len());
|
||||
let err = poll_aio!(&mut aiow);
|
||||
assert_eq!(err, Ok(()));
|
||||
assert_eq!(aiow.as_mut().aio_return().unwrap(), wbuf.len());
|
||||
}
|
||||
|
||||
f.rewind().unwrap();
|
||||
let len = f.read_to_end(&mut rbuf).unwrap();
|
||||
@@ -413,12 +414,14 @@ mod aio_write {
|
||||
// Skip on Linux, because Linux's AIO implementation can't detect errors
|
||||
// synchronously
|
||||
#[test]
|
||||
#[cfg(any(target_os = "freebsd", target_os = "macos"))]
|
||||
#[cfg_attr(any(target_os = "android", target_os = "linux"), ignore)]
|
||||
fn error() {
|
||||
// Not I/O safe! Deliberately create an invalid fd.
|
||||
let fd = unsafe { BorrowedFd::borrow_raw(666) };
|
||||
let wbuf = "CDEF".to_string().into_bytes();
|
||||
let mut aiow = Box::pin(AioWrite::new(
|
||||
666, // An invalid file descriptor
|
||||
0, //offset
|
||||
fd,
|
||||
0, //offset
|
||||
&wbuf,
|
||||
0, //priority
|
||||
SigevNotify::SigevNone,
|
||||
@@ -437,11 +440,12 @@ mod aio_writev {
|
||||
|
||||
#[test]
|
||||
fn test_accessors() {
|
||||
let f = tempfile().unwrap();
|
||||
let wbuf0 = vec![0; 4];
|
||||
let wbuf1 = vec![0; 8];
|
||||
let wbufs = [IoSlice::new(&wbuf0), IoSlice::new(&wbuf1)];
|
||||
let aiocb = AioWritev::new(
|
||||
1001,
|
||||
f.as_fd(),
|
||||
2, //offset
|
||||
&wbufs,
|
||||
42, //priority
|
||||
@@ -450,7 +454,7 @@ mod aio_writev {
|
||||
si_value: 99,
|
||||
},
|
||||
);
|
||||
assert_eq!(1001, aiocb.fd());
|
||||
assert_eq!(f.as_raw_fd(), aiocb.fd().as_raw_fd());
|
||||
assert_eq!(2, aiocb.iovlen());
|
||||
assert_eq!(2, aiocb.offset());
|
||||
assert_eq!(42, aiocb.priority());
|
||||
@@ -474,18 +478,20 @@ mod aio_writev {
|
||||
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
let mut aiow = Box::pin(AioWritev::new(
|
||||
f.as_raw_fd(),
|
||||
1,
|
||||
&wbufs,
|
||||
0,
|
||||
SigevNotify::SigevNone,
|
||||
));
|
||||
aiow.as_mut().submit().unwrap();
|
||||
{
|
||||
let mut aiow = Box::pin(AioWritev::new(
|
||||
f.as_fd(),
|
||||
1,
|
||||
&wbufs,
|
||||
0,
|
||||
SigevNotify::SigevNone,
|
||||
));
|
||||
aiow.as_mut().submit().unwrap();
|
||||
|
||||
let err = poll_aio!(&mut aiow);
|
||||
assert_eq!(err, Ok(()));
|
||||
assert_eq!(aiow.as_mut().aio_return().unwrap(), wlen);
|
||||
let err = poll_aio!(&mut aiow);
|
||||
assert_eq!(err, Ok(()));
|
||||
assert_eq!(aiow.as_mut().aio_return().unwrap(), wlen);
|
||||
}
|
||||
|
||||
f.rewind().unwrap();
|
||||
let len = f.read_to_end(&mut rbuf).unwrap();
|
||||
@@ -500,7 +506,9 @@ mod aio_writev {
|
||||
any(
|
||||
all(target_env = "musl", target_arch = "x86_64"),
|
||||
target_arch = "mips",
|
||||
target_arch = "mips64"
|
||||
target_arch = "mips32r6",
|
||||
target_arch = "mips64",
|
||||
target_arch = "mips64r6"
|
||||
),
|
||||
ignore
|
||||
)]
|
||||
@@ -521,22 +529,25 @@ fn sigev_signal() {
|
||||
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
let mut aiow = Box::pin(AioWrite::new(
|
||||
f.as_raw_fd(),
|
||||
2, //offset
|
||||
WBUF,
|
||||
0, //priority
|
||||
SigevNotify::SigevSignal {
|
||||
signal: Signal::SIGUSR2,
|
||||
si_value: 0, //TODO: validate in sigfunc
|
||||
},
|
||||
));
|
||||
aiow.as_mut().submit().unwrap();
|
||||
while !SIGNALED.load(Ordering::Relaxed) {
|
||||
thread::sleep(time::Duration::from_millis(10));
|
||||
{
|
||||
let mut aiow = Box::pin(AioWrite::new(
|
||||
f.as_fd(),
|
||||
2, //offset
|
||||
WBUF,
|
||||
0, //priority
|
||||
SigevNotify::SigevSignal {
|
||||
signal: Signal::SIGUSR2,
|
||||
si_value: 0, //TODO: validate in sigfunc
|
||||
},
|
||||
));
|
||||
aiow.as_mut().submit().unwrap();
|
||||
while !SIGNALED.load(Ordering::Relaxed) {
|
||||
thread::sleep(time::Duration::from_millis(10));
|
||||
}
|
||||
|
||||
assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len());
|
||||
}
|
||||
|
||||
assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len());
|
||||
f.rewind().unwrap();
|
||||
let len = f.read_to_end(&mut rbuf).unwrap();
|
||||
assert_eq!(len, EXPECT.len());
|
||||
@@ -551,7 +562,7 @@ fn test_aio_cancel_all() {
|
||||
|
||||
let f = tempfile().unwrap();
|
||||
let mut aiocb = Box::pin(AioWrite::new(
|
||||
f.as_raw_fd(),
|
||||
f.as_fd(),
|
||||
0, //offset
|
||||
wbuf,
|
||||
0, //priority
|
||||
@@ -561,7 +572,7 @@ fn test_aio_cancel_all() {
|
||||
let err = aiocb.as_mut().error();
|
||||
assert!(err == Ok(()) || err == Err(Errno::EINPROGRESS));
|
||||
|
||||
aio_cancel_all(f.as_raw_fd()).unwrap();
|
||||
aio_cancel_all(f.as_fd()).unwrap();
|
||||
|
||||
// Wait for aiocb to complete, but don't care whether it succeeded
|
||||
let _ = poll_aio!(&mut aiocb);
|
||||
@@ -569,12 +580,6 @@ fn test_aio_cancel_all() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
// On Cirrus on Linux, this test fails due to a glibc bug.
|
||||
// https://github.com/nix-rust/nix/issues/1099
|
||||
#[cfg_attr(target_os = "linux", ignore)]
|
||||
// On Cirrus, aio_suspend is failing with EINVAL
|
||||
// https://github.com/nix-rust/nix/issues/1361
|
||||
#[cfg_attr(target_os = "macos", ignore)]
|
||||
fn test_aio_suspend() {
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
const WBUF: &[u8] = b"CDEFG";
|
||||
@@ -585,7 +590,7 @@ fn test_aio_suspend() {
|
||||
f.write_all(INITIAL).unwrap();
|
||||
|
||||
let mut wcb = Box::pin(AioWrite::new(
|
||||
f.as_raw_fd(),
|
||||
f.as_fd(),
|
||||
2, //offset
|
||||
WBUF,
|
||||
0, //priority
|
||||
@@ -593,7 +598,7 @@ fn test_aio_suspend() {
|
||||
));
|
||||
|
||||
let mut rcb = Box::pin(AioRead::new(
|
||||
f.as_raw_fd(),
|
||||
f.as_fd(),
|
||||
8, //offset
|
||||
&mut rbuf,
|
||||
0, //priority
|
||||
@@ -610,7 +615,7 @@ fn test_aio_suspend() {
|
||||
let r = aio_suspend(&cbbuf[..], Some(timeout));
|
||||
match r {
|
||||
Err(Errno::EINTR) => continue,
|
||||
Err(e) => panic!("aio_suspend returned {:?}", e),
|
||||
Err(e) => panic!("aio_suspend returned {e:?}"),
|
||||
Ok(_) => (),
|
||||
};
|
||||
}
|
||||
@@ -624,3 +629,57 @@ fn test_aio_suspend() {
|
||||
assert_eq!(wcb.as_mut().aio_return().unwrap(), WBUF.len());
|
||||
assert_eq!(rcb.as_mut().aio_return().unwrap(), rlen);
|
||||
}
|
||||
|
||||
/// aio_suspend relies on casting Rust Aio* struct pointers to libc::aiocb
|
||||
/// pointers. This test ensures that such casts are valid.
|
||||
#[test]
|
||||
fn casting() {
|
||||
let sev = SigevNotify::SigevNone;
|
||||
// Only safe because we'll never await the futures
|
||||
let fd = unsafe { BorrowedFd::borrow_raw(666) };
|
||||
let aiof = AioFsync::new(fd, AioFsyncMode::O_SYNC, 0, sev);
|
||||
assert_eq!(
|
||||
aiof.as_ref() as *const libc::aiocb,
|
||||
&aiof as *const AioFsync as *const libc::aiocb
|
||||
);
|
||||
|
||||
let mut rbuf = [];
|
||||
let aior = AioRead::new(fd, 0, &mut rbuf, 0, sev);
|
||||
assert_eq!(
|
||||
aior.as_ref() as *const libc::aiocb,
|
||||
&aior as *const AioRead as *const libc::aiocb
|
||||
);
|
||||
|
||||
let wbuf = [];
|
||||
let aiow = AioWrite::new(fd, 0, &wbuf, 0, sev);
|
||||
assert_eq!(
|
||||
aiow.as_ref() as *const libc::aiocb,
|
||||
&aiow as *const AioWrite as *const libc::aiocb
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[test]
|
||||
fn casting_vectored() {
|
||||
use std::io::{IoSlice, IoSliceMut};
|
||||
|
||||
let sev = SigevNotify::SigevNone;
|
||||
|
||||
let mut rbuf = [];
|
||||
let mut rbufs = [IoSliceMut::new(&mut rbuf)];
|
||||
// Only safe because we'll never await the futures
|
||||
let fd = unsafe { BorrowedFd::borrow_raw(666) };
|
||||
let aiorv = AioReadv::new(fd, 0, &mut rbufs[..], 0, sev);
|
||||
assert_eq!(
|
||||
aiorv.as_ref() as *const libc::aiocb,
|
||||
&aiorv as *const AioReadv as *const libc::aiocb
|
||||
);
|
||||
|
||||
let wbuf = [];
|
||||
let wbufs = [IoSlice::new(&wbuf)];
|
||||
let aiowv = AioWritev::new(fd, 0, &wbufs, 0, sev);
|
||||
assert_eq!(
|
||||
aiowv.as_ref() as *const libc::aiocb,
|
||||
&aiowv as *const AioWritev as *const libc::aiocb
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
#[cfg(all(
|
||||
not(target_env = "musl"),
|
||||
not(target_env = "uclibc"),
|
||||
not(target_env = "ohos"),
|
||||
any(
|
||||
target_os = "linux",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
apple_targets,
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd"
|
||||
)
|
||||
@@ -17,7 +17,7 @@
|
||||
fn test_drop() {
|
||||
use nix::sys::aio::*;
|
||||
use nix::sys::signal::*;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::os::unix::io::AsFd;
|
||||
use tempfile::tempfile;
|
||||
|
||||
const WBUF: &[u8] = b"CDEF";
|
||||
@@ -25,7 +25,7 @@ fn test_drop() {
|
||||
let f = tempfile().unwrap();
|
||||
f.set_len(6).unwrap();
|
||||
let mut aiocb = Box::pin(AioWrite::new(
|
||||
f.as_raw_fd(),
|
||||
f.as_fd(),
|
||||
2, //offset
|
||||
WBUF,
|
||||
0, //priority
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#![allow(deprecated)]
|
||||
|
||||
use nix::errno::Errno;
|
||||
use nix::sys::epoll::{epoll_create1, epoll_ctl};
|
||||
use nix::sys::epoll::{EpollCreateFlags, EpollEvent, EpollFlags, EpollOp};
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
use libc::intptr_t;
|
||||
use nix::sys::event::{EvFlags, EventFilter, FilterFlag, KEvent};
|
||||
|
||||
#[test]
|
||||
fn test_struct_kevent() {
|
||||
use std::mem;
|
||||
|
||||
let udata: intptr_t = 12345;
|
||||
let data: intptr_t = 0x1337;
|
||||
|
||||
let actual = KEvent::new(
|
||||
0xdead_beef,
|
||||
EventFilter::EVFILT_READ,
|
||||
EvFlags::EV_ONESHOT | EvFlags::EV_ADD,
|
||||
FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT,
|
||||
data,
|
||||
udata,
|
||||
);
|
||||
assert_eq!(0xdead_beef, actual.ident());
|
||||
assert_eq!(EventFilter::EVFILT_READ, actual.filter().unwrap());
|
||||
assert_eq!(libc::EV_ONESHOT | libc::EV_ADD, actual.flags().bits());
|
||||
assert_eq!(libc::NOTE_CHILD | libc::NOTE_EXIT, actual.fflags().bits());
|
||||
assert_eq!(data, actual.data());
|
||||
assert_eq!(udata, actual.udata());
|
||||
assert_eq!(mem::size_of::<libc::kevent>(), mem::size_of::<KEvent>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_kevent_filter() {
|
||||
let udata: intptr_t = 12345;
|
||||
|
||||
let actual = KEvent::new(
|
||||
0xdead_beef,
|
||||
EventFilter::EVFILT_READ,
|
||||
EvFlags::EV_ONESHOT | EvFlags::EV_ADD,
|
||||
FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT,
|
||||
0x1337,
|
||||
udata,
|
||||
);
|
||||
assert_eq!(EventFilter::EVFILT_READ, actual.filter().unwrap());
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
use crate::*;
|
||||
use nix::errno::Errno;
|
||||
use nix::fcntl::AT_FDCWD;
|
||||
use nix::sys::fanotify::{
|
||||
EventFFlags, Fanotify, FanotifyResponse, InitFlags, MarkFlags, MaskFlags,
|
||||
Response,
|
||||
};
|
||||
use std::fs::{read_link, read_to_string, File, OpenOptions};
|
||||
use std::io::ErrorKind;
|
||||
use std::io::{Read, Write};
|
||||
use std::os::fd::AsRawFd;
|
||||
use std::thread;
|
||||
|
||||
#[test]
|
||||
/// Run fanotify tests sequentially to avoid tmp files races
|
||||
pub fn test_fanotify() {
|
||||
require_capability!("test_fanotify", CAP_SYS_ADMIN);
|
||||
|
||||
test_fanotify_notifications();
|
||||
test_fanotify_responses();
|
||||
test_fanotify_overflow();
|
||||
}
|
||||
|
||||
fn test_fanotify_notifications() {
|
||||
let group =
|
||||
Fanotify::init(InitFlags::FAN_CLASS_NOTIF, EventFFlags::O_RDONLY)
|
||||
.unwrap();
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
let tempfile = tempdir.path().join("test");
|
||||
OpenOptions::new()
|
||||
.write(true)
|
||||
.create_new(true)
|
||||
.open(&tempfile)
|
||||
.unwrap();
|
||||
|
||||
group
|
||||
.mark(
|
||||
MarkFlags::FAN_MARK_ADD,
|
||||
MaskFlags::FAN_OPEN | MaskFlags::FAN_MODIFY | MaskFlags::FAN_CLOSE,
|
||||
AT_FDCWD,
|
||||
Some(&tempfile),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// modify test file
|
||||
{
|
||||
let mut f = OpenOptions::new().write(true).open(&tempfile).unwrap();
|
||||
f.write_all(b"hello").unwrap();
|
||||
}
|
||||
|
||||
let mut events = group.read_events().unwrap();
|
||||
assert_eq!(events.len(), 1, "should have read exactly one event");
|
||||
let event = events.pop().unwrap();
|
||||
assert!(event.check_version());
|
||||
assert_eq!(
|
||||
event.mask(),
|
||||
MaskFlags::FAN_OPEN
|
||||
| MaskFlags::FAN_MODIFY
|
||||
| MaskFlags::FAN_CLOSE_WRITE
|
||||
);
|
||||
let fd_opt = event.fd();
|
||||
let fd = fd_opt.as_ref().unwrap();
|
||||
let path = read_link(format!("/proc/self/fd/{}", fd.as_raw_fd())).unwrap();
|
||||
assert_eq!(path, tempfile);
|
||||
|
||||
// read test file
|
||||
{
|
||||
let mut f = File::open(&tempfile).unwrap();
|
||||
let mut s = String::new();
|
||||
f.read_to_string(&mut s).unwrap();
|
||||
}
|
||||
|
||||
let mut events = group.read_events().unwrap();
|
||||
assert_eq!(events.len(), 1, "should have read exactly one event");
|
||||
let event = events.pop().unwrap();
|
||||
assert!(event.check_version());
|
||||
assert_eq!(
|
||||
event.mask(),
|
||||
MaskFlags::FAN_OPEN | MaskFlags::FAN_CLOSE_NOWRITE
|
||||
);
|
||||
let fd_opt = event.fd();
|
||||
let fd = fd_opt.as_ref().unwrap();
|
||||
let path = read_link(format!("/proc/self/fd/{}", fd.as_raw_fd())).unwrap();
|
||||
assert_eq!(path, tempfile);
|
||||
}
|
||||
|
||||
fn test_fanotify_responses() {
|
||||
let group =
|
||||
Fanotify::init(InitFlags::FAN_CLASS_CONTENT, EventFFlags::O_RDONLY)
|
||||
.unwrap();
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
let tempfile = tempdir.path().join("test");
|
||||
OpenOptions::new()
|
||||
.write(true)
|
||||
.create_new(true)
|
||||
.open(&tempfile)
|
||||
.unwrap();
|
||||
|
||||
group
|
||||
.mark(
|
||||
MarkFlags::FAN_MARK_ADD,
|
||||
MaskFlags::FAN_OPEN_PERM,
|
||||
AT_FDCWD,
|
||||
Some(&tempfile),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let file_thread = thread::spawn({
|
||||
let tempfile = tempfile.clone();
|
||||
|
||||
move || {
|
||||
// first open, should fail
|
||||
let Err(e) = File::open(&tempfile) else {
|
||||
panic!("The first open should fail");
|
||||
};
|
||||
assert_eq!(e.kind(), ErrorKind::PermissionDenied);
|
||||
|
||||
// second open, should succeed
|
||||
File::open(&tempfile).unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
// Deny the first open try
|
||||
let mut events = group.read_events().unwrap();
|
||||
assert_eq!(events.len(), 1, "should have read exactly one event");
|
||||
let event = events.pop().unwrap();
|
||||
assert!(event.check_version());
|
||||
assert_eq!(event.mask(), MaskFlags::FAN_OPEN_PERM);
|
||||
let fd_opt = event.fd();
|
||||
let fd = fd_opt.as_ref().unwrap();
|
||||
let path = read_link(format!("/proc/self/fd/{}", fd.as_raw_fd())).unwrap();
|
||||
assert_eq!(path, tempfile);
|
||||
group
|
||||
.write_response(FanotifyResponse::new(*fd, Response::FAN_DENY))
|
||||
.unwrap();
|
||||
|
||||
// Allow the second open try
|
||||
let mut events = group.read_events().unwrap();
|
||||
assert_eq!(events.len(), 1, "should have read exactly one event");
|
||||
let event = events.pop().unwrap();
|
||||
assert!(event.check_version());
|
||||
assert_eq!(event.mask(), MaskFlags::FAN_OPEN_PERM);
|
||||
let fd_opt = event.fd();
|
||||
let fd = fd_opt.as_ref().unwrap();
|
||||
let path = read_link(format!("/proc/self/fd/{}", fd.as_raw_fd())).unwrap();
|
||||
assert_eq!(path, tempfile);
|
||||
group
|
||||
.write_response(FanotifyResponse::new(*fd, Response::FAN_ALLOW))
|
||||
.unwrap();
|
||||
|
||||
file_thread.join().unwrap();
|
||||
}
|
||||
|
||||
fn test_fanotify_overflow() {
|
||||
let max_events: usize =
|
||||
read_to_string("/proc/sys/fs/fanotify/max_queued_events")
|
||||
.unwrap()
|
||||
.trim()
|
||||
.parse()
|
||||
.unwrap();
|
||||
|
||||
// make sure the kernel is configured with the default value,
|
||||
// just so this test doesn't run forever
|
||||
assert_eq!(max_events, 16384);
|
||||
|
||||
let group = Fanotify::init(
|
||||
InitFlags::FAN_CLASS_NOTIF
|
||||
| InitFlags::FAN_REPORT_TID
|
||||
| InitFlags::FAN_NONBLOCK,
|
||||
EventFFlags::O_RDONLY,
|
||||
)
|
||||
.unwrap();
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
let tempfile = tempdir.path().join("test");
|
||||
|
||||
OpenOptions::new()
|
||||
.write(true)
|
||||
.create_new(true)
|
||||
.open(&tempfile)
|
||||
.unwrap();
|
||||
|
||||
group
|
||||
.mark(
|
||||
MarkFlags::FAN_MARK_ADD,
|
||||
MaskFlags::FAN_OPEN,
|
||||
AT_FDCWD,
|
||||
Some(&tempfile),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
thread::scope(|s| {
|
||||
// perform 10 more events to demonstrate some will be dropped
|
||||
for _ in 0..(max_events + 10) {
|
||||
s.spawn(|| {
|
||||
File::open(&tempfile).unwrap();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// flush the queue until it's empty
|
||||
let mut n = 0;
|
||||
let mut last_event = None;
|
||||
loop {
|
||||
match group.read_events() {
|
||||
Ok(events) => {
|
||||
n += events.len();
|
||||
if let Some(event) = events.last() {
|
||||
last_event = Some(event.mask());
|
||||
}
|
||||
}
|
||||
Err(e) if e == Errno::EWOULDBLOCK => break,
|
||||
Err(e) => panic!("{e:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
// make sure we read all we expected.
|
||||
// the +1 is for the overflow event.
|
||||
assert_eq!(n, max_events + 1);
|
||||
assert_eq!(last_event, Some(MaskFlags::FAN_Q_OVERFLOW));
|
||||
}
|
||||
+20
-13
@@ -28,7 +28,7 @@ ioctl_readwrite_buf!(readwritebuf_test, 0, 0, u32);
|
||||
// TODO: Need a way to compute these constants at test time. Using precomputed
|
||||
// values is fragile and needs to be maintained.
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[cfg(linux_android)]
|
||||
mod linux {
|
||||
// The cast is not unnecessary on all platforms.
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
@@ -36,7 +36,9 @@ mod linux {
|
||||
fn test_op_none() {
|
||||
if cfg!(any(
|
||||
target_arch = "mips",
|
||||
target_arch = "mips32r6",
|
||||
target_arch = "mips64",
|
||||
target_arch = "mips64r6",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64"
|
||||
)) {
|
||||
@@ -54,7 +56,9 @@ mod linux {
|
||||
fn test_op_write() {
|
||||
if cfg!(any(
|
||||
target_arch = "mips",
|
||||
target_arch = "mips32r6",
|
||||
target_arch = "mips64",
|
||||
target_arch = "mips64r6",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64"
|
||||
)) {
|
||||
@@ -69,7 +73,11 @@ mod linux {
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[test]
|
||||
fn test_op_write_64() {
|
||||
if cfg!(any(target_arch = "mips64", target_arch = "powerpc64")) {
|
||||
if cfg!(any(
|
||||
target_arch = "mips64",
|
||||
target_arch = "mips64r6",
|
||||
target_arch = "powerpc64"
|
||||
)) {
|
||||
assert_eq!(
|
||||
request_code_write!(b'z', 10, 1u64 << 32) as u32,
|
||||
0x8000_7A0A
|
||||
@@ -88,7 +96,9 @@ mod linux {
|
||||
fn test_op_read() {
|
||||
if cfg!(any(
|
||||
target_arch = "mips",
|
||||
target_arch = "mips32r6",
|
||||
target_arch = "mips64",
|
||||
target_arch = "mips64r6",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64"
|
||||
)) {
|
||||
@@ -103,7 +113,11 @@ mod linux {
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[test]
|
||||
fn test_op_read_64() {
|
||||
if cfg!(any(target_arch = "mips64", target_arch = "powerpc64")) {
|
||||
if cfg!(any(
|
||||
target_arch = "mips64",
|
||||
target_arch = "mips64r6",
|
||||
target_arch = "powerpc64"
|
||||
)) {
|
||||
assert_eq!(
|
||||
request_code_read!(b'z', 10, 1u64 << 32) as u32,
|
||||
0x4000_7A0A
|
||||
@@ -134,14 +148,7 @@ mod linux {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
#[cfg(bsd)]
|
||||
mod bsd {
|
||||
#[test]
|
||||
fn test_op_none() {
|
||||
@@ -149,7 +156,7 @@ mod bsd {
|
||||
assert_eq!(request_code_none!(b'a', 255), 0x2000_61FF);
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
|
||||
#[cfg(freebsdlike)]
|
||||
#[test]
|
||||
fn test_op_write_int() {
|
||||
assert_eq!(request_code_write_int!(b'v', 4), 0x2004_7604);
|
||||
@@ -193,7 +200,7 @@ mod bsd {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
mod linux_ioctls {
|
||||
use std::mem;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#[test]
|
||||
fn test_memfd_create() {
|
||||
use nix::sys::memfd::memfd_create;
|
||||
use nix::sys::memfd::MFdFlags;
|
||||
use nix::unistd::lseek;
|
||||
use nix::unistd::read;
|
||||
use nix::unistd::{write, Whence};
|
||||
|
||||
let fd =
|
||||
memfd_create("test_memfd_create_name", MFdFlags::MFD_CLOEXEC).unwrap();
|
||||
let contents = b"hello";
|
||||
assert_eq!(write(&fd, contents).unwrap(), 5);
|
||||
|
||||
lseek(&fd, 0, Whence::SeekSet).unwrap();
|
||||
|
||||
let mut buf = vec![0_u8; contents.len()];
|
||||
assert_eq!(read(&fd, &mut buf).unwrap(), 5);
|
||||
|
||||
assert_eq!(contents, buf.as_slice());
|
||||
}
|
||||
+105
-27
@@ -1,44 +1,44 @@
|
||||
use nix::sys::mman::{mmap, MapFlags, ProtFlags};
|
||||
#![allow(clippy::redundant_slicing)]
|
||||
|
||||
use nix::sys::mman::{mmap_anonymous, MapFlags, ProtFlags};
|
||||
use std::num::NonZeroUsize;
|
||||
|
||||
#[test]
|
||||
fn test_mmap_anonymous() {
|
||||
unsafe {
|
||||
let ptr = mmap(
|
||||
let mut ptr = mmap_anonymous(
|
||||
None,
|
||||
NonZeroUsize::new(1).unwrap(),
|
||||
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
|
||||
MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS,
|
||||
-1,
|
||||
0,
|
||||
MapFlags::MAP_PRIVATE,
|
||||
)
|
||||
.unwrap() as *mut u8;
|
||||
assert_eq!(*ptr, 0x00u8);
|
||||
*ptr = 0xffu8;
|
||||
assert_eq!(*ptr, 0xffu8);
|
||||
.unwrap()
|
||||
.cast::<u8>();
|
||||
assert_eq!(*ptr.as_ref(), 0x00u8);
|
||||
*ptr.as_mut() = 0xffu8;
|
||||
assert_eq!(*ptr.as_ref(), 0xffu8);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(target_os = "linux", target_os = "netbsd"))]
|
||||
fn test_mremap_grow() {
|
||||
use nix::libc::{c_void, size_t};
|
||||
use nix::libc::size_t;
|
||||
use nix::sys::mman::{mremap, MRemapFlags};
|
||||
use std::ptr::NonNull;
|
||||
|
||||
const ONE_K: size_t = 1024;
|
||||
let one_k_non_zero = NonZeroUsize::new(ONE_K).unwrap();
|
||||
|
||||
let slice: &mut [u8] = unsafe {
|
||||
let mem = mmap(
|
||||
let mem = mmap_anonymous(
|
||||
None,
|
||||
one_k_non_zero,
|
||||
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
|
||||
MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE,
|
||||
-1,
|
||||
0,
|
||||
MapFlags::MAP_PRIVATE,
|
||||
)
|
||||
.unwrap();
|
||||
std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K)
|
||||
std::slice::from_raw_parts_mut(mem.as_ptr().cast(), ONE_K)
|
||||
};
|
||||
assert_eq!(slice[ONE_K - 1], 0x00);
|
||||
slice[ONE_K - 1] = 0xFF;
|
||||
@@ -47,7 +47,7 @@ fn test_mremap_grow() {
|
||||
let slice: &mut [u8] = unsafe {
|
||||
#[cfg(target_os = "linux")]
|
||||
let mem = mremap(
|
||||
slice.as_mut_ptr() as *mut c_void,
|
||||
NonNull::from(&mut slice[..]).cast(),
|
||||
ONE_K,
|
||||
10 * ONE_K,
|
||||
MRemapFlags::MREMAP_MAYMOVE,
|
||||
@@ -56,14 +56,14 @@ fn test_mremap_grow() {
|
||||
.unwrap();
|
||||
#[cfg(target_os = "netbsd")]
|
||||
let mem = mremap(
|
||||
slice.as_mut_ptr() as *mut c_void,
|
||||
NonNull::from(&mut slice[..]).cast(),
|
||||
ONE_K,
|
||||
10 * ONE_K,
|
||||
MRemapFlags::MAP_REMAPDUP,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
std::slice::from_raw_parts_mut(mem as *mut u8, 10 * ONE_K)
|
||||
std::slice::from_raw_parts_mut(mem.cast().as_ptr(), 10 * ONE_K)
|
||||
};
|
||||
|
||||
// The first KB should still have the old data in it.
|
||||
@@ -80,23 +80,22 @@ fn test_mremap_grow() {
|
||||
// Segfaults for unknown reasons under QEMU for 32-bit targets
|
||||
#[cfg_attr(all(target_pointer_width = "32", qemu), ignore)]
|
||||
fn test_mremap_shrink() {
|
||||
use nix::libc::{c_void, size_t};
|
||||
use nix::libc::size_t;
|
||||
use nix::sys::mman::{mremap, MRemapFlags};
|
||||
use std::num::NonZeroUsize;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
const ONE_K: size_t = 1024;
|
||||
let ten_one_k = NonZeroUsize::new(10 * ONE_K).unwrap();
|
||||
let slice: &mut [u8] = unsafe {
|
||||
let mem = mmap(
|
||||
let mem = mmap_anonymous(
|
||||
None,
|
||||
ten_one_k,
|
||||
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
|
||||
MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE,
|
||||
-1,
|
||||
0,
|
||||
MapFlags::MAP_PRIVATE,
|
||||
)
|
||||
.unwrap();
|
||||
std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K)
|
||||
std::slice::from_raw_parts_mut(mem.as_ptr().cast(), ONE_K)
|
||||
};
|
||||
assert_eq!(slice[ONE_K - 1], 0x00);
|
||||
slice[ONE_K - 1] = 0xFF;
|
||||
@@ -104,7 +103,7 @@ fn test_mremap_shrink() {
|
||||
|
||||
let slice: &mut [u8] = unsafe {
|
||||
let mem = mremap(
|
||||
slice.as_mut_ptr() as *mut c_void,
|
||||
NonNull::from(&mut slice[..]).cast(),
|
||||
ten_one_k.into(),
|
||||
ONE_K,
|
||||
MRemapFlags::empty(),
|
||||
@@ -113,10 +112,89 @@ fn test_mremap_shrink() {
|
||||
.unwrap();
|
||||
// Since we didn't supply MREMAP_MAYMOVE, the address should be the
|
||||
// same.
|
||||
assert_eq!(mem, slice.as_mut_ptr() as *mut c_void);
|
||||
std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K)
|
||||
assert_eq!(mem.as_ptr(), NonNull::from(&mut slice[..]).cast().as_ptr());
|
||||
std::slice::from_raw_parts_mut(mem.as_ptr().cast(), ONE_K)
|
||||
};
|
||||
|
||||
// The first KB should still be accessible and have the old data in it.
|
||||
assert_eq!(slice[ONE_K - 1], 0xFF);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_mremap_dontunmap() {
|
||||
use nix::libc::size_t;
|
||||
use nix::sys::mman::{mremap, MRemapFlags};
|
||||
use std::num::NonZeroUsize;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
const ONE_K: size_t = 1024;
|
||||
let one_k_non_zero = NonZeroUsize::new(ONE_K).unwrap();
|
||||
|
||||
let slice: &mut [u8] = unsafe {
|
||||
let mem = mmap_anonymous(
|
||||
None,
|
||||
one_k_non_zero,
|
||||
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
|
||||
MapFlags::MAP_PRIVATE,
|
||||
)
|
||||
.unwrap();
|
||||
std::slice::from_raw_parts_mut(mem.as_ptr().cast(), ONE_K)
|
||||
};
|
||||
|
||||
// because we do not unmap `slice`, `old_size` and `new_size`
|
||||
// need to be equal or `EINVAL` is set.
|
||||
let _new_slice: &mut [u8] = unsafe {
|
||||
let mem = mremap(
|
||||
NonNull::from(&mut slice[..]).cast(),
|
||||
ONE_K,
|
||||
ONE_K,
|
||||
MRemapFlags::MREMAP_MAYMOVE | MRemapFlags::MREMAP_DONTUNMAP,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
std::slice::from_raw_parts_mut(mem.cast().as_ptr(), 10 * ONE_K)
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_madv_wipeonfork() {
|
||||
use nix::libc::size_t;
|
||||
use nix::sys::mman::{madvise, MmapAdvise};
|
||||
use nix::unistd::{fork, ForkResult};
|
||||
use std::num::NonZeroUsize;
|
||||
|
||||
const ONE_K: size_t = 1024;
|
||||
let ten_one_k = NonZeroUsize::new(10 * ONE_K).unwrap();
|
||||
let slice: &mut [u8] = unsafe {
|
||||
let mem = mmap_anonymous(
|
||||
None,
|
||||
ten_one_k,
|
||||
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
|
||||
MapFlags::MAP_PRIVATE,
|
||||
)
|
||||
.unwrap();
|
||||
madvise(mem, ONE_K, MmapAdvise::MADV_WIPEONFORK)
|
||||
.expect("madvise failed");
|
||||
std::slice::from_raw_parts_mut(mem.as_ptr().cast(), ONE_K)
|
||||
};
|
||||
slice[ONE_K - 1] = 0xFF;
|
||||
let _m = crate::FORK_MTX.lock();
|
||||
|
||||
unsafe {
|
||||
let res = fork().expect("fork failed");
|
||||
match res {
|
||||
ForkResult::Child => {
|
||||
// that s the whole point of MADV_WIPEONFORK
|
||||
assert_eq!(slice[ONE_K - 1], 0x00);
|
||||
libc::_exit(0);
|
||||
}
|
||||
ForkResult::Parent { child } => {
|
||||
nix::sys::signal::kill(child, nix::sys::signal::SIGTERM)
|
||||
.unwrap();
|
||||
let _ = nix::sys::wait::wait().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(feature = "process")]
|
||||
mod test_prctl {
|
||||
use std::ffi::CStr;
|
||||
|
||||
use nix::sys::prctl;
|
||||
|
||||
#[cfg_attr(qemu, ignore)]
|
||||
#[test]
|
||||
fn test_get_set_subreaper() {
|
||||
let original = prctl::get_child_subreaper().unwrap();
|
||||
|
||||
prctl::set_child_subreaper(true).unwrap();
|
||||
let subreaper = prctl::get_child_subreaper().unwrap();
|
||||
assert!(subreaper);
|
||||
|
||||
prctl::set_child_subreaper(original).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_set_dumpable() {
|
||||
let original = prctl::get_dumpable().unwrap();
|
||||
|
||||
prctl::set_dumpable(false).unwrap();
|
||||
let dumpable = prctl::get_dumpable().unwrap();
|
||||
assert!(!dumpable);
|
||||
|
||||
prctl::set_dumpable(original).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_set_keepcaps() {
|
||||
let original = prctl::get_keepcaps().unwrap();
|
||||
|
||||
prctl::set_keepcaps(true).unwrap();
|
||||
let keepcaps = prctl::get_keepcaps().unwrap();
|
||||
assert!(keepcaps);
|
||||
|
||||
prctl::set_keepcaps(original).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_set_clear_mce_kill() {
|
||||
use prctl::PrctlMCEKillPolicy::*;
|
||||
|
||||
prctl::set_mce_kill(PR_MCE_KILL_LATE).unwrap();
|
||||
let mce = prctl::get_mce_kill().unwrap();
|
||||
assert_eq!(mce, PR_MCE_KILL_LATE);
|
||||
|
||||
prctl::clear_mce_kill().unwrap();
|
||||
let mce = prctl::get_mce_kill().unwrap();
|
||||
assert_eq!(mce, PR_MCE_KILL_DEFAULT);
|
||||
}
|
||||
|
||||
#[cfg_attr(qemu, ignore)]
|
||||
#[test]
|
||||
fn test_get_set_pdeathsig() {
|
||||
use nix::sys::signal::Signal;
|
||||
|
||||
let original = prctl::get_pdeathsig().unwrap();
|
||||
|
||||
prctl::set_pdeathsig(Signal::SIGUSR1).unwrap();
|
||||
let sig = prctl::get_pdeathsig().unwrap();
|
||||
assert_eq!(sig, Some(Signal::SIGUSR1));
|
||||
|
||||
prctl::set_pdeathsig(original).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_set_name() {
|
||||
let original = prctl::get_name().unwrap();
|
||||
|
||||
let long_name =
|
||||
CStr::from_bytes_with_nul(b"0123456789abcdefghijklmn\0").unwrap();
|
||||
prctl::set_name(long_name).unwrap();
|
||||
let res = prctl::get_name().unwrap();
|
||||
|
||||
// name truncated by kernel to TASK_COMM_LEN
|
||||
assert_eq!(&long_name.to_str().unwrap()[..15], res.to_str().unwrap());
|
||||
|
||||
let short_name = CStr::from_bytes_with_nul(b"01234567\0").unwrap();
|
||||
prctl::set_name(short_name).unwrap();
|
||||
let res = prctl::get_name().unwrap();
|
||||
assert_eq!(short_name.to_str().unwrap(), res.to_str().unwrap());
|
||||
|
||||
prctl::set_name(&original).unwrap();
|
||||
}
|
||||
|
||||
#[cfg_attr(qemu, ignore)]
|
||||
#[test]
|
||||
fn test_get_set_timerslack() {
|
||||
let original = prctl::get_timerslack().unwrap() as libc::c_ulong;
|
||||
|
||||
let slack = 60_000;
|
||||
prctl::set_timerslack(slack).unwrap();
|
||||
let res = prctl::get_timerslack().unwrap() as libc::c_ulong;
|
||||
assert_eq!(slack, res);
|
||||
|
||||
prctl::set_timerslack(original).unwrap();
|
||||
}
|
||||
|
||||
// Loongarch need to use a newer QEMU that disabled these PRCTL subcodes/methods.
|
||||
// https://github.com/qemu/qemu/commit/220717a6f46a99031a5b1af964bbf4dec1310440
|
||||
// So we should ignore them when testing in QEMU environments.
|
||||
#[cfg_attr(all(qemu, target_arch = "loongarch64"), ignore)]
|
||||
#[test]
|
||||
fn test_disable_enable_perf_events() {
|
||||
prctl::task_perf_events_disable().unwrap();
|
||||
prctl::task_perf_events_enable().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_set_no_new_privs() {
|
||||
prctl::set_no_new_privs().unwrap();
|
||||
let no_new_privs = prctl::get_no_new_privs().unwrap();
|
||||
assert!(no_new_privs);
|
||||
}
|
||||
|
||||
// Loongarch need to use a newer QEMU that disabled these PRCTL subcodes/methods
|
||||
// https://github.com/qemu/qemu/commit/220717a6f46a99031a5b1af964bbf4dec1310440
|
||||
// So we should ignore them when testing in QEMU environments.
|
||||
#[cfg_attr(all(qemu, target_arch = "loongarch64"), ignore)]
|
||||
#[test]
|
||||
fn test_get_set_thp_disable() {
|
||||
let original = prctl::get_thp_disable().unwrap();
|
||||
|
||||
prctl::set_thp_disable(true).unwrap();
|
||||
let thp_disable = prctl::get_thp_disable().unwrap();
|
||||
assert!(thp_disable);
|
||||
|
||||
prctl::set_thp_disable(original).unwrap();
|
||||
}
|
||||
|
||||
// Ignore this test under QEMU, as it started failing after updating the Linux CI
|
||||
// runner image, for reasons unknown.
|
||||
//
|
||||
// See: https://github.com/nix-rust/nix/issues/2418
|
||||
#[test]
|
||||
#[cfg_attr(qemu, ignore)]
|
||||
fn test_set_vma_anon_name() {
|
||||
use nix::errno::Errno;
|
||||
use nix::sys::mman;
|
||||
use std::num::NonZeroUsize;
|
||||
|
||||
const ONE_K: libc::size_t = 1024;
|
||||
let sz = NonZeroUsize::new(ONE_K).unwrap();
|
||||
let ptr = unsafe {
|
||||
mman::mmap_anonymous(
|
||||
None,
|
||||
sz,
|
||||
mman::ProtFlags::PROT_READ,
|
||||
mman::MapFlags::MAP_SHARED,
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
let err = prctl::set_vma_anon_name(
|
||||
ptr,
|
||||
sz,
|
||||
Some(CStr::from_bytes_with_nul(b"[,$\0").unwrap()),
|
||||
)
|
||||
.unwrap_err();
|
||||
assert_eq!(err, Errno::EINVAL);
|
||||
// `CONFIG_ANON_VMA_NAME` kernel config might not be set
|
||||
prctl::set_vma_anon_name(
|
||||
ptr,
|
||||
sz,
|
||||
Some(CStr::from_bytes_with_nul(b"Nix\0").unwrap()),
|
||||
)
|
||||
.unwrap_or_default();
|
||||
prctl::set_vma_anon_name(ptr, sz, None).unwrap_or_default();
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,23 @@
|
||||
use nix::sys::pthread::*;
|
||||
|
||||
#[cfg(any(target_env = "musl", target_os = "redox"))]
|
||||
#[cfg(any(
|
||||
target_env = "musl",
|
||||
target_os = "redox",
|
||||
target_env = "ohos",
|
||||
target_os = "cygwin"
|
||||
))]
|
||||
#[test]
|
||||
fn test_pthread_self() {
|
||||
let tid = pthread_self();
|
||||
assert!(!tid.is_null());
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_env = "musl", target_os = "redox")))]
|
||||
#[cfg(not(any(
|
||||
target_env = "musl",
|
||||
target_os = "redox",
|
||||
target_env = "ohos",
|
||||
target_os = "cygwin"
|
||||
)))]
|
||||
#[test]
|
||||
fn test_pthread_self() {
|
||||
let tid = pthread_self();
|
||||
|
||||
+147
-10
@@ -1,16 +1,16 @@
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
any(target_arch = "x86_64", target_arch = "x86"),
|
||||
target_env = "gnu"
|
||||
target_env = "gnu",
|
||||
any(target_arch = "x86_64", target_arch = "x86")
|
||||
))]
|
||||
use memoffset::offset_of;
|
||||
use nix::errno::Errno;
|
||||
use nix::sys::ptrace;
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
use nix::sys::ptrace::Options;
|
||||
use nix::unistd::getpid;
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
use std::mem;
|
||||
|
||||
use crate::*;
|
||||
@@ -28,7 +28,7 @@ fn test_ptrace() {
|
||||
|
||||
// Just make sure ptrace_setoptions can be called at all, for now.
|
||||
#[test]
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
fn test_ptrace_setoptions() {
|
||||
require_capability!("test_ptrace_setoptions", CAP_SYS_PTRACE);
|
||||
let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD)
|
||||
@@ -38,7 +38,7 @@ fn test_ptrace_setoptions() {
|
||||
|
||||
// Just make sure ptrace_getevent can be called at all, for now.
|
||||
#[test]
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
fn test_ptrace_getevent() {
|
||||
require_capability!("test_ptrace_getevent", CAP_SYS_PTRACE);
|
||||
let err = ptrace::getevent(getpid()).unwrap_err();
|
||||
@@ -47,7 +47,7 @@ fn test_ptrace_getevent() {
|
||||
|
||||
// Just make sure ptrace_getsiginfo can be called at all, for now.
|
||||
#[test]
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
fn test_ptrace_getsiginfo() {
|
||||
require_capability!("test_ptrace_getsiginfo", CAP_SYS_PTRACE);
|
||||
if let Err(Errno::EOPNOTSUPP) = ptrace::getsiginfo(getpid()) {
|
||||
@@ -57,7 +57,7 @@ fn test_ptrace_getsiginfo() {
|
||||
|
||||
// Just make sure ptrace_setsiginfo can be called at all, for now.
|
||||
#[test]
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[cfg(linux_android)]
|
||||
fn test_ptrace_setsiginfo() {
|
||||
require_capability!("test_ptrace_setsiginfo", CAP_SYS_PTRACE);
|
||||
let siginfo = unsafe { mem::zeroed() };
|
||||
@@ -179,8 +179,18 @@ fn test_ptrace_interrupt() {
|
||||
// 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"
|
||||
any(
|
||||
all(
|
||||
target_env = "gnu",
|
||||
any(
|
||||
target_arch = "x86_64",
|
||||
target_arch = "x86",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "riscv64"
|
||||
)
|
||||
),
|
||||
all(target_env = "musl", target_arch = "aarch64")
|
||||
)
|
||||
))]
|
||||
#[test]
|
||||
fn test_ptrace_syscall() {
|
||||
@@ -226,12 +236,21 @@ fn test_ptrace_syscall() {
|
||||
let get_syscall_id =
|
||||
|| ptrace::getregs(child).unwrap().orig_eax as libc::c_long;
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
let get_syscall_id =
|
||||
|| ptrace::getregs(child).unwrap().regs[8] as libc::c_long;
|
||||
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
let get_syscall_id =
|
||||
|| ptrace::getregs(child).unwrap().a7 as libc::c_long;
|
||||
|
||||
// this duplicates `get_syscall_id` for the purpose of testing `ptrace::read_user`.
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let rax_offset = offset_of!(libc::user_regs_struct, orig_rax);
|
||||
#[cfg(target_arch = "x86")]
|
||||
let rax_offset = offset_of!(libc::user_regs_struct, orig_eax);
|
||||
|
||||
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
|
||||
let get_syscall_from_user_area = || {
|
||||
// Find the offset of `user.regs.rax` (or `user.regs.eax` for x86)
|
||||
let rax_offset = offset_of!(libc::user, regs) + rax_offset;
|
||||
@@ -246,6 +265,7 @@ fn test_ptrace_syscall() {
|
||||
Ok(WaitStatus::PtraceSyscall(child))
|
||||
);
|
||||
assert_eq!(get_syscall_id(), ::libc::SYS_kill);
|
||||
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
|
||||
assert_eq!(get_syscall_from_user_area(), ::libc::SYS_kill);
|
||||
|
||||
// kill exit
|
||||
@@ -255,6 +275,7 @@ fn test_ptrace_syscall() {
|
||||
Ok(WaitStatus::PtraceSyscall(child))
|
||||
);
|
||||
assert_eq!(get_syscall_id(), ::libc::SYS_kill);
|
||||
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
|
||||
assert_eq!(get_syscall_from_user_area(), ::libc::SYS_kill);
|
||||
|
||||
// receive signal
|
||||
@@ -273,3 +294,119 @@ fn test_ptrace_syscall() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
any(
|
||||
all(
|
||||
target_env = "gnu",
|
||||
any(
|
||||
target_arch = "x86_64",
|
||||
target_arch = "x86",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "riscv64"
|
||||
)
|
||||
),
|
||||
all(target_env = "musl", target_arch = "aarch64")
|
||||
)
|
||||
))]
|
||||
#[test]
|
||||
fn test_ptrace_regsets() {
|
||||
use nix::sys::ptrace::{self, getregset, regset, setregset};
|
||||
use nix::sys::signal::*;
|
||||
use nix::sys::wait::{waitpid, WaitStatus};
|
||||
use nix::unistd::fork;
|
||||
use nix::unistd::ForkResult::*;
|
||||
|
||||
require_capability!("test_ptrace_regsets", CAP_SYS_PTRACE);
|
||||
|
||||
let _m = crate::FORK_MTX.lock();
|
||||
|
||||
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))
|
||||
);
|
||||
let mut regstruct =
|
||||
getregset::<regset::NT_PRSTATUS>(child).unwrap();
|
||||
let mut fpregstruct =
|
||||
getregset::<regset::NT_PRFPREG>(child).unwrap();
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let (reg, fpreg) =
|
||||
(&mut regstruct.r15, &mut fpregstruct.st_space[5]);
|
||||
#[cfg(target_arch = "x86")]
|
||||
let (reg, fpreg) =
|
||||
(&mut regstruct.edx, &mut fpregstruct.st_space[5]);
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
let (reg, fpreg) =
|
||||
(&mut regstruct.regs[16], &mut fpregstruct.vregs[5]);
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
let (reg, fpreg) = (&mut regstruct.t1, &mut fpregstruct.__f[5]);
|
||||
|
||||
*reg = 0xdeadbeefu32 as _;
|
||||
*fpreg = 0xfeedfaceu32 as _;
|
||||
let _ = setregset::<regset::NT_PRSTATUS>(child, regstruct);
|
||||
regstruct = getregset::<regset::NT_PRSTATUS>(child).unwrap();
|
||||
let _ = setregset::<regset::NT_PRFPREG>(child, fpregstruct);
|
||||
fpregstruct = getregset::<regset::NT_PRFPREG>(child).unwrap();
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let (reg, fpreg) = (regstruct.r15, fpregstruct.st_space[5]);
|
||||
#[cfg(target_arch = "x86")]
|
||||
let (reg, fpreg) = (regstruct.edx, fpregstruct.st_space[5]);
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
let (reg, fpreg) = (regstruct.regs[16], fpregstruct.vregs[5]);
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
let (reg, fpreg) = (regstruct.t1, fpregstruct.__f[5]);
|
||||
assert_eq!(reg, 0xdeadbeefu32 as _);
|
||||
assert_eq!(fpreg, 0xfeedfaceu32 as _);
|
||||
|
||||
ptrace::cont(child, Some(Signal::SIGKILL)).unwrap();
|
||||
match waitpid(child, None) {
|
||||
Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _))
|
||||
if pid == child => {}
|
||||
_ => panic!("The process should have been killed"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu"))]
|
||||
#[test]
|
||||
fn test_ptrace_syscall_info() {
|
||||
use nix::sys::ptrace;
|
||||
use nix::sys::wait::{waitpid, WaitStatus};
|
||||
use nix::unistd::fork;
|
||||
use nix::unistd::ForkResult::*;
|
||||
|
||||
require_capability!("test_ptrace_syscall_info", CAP_SYS_PTRACE);
|
||||
|
||||
let _m = crate::FORK_MTX.lock();
|
||||
match unsafe { fork() }.expect("Error: Fork Failed") {
|
||||
Child => {
|
||||
ptrace::traceme().unwrap();
|
||||
std::thread::sleep(std::time::Duration::from_millis(1000));
|
||||
unsafe {
|
||||
::libc::_exit(0);
|
||||
}
|
||||
}
|
||||
Parent { child } => loop {
|
||||
if let Ok(WaitStatus::Exited(_, 0)) = waitpid(child, None) {
|
||||
break;
|
||||
}
|
||||
let si = ptrace::syscall_info(child).unwrap();
|
||||
assert!(si.op >= libc::PTRACE_SYSCALL_INFO_ENTRY);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user