mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-10-01 11:05:46 +00:00
vendor: Add vmm-sys-util duplicate
Since the top-level Cargo.toml specifies a vmm-sys-util revision but not the sub crates, Cargo.lock points at 2 different crates. cargo vendor copies both of them into the vendor directory but forces the build to use the one coming from the top level driven requirement. Although this is a waste of space, this is a cargo vendor limitation that we have to live with for now. Also, because the dependency onto linux-loader had to be updated, we had to specify a newly introduced feature called "elf". Signed-off-by: Samuel Ortiz <sameo@linux.intel.com> Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
parent
89fc75d5d3
commit
842515c2f1
14
Cargo.lock
generated
14
Cargo.lock
generated
@ -43,7 +43,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.0.4"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -86,7 +86,7 @@ name = "cloudabi"
|
|||||||
version = "0.0.3"
|
version = "0.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -105,7 +105,7 @@ name = "epoll"
|
|||||||
version = "4.0.1"
|
version = "4.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -136,7 +136,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-loader"
|
name = "linux-loader"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/bjzhjing/linux-loader#55c985a16d63dceccbd30952f0e93a73b25a8191"
|
source = "git+https://github.com/bjzhjing/linux-loader#9fa483ce4a7d6a1250be82fa551060ecdbdec4aa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"vm-memory 0.1.0 (git+https://github.com/rust-vmm/vm-memory)",
|
"vm-memory 0.1.0 (git+https://github.com/rust-vmm/vm-memory)",
|
||||||
]
|
]
|
||||||
@ -439,7 +439,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "vm-memory"
|
name = "vm-memory"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/rust-vmm/vm-memory#281b8bd6cd2927f7a65130194b203a1c2b0ad2e3"
|
source = "git+https://github.com/rust-vmm/vm-memory#682f10b36d6a48e656d45143fb64621bc8fe4b8e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@ -495,7 +495,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "vmm-sys-util"
|
name = "vmm-sys-util"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/rust-vmm/vmm-sys-util#60fe35bea0bdce8b36c6186a740878880f944bdc"
|
source = "git+https://github.com/rust-vmm/vmm-sys-util#cb33925bfd1eb314e5384c58c78874d2c98d6182"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@ -532,7 +532,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
|
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
|
||||||
"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf"
|
"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf"
|
||||||
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
|
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
|
||||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
|
||||||
"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23"
|
"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23"
|
||||||
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
|
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
|
||||||
"checksum clap 2.27.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1b8c532887f1a292d17de05ae858a8fe50a301e196f9ef0ddb7ccd0d1d00f180"
|
"checksum clap 2.27.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1b8c532887f1a292d17de05ae858a8fe50a301e196f9ef0ddb7ccd0d1d00f180"
|
||||||
|
@ -9,7 +9,7 @@ steps:
|
|||||||
os: linux
|
os: linux
|
||||||
plugins:
|
plugins:
|
||||||
- docker#v3.0.1:
|
- docker#v3.0.1:
|
||||||
image: "fandree/rust-vmm-dev"
|
image: "rustvmm/dev:v2"
|
||||||
always-pull: true
|
always-pull: true
|
||||||
|
|
||||||
- label: "build-gnu-x86-mmap"
|
- label: "build-gnu-x86-mmap"
|
||||||
@ -22,7 +22,7 @@ steps:
|
|||||||
os: linux
|
os: linux
|
||||||
plugins:
|
plugins:
|
||||||
- docker#v3.0.1:
|
- docker#v3.0.1:
|
||||||
image: "fandree/rust-vmm-dev"
|
image: "rustvmm/dev:v2"
|
||||||
always-pull: true
|
always-pull: true
|
||||||
|
|
||||||
- label: "build-gnu-arm-mmap"
|
- label: "build-gnu-arm-mmap"
|
||||||
@ -35,7 +35,7 @@ steps:
|
|||||||
os: linux
|
os: linux
|
||||||
plugins:
|
plugins:
|
||||||
- docker#v3.0.1:
|
- docker#v3.0.1:
|
||||||
image: "fandree/rust-vmm-dev"
|
image: "rustvmm/dev:v2"
|
||||||
always-pull: true
|
always-pull: true
|
||||||
|
|
||||||
- label: "build-musl-arm-mmap"
|
- label: "build-musl-arm-mmap"
|
||||||
@ -48,7 +48,7 @@ steps:
|
|||||||
os: linux
|
os: linux
|
||||||
plugins:
|
plugins:
|
||||||
- docker#v3.0.1:
|
- docker#v3.0.1:
|
||||||
image: "fandree/rust-vmm-dev"
|
image: "rustvmm/dev:v2"
|
||||||
always-pull: true
|
always-pull: true
|
||||||
|
|
||||||
- label: "style"
|
- label: "style"
|
||||||
@ -60,7 +60,7 @@ steps:
|
|||||||
os: linux
|
os: linux
|
||||||
plugins:
|
plugins:
|
||||||
- docker#v3.0.1:
|
- docker#v3.0.1:
|
||||||
image: "fandree/rust-vmm-dev"
|
image: "rustvmm/dev:v2"
|
||||||
always-pull: true
|
always-pull: true
|
||||||
|
|
||||||
- label: "unittests-gnu-x86"
|
- label: "unittests-gnu-x86"
|
||||||
@ -73,7 +73,7 @@ steps:
|
|||||||
os: linux
|
os: linux
|
||||||
plugins:
|
plugins:
|
||||||
- docker#v3.0.1:
|
- docker#v3.0.1:
|
||||||
image: "fandree/rust-vmm-dev"
|
image: "rustvmm/dev:v2"
|
||||||
always-pull: true
|
always-pull: true
|
||||||
|
|
||||||
- label: "unittests-musl-x86"
|
- label: "unittests-musl-x86"
|
||||||
@ -86,7 +86,7 @@ steps:
|
|||||||
os: linux
|
os: linux
|
||||||
plugins:
|
plugins:
|
||||||
- docker#v3.0.1:
|
- docker#v3.0.1:
|
||||||
image: "fandree/rust-vmm-dev"
|
image: "rustvmm/dev:v2"
|
||||||
always-pull: true
|
always-pull: true
|
||||||
|
|
||||||
- label: "unittests-gnu-arm"
|
- label: "unittests-gnu-arm"
|
||||||
@ -99,7 +99,7 @@ steps:
|
|||||||
os: linux
|
os: linux
|
||||||
plugins:
|
plugins:
|
||||||
- docker#v3.0.1:
|
- docker#v3.0.1:
|
||||||
image: "fandree/rust-vmm-dev"
|
image: "rustvmm/dev:v2"
|
||||||
always-pull: true
|
always-pull: true
|
||||||
|
|
||||||
- label: "unittests-musl-arm"
|
- label: "unittests-musl-arm"
|
||||||
@ -112,12 +112,12 @@ steps:
|
|||||||
os: linux
|
os: linux
|
||||||
plugins:
|
plugins:
|
||||||
- docker#v3.0.1:
|
- docker#v3.0.1:
|
||||||
image: "fandree/rust-vmm-dev"
|
image: "rustvmm/dev:v2"
|
||||||
always-pull: true
|
always-pull: true
|
||||||
|
|
||||||
- label: "clippy-x86"
|
- label: "clippy-x86"
|
||||||
commands:
|
commands:
|
||||||
- cargo clippy --all
|
- cargo clippy --all -- -D warnings
|
||||||
retry:
|
retry:
|
||||||
automatic: false
|
automatic: false
|
||||||
agents:
|
agents:
|
||||||
@ -125,7 +125,20 @@ steps:
|
|||||||
os: linux
|
os: linux
|
||||||
plugins:
|
plugins:
|
||||||
- docker#v3.0.1:
|
- docker#v3.0.1:
|
||||||
image: "fandree/rust-vmm-dev"
|
image: "rustvmm/dev:v2"
|
||||||
|
always-pull: true
|
||||||
|
|
||||||
|
- label: "clippy-arm"
|
||||||
|
commands:
|
||||||
|
- cargo clippy --all -- -D warnings
|
||||||
|
retry:
|
||||||
|
automatic: false
|
||||||
|
agents:
|
||||||
|
platform: arm.metal
|
||||||
|
os: linux
|
||||||
|
plugins:
|
||||||
|
- docker#v3.0.1:
|
||||||
|
image: "rustvmm/dev:v2"
|
||||||
always-pull: true
|
always-pull: true
|
||||||
|
|
||||||
- label: "check-warnings-x86"
|
- label: "check-warnings-x86"
|
||||||
@ -138,7 +151,7 @@ steps:
|
|||||||
os: linux
|
os: linux
|
||||||
plugins:
|
plugins:
|
||||||
- docker#v3.0.1:
|
- docker#v3.0.1:
|
||||||
image: "fandree/rust-vmm-dev"
|
image: "rustvmm/dev:v2"
|
||||||
always-pull: true
|
always-pull: true
|
||||||
|
|
||||||
- label: "check-warnings-arm"
|
- label: "check-warnings-arm"
|
||||||
@ -151,5 +164,5 @@ steps:
|
|||||||
os: linux
|
os: linux
|
||||||
plugins:
|
plugins:
|
||||||
- docker#v3.0.1:
|
- docker#v3.0.1:
|
||||||
image: "fandree/rust-vmm-dev"
|
image: "rustvmm/dev:v2"
|
||||||
always-pull: true
|
always-pull: true
|
||||||
|
@ -1 +1 @@
|
|||||||
{"files":{".buildkite/pipeline.linux.yml":"a792da4b923a91eb9a590da2d057f89b37b86ebcf483c344813a1abd5957854d",".buildkite/pipeline.windows.yml":"15e21819ef7321c79181ae7f04aafc0c3ceff709a800edd8994f15a9454d6405",".cargo/config":"c2f1c2fd93436e068cfb14eef3dff8a79d25d1f03c11baf6acbcfbdc9fd3a465","Cargo.toml":"459c6688ce88cac6767971e8053b03a14e05aec157a927134c34d5497c84cf68","DESIGN.md":"aa60ac0a1d59179c253c7be0e496f956344cd0bf41f01f86c9a28575ea433785","LICENSE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","README.md":"2f4aa7c6dbb257a9345d17cec07b0731cae37dc216d25b41272061861bf984b8","THIRD-PARTY":"a6d3ebd1c2f37d4fd83d0676621f695fc0cc2d8c6e646cdbb831b46e0650c208","TODO.md":"c844f03be6631843e90d13b3410df031b07ee16db4a3c7cbda7e89557e9be46b","src/address.rs":"dbc3fa642269bb6f9fb5e176dddc9fcedbe024949f32c43577f52ef04fe0cf09","src/bytes.rs":"2d0c58f53e40f51b5177a234a5062f700ea153c779661c8c34f5d9340f24dd05","src/endian.rs":"948548db28334bceeefe72b09560a700d62993372bb89f46e39990038690f516","src/guest_memory.rs":"2be506fe58244f51279c473a7d0d8e1fc41ef638e9c16cc9e6f071bcbecb3b9b","src/lib.rs":"f65c3f36632da8df7b165578bfd8db010af11c1736fd9855614435e76dd3c390","src/mmap.rs":"9f449c7dac3830128bc1875ca0cc7e7407534eeb7cc1e1db0b0d118aba8de07b","src/mmap_unix.rs":"9a1d71bf1bb7952c25e3796f992953390b6db5a32ef40f2dda1275f866dd9ff0","src/mmap_windows.rs":"bd0091dd90eddede03739ab89648a38f513310437dafdf1f449603bb15a7a2ed","src/volatile_memory.rs":"06bdb496a75f3a190b7092daffce01158acdf73654badd72e697b674eedc4fac"},"package":null}
|
{"files":{".buildkite/pipeline.linux.yml":"15e790653d9e63fb98a1aff02697ab123b44fc03c06127b222e5f67e7732722e",".buildkite/pipeline.windows.yml":"15e21819ef7321c79181ae7f04aafc0c3ceff709a800edd8994f15a9454d6405",".cargo/config":"c2f1c2fd93436e068cfb14eef3dff8a79d25d1f03c11baf6acbcfbdc9fd3a465","Cargo.toml":"459c6688ce88cac6767971e8053b03a14e05aec157a927134c34d5497c84cf68","DESIGN.md":"aa60ac0a1d59179c253c7be0e496f956344cd0bf41f01f86c9a28575ea433785","LICENSE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","README.md":"2f4aa7c6dbb257a9345d17cec07b0731cae37dc216d25b41272061861bf984b8","THIRD-PARTY":"a6d3ebd1c2f37d4fd83d0676621f695fc0cc2d8c6e646cdbb831b46e0650c208","TODO.md":"c844f03be6631843e90d13b3410df031b07ee16db4a3c7cbda7e89557e9be46b","src/address.rs":"dbc3fa642269bb6f9fb5e176dddc9fcedbe024949f32c43577f52ef04fe0cf09","src/bytes.rs":"2d0c58f53e40f51b5177a234a5062f700ea153c779661c8c34f5d9340f24dd05","src/endian.rs":"948548db28334bceeefe72b09560a700d62993372bb89f46e39990038690f516","src/guest_memory.rs":"2be506fe58244f51279c473a7d0d8e1fc41ef638e9c16cc9e6f071bcbecb3b9b","src/lib.rs":"f65c3f36632da8df7b165578bfd8db010af11c1736fd9855614435e76dd3c390","src/mmap.rs":"9f449c7dac3830128bc1875ca0cc7e7407534eeb7cc1e1db0b0d118aba8de07b","src/mmap_unix.rs":"9a1d71bf1bb7952c25e3796f992953390b6db5a32ef40f2dda1275f866dd9ff0","src/mmap_windows.rs":"bd0091dd90eddede03739ab89648a38f513310437dafdf1f449603bb15a7a2ed","src/volatile_memory.rs":"06bdb496a75f3a190b7092daffce01158acdf73654badd72e697b674eedc4fac"},"package":null}
|
153
vendor/git-643dc7ede01ca600/vmm-sys-util/.buildkite/pipeline.yml
vendored
Normal file
153
vendor/git-643dc7ede01ca600/vmm-sys-util/.buildkite/pipeline.yml
vendored
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
steps:
|
||||||
|
- label: "build-gnu-x86"
|
||||||
|
commands:
|
||||||
|
- cargo build --release
|
||||||
|
retry:
|
||||||
|
automatic: false
|
||||||
|
agents:
|
||||||
|
platform: x86_64.metal
|
||||||
|
plugins:
|
||||||
|
- docker#v3.0.1:
|
||||||
|
image: "rustvmm/dev:v2"
|
||||||
|
always-pull: true
|
||||||
|
|
||||||
|
- label: "build-gnu-arm"
|
||||||
|
commands:
|
||||||
|
- cargo build --release
|
||||||
|
retry:
|
||||||
|
automatic: false
|
||||||
|
agents:
|
||||||
|
platform: arm.metal
|
||||||
|
plugins:
|
||||||
|
- docker#v3.0.1:
|
||||||
|
image: "rustvmm/dev:v2"
|
||||||
|
always-pull: true
|
||||||
|
|
||||||
|
- label: "build-musl-arm"
|
||||||
|
commands:
|
||||||
|
- cargo build --release --target aarch64-unknown-linux-musl
|
||||||
|
retry:
|
||||||
|
automatic: false
|
||||||
|
agents:
|
||||||
|
platform: arm.metal
|
||||||
|
os: linux
|
||||||
|
plugins:
|
||||||
|
- docker#v3.0.1:
|
||||||
|
image: "rustvmm/dev:v2"
|
||||||
|
always-pull: true
|
||||||
|
|
||||||
|
- label: "unittests-musl-x86"
|
||||||
|
commands:
|
||||||
|
- cargo test --all-features --target x86_64-unknown-linux-musl
|
||||||
|
retry:
|
||||||
|
automatic: false
|
||||||
|
agents:
|
||||||
|
platform: x86_64.metal
|
||||||
|
os: linux
|
||||||
|
plugins:
|
||||||
|
- docker#v3.0.1:
|
||||||
|
image: "rustvmm/dev:v2"
|
||||||
|
always-pull: true
|
||||||
|
|
||||||
|
- label: "unittests-musl-arm"
|
||||||
|
commands:
|
||||||
|
- cargo test --all-features --target aarch64-unknown-linux-musl
|
||||||
|
retry:
|
||||||
|
automatic: false
|
||||||
|
agents:
|
||||||
|
platform: arm.metal
|
||||||
|
os: linux
|
||||||
|
plugins:
|
||||||
|
- docker#v3.0.1:
|
||||||
|
image: "rustvmm/dev:v2"
|
||||||
|
always-pull: true
|
||||||
|
|
||||||
|
|
||||||
|
- label: "style"
|
||||||
|
command: cargo fmt --all -- --check
|
||||||
|
retry:
|
||||||
|
automatic: false
|
||||||
|
agents:
|
||||||
|
platform: x86_64.metal
|
||||||
|
plugins:
|
||||||
|
- docker#v3.0.1:
|
||||||
|
image: "rustvmm/dev:v2"
|
||||||
|
always-pull: true
|
||||||
|
|
||||||
|
- label: "unittests-gnu-x86"
|
||||||
|
commands:
|
||||||
|
- cargo test
|
||||||
|
retry:
|
||||||
|
automatic: false
|
||||||
|
agents:
|
||||||
|
platform: x86_64.metal
|
||||||
|
plugins:
|
||||||
|
- docker#v3.0.1:
|
||||||
|
privileged: true
|
||||||
|
image: "rustvmm/dev:v2"
|
||||||
|
always-pull: true
|
||||||
|
tmpfs: [ "/tmp:exec" ]
|
||||||
|
|
||||||
|
- label: "unittests-gnu-arm"
|
||||||
|
commands:
|
||||||
|
- cargo test
|
||||||
|
retry:
|
||||||
|
automatic: false
|
||||||
|
agents:
|
||||||
|
platform: arm.metal
|
||||||
|
plugins:
|
||||||
|
- docker#v3.0.1:
|
||||||
|
privileged: true
|
||||||
|
image: "rustvmm/dev:v2"
|
||||||
|
always-pull: true
|
||||||
|
tmpfs: [ "/tmp:exec" ]
|
||||||
|
|
||||||
|
- label: "clippy-x86"
|
||||||
|
commands:
|
||||||
|
- cargo clippy --all -- -D warnings
|
||||||
|
retry:
|
||||||
|
automatic: false
|
||||||
|
agents:
|
||||||
|
platform: x86_64.metal
|
||||||
|
plugins:
|
||||||
|
- docker#v3.0.1:
|
||||||
|
image: "rustvmm/dev:v2"
|
||||||
|
always-pull: true
|
||||||
|
|
||||||
|
- label: "clippy-arm"
|
||||||
|
commands:
|
||||||
|
- cargo clippy --all -- -D warnings
|
||||||
|
retry:
|
||||||
|
automatic: false
|
||||||
|
agents:
|
||||||
|
platform: arm.metal
|
||||||
|
plugins:
|
||||||
|
- docker#v3.0.1:
|
||||||
|
image: "rustvmm/dev:v2"
|
||||||
|
always-pull: true
|
||||||
|
|
||||||
|
- label: "check-warnings-x86"
|
||||||
|
commands:
|
||||||
|
- RUSTFLAGS="-D warnings" cargo check --all-targets
|
||||||
|
retry:
|
||||||
|
automatic: false
|
||||||
|
agents:
|
||||||
|
platform: x86_64.metal
|
||||||
|
os: linux
|
||||||
|
plugins:
|
||||||
|
- docker#v3.0.1:
|
||||||
|
image: "rustvmm/dev:v2"
|
||||||
|
always-pull: true
|
||||||
|
|
||||||
|
- label: "check-warnings-arm"
|
||||||
|
commands:
|
||||||
|
- RUSTFLAGS="-D warnings" cargo check --all-targets
|
||||||
|
retry:
|
||||||
|
automatic: false
|
||||||
|
agents:
|
||||||
|
platform: arm.metal
|
||||||
|
os: linux
|
||||||
|
plugins:
|
||||||
|
- docker#v3.0.1:
|
||||||
|
image: "rustvmm/dev:v2"
|
||||||
|
always-pull: true
|
1
vendor/git-643dc7ede01ca600/vmm-sys-util/.cargo-checksum.json
vendored
Normal file
1
vendor/git-643dc7ede01ca600/vmm-sys-util/.cargo-checksum.json
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"files":{".buildkite/pipeline.yml":"e603f3ef6b6357911abe831a0a03f0444cb1ad057385fdd6923d01d6f9f460ba",".cargo/config":"62f04eec5a565cf7017d26222f6f424004ea6f850c22c9c7352ede255a2c59c4","Cargo.toml":"d19b52349ada25dbbae4e2bea4850cf1b09ea546d5efee03ddfbbf9f184c0c72","LICENSE-APACHE":"c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4","LICENSE-BSD-3-Clause":"a6d3ebd1c2f37d4fd83d0676621f695fc0cc2d8c6e646cdbb831b46e0650c208","README.md":"94512ed84e8e89faba431d9107e85d229363c187705ab9244f0ab5269b5961b5","src/errno.rs":"b93845c200fc596b0ef2414671d965cf5c4fdbf6bba6e5e5f0d032a32c73f8ac","src/eventfd.rs":"7bd871242f49c14d8783714e6814456f51a9c280dcadf1625e1bd2313d2b5f7f","src/file_traits.rs":"398c529e7ebce143ecb9f9bd2f5f47ea3e953ac34cc211ad71cdcf1898cc7d38","src/ioctl.rs":"5c4abf75e7b6786e7da3191ac1e4460e1ec7d073a53331a6d9597bb9ccc3f88a","src/lib.rs":"ee0818e0ca6fdc340c52d514eeb2e3aeb4f7ba8e4e522bb946cdbce4779926f1","src/poll.rs":"1498c14ba022ede57c4faf17bee49cf5ac9d1c8d3883db441697ee224dac7818","src/seek_hole.rs":"de43f21bc2c5d9eb7f06e21e3c20f93476bf6016e4d041df71a02b9e54b3c3ca","src/signal.rs":"c9bb7282ec31f10c9a9e84ec4348eaa028e47d191237c465c9b45eaea994b5a8","src/syslog.rs":"fbf4bde16b1059b5b39c5318e8bb918dc431e8e0ccbc82c0d765b9ce4a8d5f96","src/tempdir.rs":"4993460e81f7df6398e0f2b07cc3d81e728aa7e0559c7f3d83b6df1876bc3776","src/terminal.rs":"85efb1df641730fa1981bac6fd65bd75f7d532bb8680a56e94d6d006eeb363e9","src/timerfd.rs":"fd3c52e3918d881c16cb1498f8f66253ee758275a6a66ed8eb11c78e69f69e55","src/write_zeroes.rs":"c2951bbdb3ab07727eda29e9a91a51e427fdf6fed0b611ea6a3732edbd9a1246"},"package":null}
|
2
vendor/git-643dc7ede01ca600/vmm-sys-util/.cargo/config
vendored
Normal file
2
vendor/git-643dc7ede01ca600/vmm-sys-util/.cargo/config
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[target.aarch64-unknown-linux-musl]
|
||||||
|
rustflags = [ "-C", "target-feature=+crt-static", "-C", "link-arg=-lgcc"]
|
9
vendor/git-643dc7ede01ca600/vmm-sys-util/Cargo.toml
vendored
Normal file
9
vendor/git-643dc7ede01ca600/vmm-sys-util/Cargo.toml
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "vmm-sys-util"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Jing Liu <jing2.liu@linux.intel.com>"]
|
||||||
|
license = "Apache-2.0"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libc = ">=0.2.39"
|
||||||
|
|
201
vendor/git-643dc7ede01ca600/vmm-sys-util/LICENSE-APACHE
vendored
Normal file
201
vendor/git-643dc7ede01ca600/vmm-sys-util/LICENSE-APACHE
vendored
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
27
vendor/git-643dc7ede01ca600/vmm-sys-util/LICENSE-BSD-3-Clause
vendored
Normal file
27
vendor/git-643dc7ede01ca600/vmm-sys-util/LICENSE-BSD-3-Clause
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
2
vendor/git-643dc7ede01ca600/vmm-sys-util/README.md
vendored
Normal file
2
vendor/git-643dc7ede01ca600/vmm-sys-util/README.md
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# vmm-sys-util
|
||||||
|
This crate is a collection of modules that provides helpers and utilities.
|
80
vendor/git-643dc7ede01ca600/vmm-sys-util/src/errno.rs
vendored
Normal file
80
vendor/git-643dc7ede01ca600/vmm-sys-util/src/errno.rs
vendored
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
// Copyright 2019 Intel Corporation. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
|
||||||
|
use std::fmt::{Display, Formatter};
|
||||||
|
use std::io;
|
||||||
|
use std::result;
|
||||||
|
|
||||||
|
use libc::__errno_location;
|
||||||
|
|
||||||
|
/// An error number, retrieved from [`errno`](http://man7.org/linux/man-pages/man3/errno.3.html),
|
||||||
|
/// set by a libc function that returned an error.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub struct Error(i32);
|
||||||
|
pub type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
|
impl Error {
|
||||||
|
/// Constructs a new error with the given `errno`.
|
||||||
|
pub fn new(e: i32) -> Error {
|
||||||
|
Error(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs an error from the current `errno`.
|
||||||
|
///
|
||||||
|
/// The result of this only has any meaning just after a libc call that returned a value
|
||||||
|
/// indicating `errno` was set.
|
||||||
|
pub fn last() -> Error {
|
||||||
|
Error(unsafe { *__errno_location() })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the `errno` for this error.
|
||||||
|
pub fn errno(self) -> i32 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Error {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
|
||||||
|
io::Error::from_raw_os_error(self.0).fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<io::Error> for Error {
|
||||||
|
fn from(e: io::Error) -> Self {
|
||||||
|
Error::new(e.raw_os_error().unwrap_or_default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the last `errno` as a [`Result`] that is always an error.
|
||||||
|
///
|
||||||
|
/// [`Result`]: type.Result.html
|
||||||
|
pub fn errno_result<T>() -> Result<T> {
|
||||||
|
Err(Error::last())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use libc;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{self, Write};
|
||||||
|
use std::os::unix::io::FromRawFd;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_invalid_fd() {
|
||||||
|
let mut file = unsafe { File::from_raw_fd(-1) };
|
||||||
|
assert!(file.write(b"test").is_err());
|
||||||
|
let last_err = errno_result::<i32>().unwrap_err();
|
||||||
|
assert_eq!(last_err, Error::new(libc::EBADF));
|
||||||
|
assert_eq!(last_err.errno(), libc::EBADF);
|
||||||
|
assert_eq!(last_err, Error::from(io::Error::last_os_error()));
|
||||||
|
assert_eq!(last_err, Error::last());
|
||||||
|
}
|
||||||
|
}
|
150
vendor/git-643dc7ede01ca600/vmm-sys-util/src/eventfd.rs
vendored
Normal file
150
vendor/git-643dc7ede01ca600/vmm-sys-util/src/eventfd.rs
vendored
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
// Copyright 2019 Intel Corporation. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
|
||||||
|
use std::fs::File;
|
||||||
|
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||||
|
use std::{io, mem, result};
|
||||||
|
|
||||||
|
use libc::{c_void, dup, eventfd, read, write};
|
||||||
|
|
||||||
|
/// A safe wrapper around a Linux eventfd (man 2 eventfd).
|
||||||
|
pub struct EventFd {
|
||||||
|
eventfd: File,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventFd {
|
||||||
|
/// Creates a new blocking EventFd with an initial value.
|
||||||
|
///
|
||||||
|
/// `flag`: The initial value. Refer to Linux eventfd(2).
|
||||||
|
pub fn new(flag: i32) -> result::Result<EventFd, io::Error> {
|
||||||
|
// This is safe because eventfd merely allocated an eventfd for
|
||||||
|
// our process and we handle the error case.
|
||||||
|
let ret = unsafe { eventfd(0, flag) };
|
||||||
|
if ret < 0 {
|
||||||
|
Err(io::Error::last_os_error())
|
||||||
|
} else {
|
||||||
|
// This is safe because we checked ret for success and know
|
||||||
|
// the kernel gave us an fd that we own.
|
||||||
|
Ok(EventFd {
|
||||||
|
eventfd: unsafe { File::from_raw_fd(ret) },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds `v` to the eventfd's count, does not block if the result will overflow the count
|
||||||
|
pub fn write(&self, v: u64) -> result::Result<(), io::Error> {
|
||||||
|
// This is safe because we made this fd and the pointer we pass
|
||||||
|
// can not overflow because we give the syscall's size parameter properly.
|
||||||
|
let ret = unsafe {
|
||||||
|
write(
|
||||||
|
self.as_raw_fd(),
|
||||||
|
&v as *const u64 as *const c_void,
|
||||||
|
mem::size_of::<u64>(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if ret <= 0 {
|
||||||
|
Err(io::Error::last_os_error())
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tries to read from the eventfd, does not block if the counter is zero
|
||||||
|
pub fn read(&self) -> result::Result<u64, io::Error> {
|
||||||
|
let mut buf: u64 = 0;
|
||||||
|
let ret = unsafe {
|
||||||
|
// This is safe because we made this fd and the pointer we
|
||||||
|
// pass can not overflow because we give the syscall's size parameter properly.
|
||||||
|
read(
|
||||||
|
self.as_raw_fd(),
|
||||||
|
&mut buf as *mut u64 as *mut c_void,
|
||||||
|
mem::size_of::<u64>(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if ret < 0 {
|
||||||
|
Err(io::Error::last_os_error())
|
||||||
|
} else {
|
||||||
|
Ok(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clones this EventFd, internally creating a new file descriptor. The new EventFd will share
|
||||||
|
/// the same underlying count within the kernel.
|
||||||
|
pub fn try_clone(&self) -> result::Result<EventFd, io::Error> {
|
||||||
|
// This is safe because we made this fd and properly check that it returns without error.
|
||||||
|
let ret = unsafe { dup(self.as_raw_fd()) };
|
||||||
|
if ret < 0 {
|
||||||
|
Err(io::Error::last_os_error())
|
||||||
|
} else {
|
||||||
|
// This is safe because we checked ret for success and know the kernel gave us an fd that we
|
||||||
|
// own.
|
||||||
|
Ok(EventFd {
|
||||||
|
eventfd: unsafe { File::from_raw_fd(ret) },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRawFd for EventFd {
|
||||||
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
|
self.eventfd.as_raw_fd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromRawFd for EventFd {
|
||||||
|
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||||
|
EventFd {
|
||||||
|
eventfd: File::from_raw_fd(fd),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use libc::EFD_NONBLOCK;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_new() {
|
||||||
|
EventFd::new(EFD_NONBLOCK).unwrap();
|
||||||
|
EventFd::new(0).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_read_write() {
|
||||||
|
let evt = EventFd::new(EFD_NONBLOCK).unwrap();
|
||||||
|
evt.write(55).unwrap();
|
||||||
|
assert_eq!(evt.read().unwrap(), 55);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_write_overflow() {
|
||||||
|
let evt = EventFd::new(EFD_NONBLOCK).unwrap();
|
||||||
|
evt.write(std::u64::MAX - 1).unwrap();
|
||||||
|
let r = evt.write(1);
|
||||||
|
match r {
|
||||||
|
Err(ref inner) if inner.kind() == io::ErrorKind::WouldBlock => (),
|
||||||
|
_ => panic!("Unexpected"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_read_nothing() {
|
||||||
|
let evt = EventFd::new(EFD_NONBLOCK).unwrap();
|
||||||
|
let r = evt.read();
|
||||||
|
match r {
|
||||||
|
Err(ref inner) if inner.kind() == io::ErrorKind::WouldBlock => (),
|
||||||
|
_ => panic!("Unexpected"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_clone() {
|
||||||
|
let evt = EventFd::new(EFD_NONBLOCK).unwrap();
|
||||||
|
let evt_clone = evt.try_clone().unwrap();
|
||||||
|
evt.write(923).unwrap();
|
||||||
|
assert_eq!(evt_clone.read().unwrap(), 923);
|
||||||
|
}
|
||||||
|
}
|
39
vendor/git-643dc7ede01ca600/vmm-sys-util/src/file_traits.rs
vendored
Normal file
39
vendor/git-643dc7ede01ca600/vmm-sys-util/src/file_traits.rs
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Result;
|
||||||
|
|
||||||
|
/// A trait for flushing the contents of a file to disk.
|
||||||
|
/// This is equivalent to File's `sync_all` method, but
|
||||||
|
/// wrapped in a trait so that it can be implemented for
|
||||||
|
/// other types.
|
||||||
|
pub trait FileSync {
|
||||||
|
// Flush buffers related to this file to disk.
|
||||||
|
fn fsync(&mut self) -> Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileSync for File {
|
||||||
|
fn fsync(&mut self) -> Result<()> {
|
||||||
|
self.sync_all()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A trait for setting the size of a file.
|
||||||
|
/// This is equivalent to File's `set_len` method, but
|
||||||
|
/// wrapped in a trait so that it can be implemented for
|
||||||
|
/// other types.
|
||||||
|
pub trait FileSetLen {
|
||||||
|
// Set the size of this file.
|
||||||
|
// This is the moral equivalent of `ftruncate()`.
|
||||||
|
fn set_len(&self, _len: u64) -> Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileSetLen for File {
|
||||||
|
fn set_len(&self, len: u64) -> Result<()> {
|
||||||
|
File::set_len(self, len)
|
||||||
|
}
|
||||||
|
}
|
225
vendor/git-643dc7ede01ca600/vmm-sys-util/src/ioctl.rs
vendored
Normal file
225
vendor/git-643dc7ede01ca600/vmm-sys-util/src/ioctl.rs
vendored
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
// Copyright 2019 Intel Corporation. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
|
||||||
|
//! Macros and wrapper functions for dealing with ioctls.
|
||||||
|
use libc;
|
||||||
|
use std::os::raw::{c_int, c_uint, c_ulong, c_void};
|
||||||
|
use std::os::unix::io::AsRawFd;
|
||||||
|
|
||||||
|
/// Raw macro to declare the expression that calculates an ioctl number
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! ioctl_expr {
|
||||||
|
($dir:expr, $ty:expr, $nr:expr, $size:expr) => {
|
||||||
|
(($dir << $crate::ioctl::_IOC_DIRSHIFT)
|
||||||
|
| ($ty << $crate::ioctl::_IOC_TYPESHIFT)
|
||||||
|
| ($nr << $crate::ioctl::_IOC_NRSHIFT)
|
||||||
|
| ($size << $crate::ioctl::_IOC_SIZESHIFT)) as ::std::os::raw::c_ulong
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Raw macro to declare a function that returns an ioctl number.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! ioctl_ioc_nr {
|
||||||
|
($name:ident, $dir:expr, $ty:expr, $nr:expr, $size:expr) => {
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[allow(clippy::cast_lossless)]
|
||||||
|
pub fn $name() -> ::std::os::raw::c_ulong {
|
||||||
|
ioctl_expr!($dir, $ty, $nr, $size)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($name:ident, $dir:expr, $ty:expr, $nr:expr, $size:expr, $($v:ident),+) => {
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[allow(clippy::cast_lossless)]
|
||||||
|
pub fn $name($($v: ::std::os::raw::c_uint),+) -> ::std::os::raw::c_ulong {
|
||||||
|
ioctl_expr!($dir, $ty, $nr, $size)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Declare an ioctl that transfers no data.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! ioctl_io_nr {
|
||||||
|
($name:ident, $ty:expr, $nr:expr) => {
|
||||||
|
ioctl_ioc_nr!($name, $crate::ioctl::_IOC_NONE, $ty, $nr, 0);
|
||||||
|
};
|
||||||
|
($name:ident, $ty:expr, $nr:expr, $($v:ident),+) => {
|
||||||
|
ioctl_ioc_nr!($name, $crate::ioctl::_IOC_NONE, $ty, $nr, 0, $($v),+);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Declare an ioctl that reads data.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! ioctl_ior_nr {
|
||||||
|
($name:ident, $ty:expr, $nr:expr, $size:ty) => {
|
||||||
|
ioctl_ioc_nr!(
|
||||||
|
$name,
|
||||||
|
$crate::ioctl::_IOC_READ,
|
||||||
|
$ty,
|
||||||
|
$nr,
|
||||||
|
::std::mem::size_of::<$size>() as u32
|
||||||
|
);
|
||||||
|
};
|
||||||
|
($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
|
||||||
|
ioctl_ioc_nr!(
|
||||||
|
$name,
|
||||||
|
$crate::ioctl::_IOC_READ,
|
||||||
|
$ty,
|
||||||
|
$nr,
|
||||||
|
::std::mem::size_of::<$size>() as u32,
|
||||||
|
$($v),+
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Declare an ioctl that writes data.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! ioctl_iow_nr {
|
||||||
|
($name:ident, $ty:expr, $nr:expr, $size:ty) => {
|
||||||
|
ioctl_ioc_nr!(
|
||||||
|
$name,
|
||||||
|
$crate::ioctl::_IOC_WRITE,
|
||||||
|
$ty,
|
||||||
|
$nr,
|
||||||
|
::std::mem::size_of::<$size>() as u32
|
||||||
|
);
|
||||||
|
};
|
||||||
|
($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
|
||||||
|
ioctl_ioc_nr!(
|
||||||
|
$name,
|
||||||
|
$crate::ioctl::_IOC_WRITE,
|
||||||
|
$ty,
|
||||||
|
$nr,
|
||||||
|
::std::mem::size_of::<$size>() as u32,
|
||||||
|
$($v),+
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Declare an ioctl that reads and writes data.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! ioctl_iowr_nr {
|
||||||
|
($name:ident, $ty:expr, $nr:expr, $size:ty) => {
|
||||||
|
ioctl_ioc_nr!(
|
||||||
|
$name,
|
||||||
|
$crate::ioctl::_IOC_READ | $crate::ioctl::_IOC_WRITE,
|
||||||
|
$ty,
|
||||||
|
$nr,
|
||||||
|
::std::mem::size_of::<$size>() as u32
|
||||||
|
);
|
||||||
|
};
|
||||||
|
($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
|
||||||
|
ioctl_ioc_nr!(
|
||||||
|
$name,
|
||||||
|
$crate::ioctl::_IOC_READ | $crate::ioctl::_IOC_WRITE,
|
||||||
|
$ty,
|
||||||
|
$nr,
|
||||||
|
::std::mem::size_of::<$size>() as u32,
|
||||||
|
$($v),+
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const _IOC_NRBITS: c_uint = 8;
|
||||||
|
pub const _IOC_TYPEBITS: c_uint = 8;
|
||||||
|
pub const _IOC_SIZEBITS: c_uint = 14;
|
||||||
|
pub const _IOC_DIRBITS: c_uint = 2;
|
||||||
|
pub const _IOC_NRMASK: c_uint = 255;
|
||||||
|
pub const _IOC_TYPEMASK: c_uint = 255;
|
||||||
|
pub const _IOC_SIZEMASK: c_uint = 16383;
|
||||||
|
pub const _IOC_DIRMASK: c_uint = 3;
|
||||||
|
pub const _IOC_NRSHIFT: c_uint = 0;
|
||||||
|
pub const _IOC_TYPESHIFT: c_uint = 8;
|
||||||
|
pub const _IOC_SIZESHIFT: c_uint = 16;
|
||||||
|
pub const _IOC_DIRSHIFT: c_uint = 30;
|
||||||
|
pub const _IOC_NONE: c_uint = 0;
|
||||||
|
pub const _IOC_WRITE: c_uint = 1;
|
||||||
|
pub const _IOC_READ: c_uint = 2;
|
||||||
|
pub const IOC_IN: c_uint = 1_073_741_824;
|
||||||
|
pub const IOC_OUT: c_uint = 2_147_483_648;
|
||||||
|
pub const IOC_INOUT: c_uint = 3_221_225_472;
|
||||||
|
pub const IOCSIZE_MASK: c_uint = 1_073_676_288;
|
||||||
|
pub const IOCSIZE_SHIFT: c_uint = 16;
|
||||||
|
|
||||||
|
// The type of the `req` parameter is different for the `musl` library. This will enable
|
||||||
|
// successful build for other non-musl libraries.
|
||||||
|
#[cfg(target_env = "musl")]
|
||||||
|
type IoctlRequest = c_int;
|
||||||
|
#[cfg(not(target_env = "musl"))]
|
||||||
|
type IoctlRequest = c_ulong;
|
||||||
|
|
||||||
|
/// Run an ioctl with no arguments.
|
||||||
|
pub unsafe fn ioctl<F: AsRawFd>(fd: &F, req: c_ulong) -> c_int {
|
||||||
|
libc::ioctl(fd.as_raw_fd(), req as IoctlRequest, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run an ioctl with a single value argument.
|
||||||
|
pub unsafe fn ioctl_with_val<F: AsRawFd>(fd: &F, req: c_ulong, arg: c_ulong) -> c_int {
|
||||||
|
libc::ioctl(fd.as_raw_fd(), req as IoctlRequest, arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run an ioctl with an immutable reference.
|
||||||
|
pub unsafe fn ioctl_with_ref<F: AsRawFd, T>(fd: &F, req: c_ulong, arg: &T) -> c_int {
|
||||||
|
libc::ioctl(
|
||||||
|
fd.as_raw_fd(),
|
||||||
|
req as IoctlRequest,
|
||||||
|
arg as *const T as *const c_void,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run an ioctl with a mutable reference.
|
||||||
|
pub unsafe fn ioctl_with_mut_ref<F: AsRawFd, T>(fd: &F, req: c_ulong, arg: &mut T) -> c_int {
|
||||||
|
libc::ioctl(
|
||||||
|
fd.as_raw_fd(),
|
||||||
|
req as IoctlRequest,
|
||||||
|
arg as *mut T as *mut c_void,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run an ioctl with a raw pointer.
|
||||||
|
pub unsafe fn ioctl_with_ptr<F: AsRawFd, T>(fd: &F, req: c_ulong, arg: *const T) -> c_int {
|
||||||
|
libc::ioctl(fd.as_raw_fd(), req as IoctlRequest, arg as *const c_void)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run an ioctl with a mutable raw pointer.
|
||||||
|
pub unsafe fn ioctl_with_mut_ptr<F: AsRawFd, T>(fd: &F, req: c_ulong, arg: *mut T) -> c_int {
|
||||||
|
libc::ioctl(fd.as_raw_fd(), req as IoctlRequest, arg as *mut c_void)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
const TUNTAP: ::std::os::raw::c_uint = 0x54;
|
||||||
|
const VHOST: ::std::os::raw::c_uint = 0xAF;
|
||||||
|
const EVDEV: ::std::os::raw::c_uint = 0x45;
|
||||||
|
|
||||||
|
const KVMIO: ::std::os::raw::c_uint = 0xAE;
|
||||||
|
|
||||||
|
ioctl_io_nr!(KVM_CREATE_VM, KVMIO, 0x01);
|
||||||
|
ioctl_ior_nr!(TUNGETFEATURES, TUNTAP, 0xcf, ::std::os::raw::c_uint);
|
||||||
|
ioctl_iow_nr!(TUNSETQUEUE, TUNTAP, 0xd9, ::std::os::raw::c_int);
|
||||||
|
ioctl_io_nr!(VHOST_SET_OWNER, VHOST, 0x01);
|
||||||
|
ioctl_iowr_nr!(VHOST_GET_VRING_BASE, VHOST, 0x12, ::std::os::raw::c_int);
|
||||||
|
ioctl_iowr_nr!(KVM_GET_MSR_INDEX_LIST, KVMIO, 0x2, ::std::os::raw::c_int);
|
||||||
|
|
||||||
|
ioctl_ior_nr!(EVIOCGBIT, EVDEV, 0x20 + evt, [u8; 128], evt);
|
||||||
|
ioctl_io_nr!(FAKE_IOCTL_2_ARG, EVDEV, 0x01 + x + y, x, y);
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ioctl_macros() {
|
||||||
|
assert_eq!(0x0000_AE01, KVM_CREATE_VM());
|
||||||
|
assert_eq!(0x0000_AF01, VHOST_SET_OWNER());
|
||||||
|
assert_eq!(0x8004_54CF, TUNGETFEATURES());
|
||||||
|
assert_eq!(0x4004_54D9, TUNSETQUEUE());
|
||||||
|
assert_eq!(0xC004_AE02, KVM_GET_MSR_INDEX_LIST());
|
||||||
|
assert_eq!(0xC004_AF12, VHOST_GET_VRING_BASE());
|
||||||
|
|
||||||
|
assert_eq!(0x8080_4522, EVIOCGBIT(2));
|
||||||
|
assert_eq!(0x0000_4509, FAKE_IOCTL_2_ARG(3, 5));
|
||||||
|
}
|
||||||
|
}
|
78
vendor/git-643dc7ede01ca600/vmm-sys-util/src/lib.rs
vendored
Normal file
78
vendor/git-643dc7ede01ca600/vmm-sys-util/src/lib.rs
vendored
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
// Copyright 2019 Intel Corporation. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
extern crate libc;
|
||||||
|
|
||||||
|
mod tempdir;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
pub mod ioctl;
|
||||||
|
|
||||||
|
pub mod errno;
|
||||||
|
pub mod eventfd;
|
||||||
|
pub mod file_traits;
|
||||||
|
pub mod seek_hole;
|
||||||
|
pub mod signal;
|
||||||
|
pub mod terminal;
|
||||||
|
pub mod timerfd;
|
||||||
|
pub mod write_zeroes;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
pub mod syslog;
|
||||||
|
|
||||||
|
pub mod poll;
|
||||||
|
|
||||||
|
pub use crate::tempdir::*;
|
||||||
|
pub use errno::*;
|
||||||
|
pub use eventfd::*;
|
||||||
|
pub use poll::*;
|
||||||
|
|
||||||
|
use std::os::unix::io::AsRawFd;
|
||||||
|
|
||||||
|
pub use crate::file_traits::{FileSetLen, FileSync};
|
||||||
|
pub use crate::seek_hole::SeekHole;
|
||||||
|
pub use crate::write_zeroes::{PunchHole, WriteZeroes};
|
||||||
|
|
||||||
|
pub enum FallocateMode {
|
||||||
|
PunchHole,
|
||||||
|
ZeroRange,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Safe wrapper for `fallocate()`.
|
||||||
|
pub fn fallocate(
|
||||||
|
file: &dyn AsRawFd,
|
||||||
|
mode: FallocateMode,
|
||||||
|
keep_size: bool,
|
||||||
|
offset: u64,
|
||||||
|
len: u64,
|
||||||
|
) -> Result<()> {
|
||||||
|
let offset = if offset > libc::off64_t::max_value() as u64 {
|
||||||
|
return Err(Error::new(libc::EINVAL));
|
||||||
|
} else {
|
||||||
|
offset as libc::off64_t
|
||||||
|
};
|
||||||
|
|
||||||
|
let len = if len > libc::off64_t::max_value() as u64 {
|
||||||
|
return Err(Error::new(libc::EINVAL));
|
||||||
|
} else {
|
||||||
|
len as libc::off64_t
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut mode = match mode {
|
||||||
|
FallocateMode::PunchHole => libc::FALLOC_FL_PUNCH_HOLE,
|
||||||
|
FallocateMode::ZeroRange => libc::FALLOC_FL_ZERO_RANGE,
|
||||||
|
};
|
||||||
|
|
||||||
|
if keep_size {
|
||||||
|
mode |= libc::FALLOC_FL_KEEP_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safe since we pass in a valid fd and fallocate mode, validate offset and len,
|
||||||
|
// and check the return value.
|
||||||
|
let ret = unsafe { libc::fallocate64(file.as_raw_fd(), mode, offset, len) };
|
||||||
|
if ret < 0 {
|
||||||
|
errno_result()
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
711
vendor/git-643dc7ede01ca600/vmm-sys-util/src/poll.rs
vendored
Normal file
711
vendor/git-643dc7ede01ca600/vmm-sys-util/src/poll.rs
vendored
Normal file
@ -0,0 +1,711 @@
|
|||||||
|
// Copyright 2019 Intel Corporation. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
|
||||||
|
use std::cell::{Cell, Ref, RefCell};
|
||||||
|
use std::cmp::min;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::i32;
|
||||||
|
use std::i64;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
||||||
|
use std::ptr::null_mut;
|
||||||
|
use std::slice;
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use libc::{
|
||||||
|
c_int, epoll_create1, epoll_ctl, epoll_event, epoll_wait, EINTR, EPOLLHUP, EPOLLIN, EPOLLOUT,
|
||||||
|
EPOLL_CLOEXEC, EPOLL_CTL_ADD, EPOLL_CTL_DEL, EPOLL_CTL_MOD,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{errno_result, Error, Result};
|
||||||
|
|
||||||
|
macro_rules! handle_eintr_errno {
|
||||||
|
($x:expr) => {{
|
||||||
|
let mut res;
|
||||||
|
loop {
|
||||||
|
res = $x;
|
||||||
|
if res != -1 || Error::last() != Error::new(EINTR) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
const POLL_CONTEXT_MAX_EVENTS: usize = 16;
|
||||||
|
|
||||||
|
/// EpollEvents wraps raw epoll_events, it should only be used with EpollContext.
|
||||||
|
pub struct EpollEvents(RefCell<[epoll_event; POLL_CONTEXT_MAX_EVENTS]>);
|
||||||
|
|
||||||
|
impl EpollEvents {
|
||||||
|
pub fn new() -> EpollEvents {
|
||||||
|
EpollEvents(RefCell::new(
|
||||||
|
[epoll_event { events: 0, u64: 0 }; POLL_CONTEXT_MAX_EVENTS],
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for EpollEvents {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait for a token that can be associated with an `fd` in a `PollContext`.
|
||||||
|
///
|
||||||
|
/// Simple enums that have no or primitive variant data can use the `#[derive(PollToken)]`
|
||||||
|
/// custom derive to implement this trait.
|
||||||
|
pub trait PollToken {
|
||||||
|
/// Converts this token into a u64 that can be turned back into a token via `from_raw_token`.
|
||||||
|
fn as_raw_token(&self) -> u64;
|
||||||
|
|
||||||
|
/// Converts a raw token as returned from `as_raw_token` back into a token.
|
||||||
|
///
|
||||||
|
/// It is invalid to give a raw token that was not returned via `as_raw_token` from the same
|
||||||
|
/// `Self`. The implementation can expect that this will never happen as a result of its usage
|
||||||
|
/// in `PollContext`.
|
||||||
|
fn from_raw_token(data: u64) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PollToken for usize {
|
||||||
|
fn as_raw_token(&self) -> u64 {
|
||||||
|
*self as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_raw_token(data: u64) -> Self {
|
||||||
|
data as Self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PollToken for u64 {
|
||||||
|
fn as_raw_token(&self) -> u64 {
|
||||||
|
*self as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_raw_token(data: u64) -> Self {
|
||||||
|
data as Self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PollToken for u32 {
|
||||||
|
fn as_raw_token(&self) -> u64 {
|
||||||
|
u64::from(*self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_raw_token(data: u64) -> Self {
|
||||||
|
data as Self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PollToken for u16 {
|
||||||
|
fn as_raw_token(&self) -> u64 {
|
||||||
|
u64::from(*self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_raw_token(data: u64) -> Self {
|
||||||
|
data as Self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PollToken for u8 {
|
||||||
|
fn as_raw_token(&self) -> u64 {
|
||||||
|
u64::from(*self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_raw_token(data: u64) -> Self {
|
||||||
|
data as Self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PollToken for () {
|
||||||
|
fn as_raw_token(&self) -> u64 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_raw_token(_data: u64) -> Self {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An event returned by `PollContext::wait`.
|
||||||
|
pub struct PollEvent<'a, T> {
|
||||||
|
event: &'a epoll_event,
|
||||||
|
token: PhantomData<T>, // Needed to satisfy usage of T
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: PollToken> PollEvent<'a, T> {
|
||||||
|
/// Gets the token associated in `PollContext::add` with this event.
|
||||||
|
pub fn token(&self) -> T {
|
||||||
|
T::from_raw_token(self.event.u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// True if the `fd` associated with this token in `PollContext::add` is readable.
|
||||||
|
pub fn readable(&self) -> bool {
|
||||||
|
self.event.events & (EPOLLIN as u32) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// True if the `fd` associated with this token in `PollContext::add` has been hungup on.
|
||||||
|
pub fn hungup(&self) -> bool {
|
||||||
|
self.event.events & (EPOLLHUP as u32) != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An iterator over some (sub)set of events returned by `PollContext::wait`.
|
||||||
|
pub struct PollEventIter<'a, I, T>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = &'a epoll_event>,
|
||||||
|
{
|
||||||
|
mask: u32,
|
||||||
|
iter: I,
|
||||||
|
tokens: PhantomData<[T]>, // Needed to satisfy usage of T
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, I, T> Iterator for PollEventIter<'a, I, T>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = &'a epoll_event>,
|
||||||
|
T: PollToken,
|
||||||
|
{
|
||||||
|
type Item = PollEvent<'a, T>;
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let mask = self.mask;
|
||||||
|
self.iter
|
||||||
|
.find(|event| (event.events & mask) != 0)
|
||||||
|
.map(|event| PollEvent {
|
||||||
|
event,
|
||||||
|
token: PhantomData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The list of event returned by `PollContext::wait`.
|
||||||
|
pub struct PollEvents<'a, T> {
|
||||||
|
count: usize,
|
||||||
|
events: Ref<'a, [epoll_event; POLL_CONTEXT_MAX_EVENTS]>,
|
||||||
|
tokens: PhantomData<[T]>, // Needed to satisfy usage of T
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: PollToken> PollEvents<'a, T> {
|
||||||
|
/// Copies the events to an owned structure so the reference to this (and by extension
|
||||||
|
/// `PollContext`) can be dropped.
|
||||||
|
pub fn to_owned(&self) -> PollEventsOwned<T> {
|
||||||
|
PollEventsOwned {
|
||||||
|
count: self.count,
|
||||||
|
events: RefCell::new(*self.events),
|
||||||
|
tokens: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterates over each event.
|
||||||
|
pub fn iter(&self) -> PollEventIter<slice::Iter<epoll_event>, T> {
|
||||||
|
PollEventIter {
|
||||||
|
mask: 0xffff_ffff,
|
||||||
|
iter: self.events[..self.count].iter(),
|
||||||
|
tokens: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterates over each readable event.
|
||||||
|
pub fn iter_readable(&self) -> PollEventIter<slice::Iter<epoll_event>, T> {
|
||||||
|
PollEventIter {
|
||||||
|
mask: EPOLLIN as u32,
|
||||||
|
iter: self.events[..self.count].iter(),
|
||||||
|
tokens: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterates over each hungup event.
|
||||||
|
pub fn iter_hungup(&self) -> PollEventIter<slice::Iter<epoll_event>, T> {
|
||||||
|
PollEventIter {
|
||||||
|
mask: EPOLLHUP as u32,
|
||||||
|
iter: self.events[..self.count].iter(),
|
||||||
|
tokens: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A deep copy of the event records from `PollEvents`.
|
||||||
|
pub struct PollEventsOwned<T> {
|
||||||
|
count: usize,
|
||||||
|
events: RefCell<[epoll_event; POLL_CONTEXT_MAX_EVENTS]>,
|
||||||
|
tokens: PhantomData<T>, // Needed to satisfy usage of T
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PollToken> PollEventsOwned<T> {
|
||||||
|
/// Takes a reference to the events so that they can be iterated via methods in `PollEvents`.
|
||||||
|
pub fn as_ref(&self) -> PollEvents<T> {
|
||||||
|
PollEvents {
|
||||||
|
count: self.count,
|
||||||
|
events: self.events.borrow(),
|
||||||
|
tokens: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Watching events taken by PollContext.
|
||||||
|
pub struct WatchingEvents(u32);
|
||||||
|
|
||||||
|
impl WatchingEvents {
|
||||||
|
/// Returns empty Events.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn empty() -> WatchingEvents {
|
||||||
|
WatchingEvents(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build Events from raw epoll events (defined in epoll_ctl(2)).
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn new(raw: u32) -> WatchingEvents {
|
||||||
|
WatchingEvents(raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set read events.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_read(self) -> WatchingEvents {
|
||||||
|
WatchingEvents(self.0 | EPOLLIN as u32)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set write events.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_write(self) -> WatchingEvents {
|
||||||
|
WatchingEvents(self.0 | EPOLLOUT as u32)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the underlying epoll events.
|
||||||
|
pub fn get_raw(&self) -> u32 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// EpollContext wraps linux epoll. It provides similar interface to PollContext.
|
||||||
|
/// It is thread safe while PollContext is not. It requires user to pass in a reference of
|
||||||
|
/// EpollEvents while PollContext does not. Always use PollContext if you don't need to access the
|
||||||
|
/// same epoll from different threads.
|
||||||
|
pub struct EpollContext<T> {
|
||||||
|
epoll_ctx: File,
|
||||||
|
// Needed to satisfy usage of T
|
||||||
|
tokens: PhantomData<[T]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PollToken> EpollContext<T> {
|
||||||
|
/// Creates a new `EpollContext`.
|
||||||
|
pub fn new() -> Result<EpollContext<T>> {
|
||||||
|
// Safe because we check the return value.
|
||||||
|
let epoll_fd = unsafe { epoll_create1(EPOLL_CLOEXEC) };
|
||||||
|
if epoll_fd < 0 {
|
||||||
|
return errno_result();
|
||||||
|
}
|
||||||
|
Ok(EpollContext {
|
||||||
|
epoll_ctx: unsafe { File::from_raw_fd(epoll_fd) },
|
||||||
|
tokens: PhantomData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds the given `fd` to this context and associates the given `token` with the `fd`'s
|
||||||
|
/// readable events.
|
||||||
|
///
|
||||||
|
/// A `fd` can only be added once and does not need to be kept open. If the `fd` is dropped and
|
||||||
|
/// there were no duplicated file descriptors (i.e. adding the same descriptor with a different
|
||||||
|
/// FD number) added to this context, events will not be reported by `wait` anymore.
|
||||||
|
pub fn add(&self, fd: &AsRawFd, token: T) -> Result<()> {
|
||||||
|
self.add_fd_with_events(fd, WatchingEvents::empty().set_read(), token)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds the given `fd` to this context, watching for the specified events and associates the
|
||||||
|
/// given 'token' with those events.
|
||||||
|
///
|
||||||
|
/// A `fd` can only be added once and does not need to be kept open. If the `fd` is dropped and
|
||||||
|
/// there were no duplicated file descriptors (i.e. adding the same descriptor with a different
|
||||||
|
/// FD number) added to this context, events will not be reported by `wait` anymore.
|
||||||
|
pub fn add_fd_with_events(&self, fd: &AsRawFd, events: WatchingEvents, token: T) -> Result<()> {
|
||||||
|
let mut evt = epoll_event {
|
||||||
|
events: events.get_raw(),
|
||||||
|
u64: token.as_raw_token(),
|
||||||
|
};
|
||||||
|
// Safe because we give a valid epoll FD and FD to watch, as well as a valid epoll_event
|
||||||
|
// structure. Then we check the return value.
|
||||||
|
let ret = unsafe {
|
||||||
|
epoll_ctl(
|
||||||
|
self.epoll_ctx.as_raw_fd(),
|
||||||
|
EPOLL_CTL_ADD,
|
||||||
|
fd.as_raw_fd(),
|
||||||
|
&mut evt,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if ret < 0 {
|
||||||
|
return errno_result();
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If `fd` was previously added to this context, the watched events will be replaced with
|
||||||
|
/// `events` and the token associated with it will be replaced with the given `token`.
|
||||||
|
pub fn modify(&self, fd: &AsRawFd, events: WatchingEvents, token: T) -> Result<()> {
|
||||||
|
let mut evt = epoll_event {
|
||||||
|
events: events.0,
|
||||||
|
u64: token.as_raw_token(),
|
||||||
|
};
|
||||||
|
// Safe because we give a valid epoll FD and FD to modify, as well as a valid epoll_event
|
||||||
|
// structure. Then we check the return value.
|
||||||
|
let ret = unsafe {
|
||||||
|
epoll_ctl(
|
||||||
|
self.epoll_ctx.as_raw_fd(),
|
||||||
|
EPOLL_CTL_MOD,
|
||||||
|
fd.as_raw_fd(),
|
||||||
|
&mut evt,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if ret < 0 {
|
||||||
|
return errno_result();
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deletes the given `fd` from this context.
|
||||||
|
///
|
||||||
|
/// If an `fd`'s token shows up in the list of hangup events, it should be removed using this
|
||||||
|
/// method or by closing/dropping (if and only if the fd was never dup()'d/fork()'d) the `fd`.
|
||||||
|
/// Failure to do so will cause the `wait` method to always return immediately, causing ~100%
|
||||||
|
/// CPU load.
|
||||||
|
pub fn delete(&self, fd: &AsRawFd) -> Result<()> {
|
||||||
|
// Safe because we give a valid epoll FD and FD to stop watching. Then we check the return
|
||||||
|
// value.
|
||||||
|
let ret = unsafe {
|
||||||
|
epoll_ctl(
|
||||||
|
self.epoll_ctx.as_raw_fd(),
|
||||||
|
EPOLL_CTL_DEL,
|
||||||
|
fd.as_raw_fd(),
|
||||||
|
null_mut(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if ret < 0 {
|
||||||
|
return errno_result();
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Waits for any events to occur in FDs that were previously added to this context.
|
||||||
|
///
|
||||||
|
/// The events are level-triggered, meaning that if any events are unhandled (i.e. not reading
|
||||||
|
/// for readable events and not closing for hungup events), subsequent calls to `wait` will
|
||||||
|
/// return immediately. The consequence of not handling an event perpetually while calling
|
||||||
|
/// `wait` is that the callers loop will degenerated to busy loop polling, pinning a CPU to
|
||||||
|
/// ~100% usage.
|
||||||
|
pub fn wait<'a>(&self, events: &'a EpollEvents) -> Result<PollEvents<'a, T>> {
|
||||||
|
self.wait_timeout(events, Duration::new(i64::MAX as u64, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Like `wait` except will only block for a maximum of the given `timeout`.
|
||||||
|
///
|
||||||
|
/// This may return earlier than `timeout` with zero events if the duration indicated exceeds
|
||||||
|
/// system limits.
|
||||||
|
pub fn wait_timeout<'a>(
|
||||||
|
&self,
|
||||||
|
events: &'a EpollEvents,
|
||||||
|
timeout: Duration,
|
||||||
|
) -> Result<PollEvents<'a, T>> {
|
||||||
|
let timeout_millis = if timeout.as_secs() as i64 == i64::max_value() {
|
||||||
|
// We make the convenient assumption that 2^63 seconds is an effectively unbounded time
|
||||||
|
// frame. This is meant to mesh with `wait` calling us with no timeout.
|
||||||
|
-1
|
||||||
|
} else {
|
||||||
|
// In cases where we the number of milliseconds would overflow an i32, we substitute the
|
||||||
|
// maximum timeout which is ~24.8 days.
|
||||||
|
let millis = timeout
|
||||||
|
.as_secs()
|
||||||
|
.checked_mul(1_000)
|
||||||
|
.and_then(|ms| ms.checked_add(u64::from(timeout.subsec_nanos()) / 1_000_000))
|
||||||
|
.unwrap_or(i32::max_value() as u64);
|
||||||
|
min(i32::max_value() as u64, millis) as i32
|
||||||
|
};
|
||||||
|
let ret = {
|
||||||
|
let mut epoll_events = events.0.borrow_mut();
|
||||||
|
let max_events = epoll_events.len() as c_int;
|
||||||
|
// Safe because we give an epoll context and a properly sized epoll_events array
|
||||||
|
// pointer, which we trust the kernel to fill in properly.
|
||||||
|
unsafe {
|
||||||
|
handle_eintr_errno!(epoll_wait(
|
||||||
|
self.epoll_ctx.as_raw_fd(),
|
||||||
|
&mut epoll_events[0],
|
||||||
|
max_events,
|
||||||
|
timeout_millis
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if ret < 0 {
|
||||||
|
return errno_result();
|
||||||
|
}
|
||||||
|
let epoll_events = events.0.borrow();
|
||||||
|
let events = PollEvents {
|
||||||
|
count: ret as usize,
|
||||||
|
events: epoll_events,
|
||||||
|
tokens: PhantomData,
|
||||||
|
};
|
||||||
|
Ok(events)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PollToken> AsRawFd for EpollContext<T> {
|
||||||
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
|
self.epoll_ctx.as_raw_fd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PollToken> IntoRawFd for EpollContext<T> {
|
||||||
|
fn into_raw_fd(self) -> RawFd {
|
||||||
|
self.epoll_ctx.into_raw_fd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used to poll multiple objects that have file descriptors.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use vmm_sys_util::{Result, EventFd, PollContext, PollEvents};
|
||||||
|
/// # fn test() -> Result<()> {
|
||||||
|
/// let evt1 = EventFd::new(0)?;
|
||||||
|
/// let evt2 = EventFd::new(0)?;
|
||||||
|
/// evt2.write(1)?;
|
||||||
|
///
|
||||||
|
/// let ctx: PollContext<u32> = PollContext::new()?;
|
||||||
|
/// ctx.add(&evt1, 1)?;
|
||||||
|
/// ctx.add(&evt2, 2)?;
|
||||||
|
///
|
||||||
|
/// let pollevents: PollEvents<u32> = ctx.wait()?;
|
||||||
|
/// let tokens: Vec<u32> = pollevents.iter_readable().map(|e| e.token()).collect();
|
||||||
|
/// assert_eq!(&tokens[..], &[2]);
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub struct PollContext<T> {
|
||||||
|
epoll_ctx: EpollContext<T>,
|
||||||
|
|
||||||
|
// We use a RefCell here so that the `wait` method only requires an immutable self reference
|
||||||
|
// while returning the events (encapsulated by PollEvents). Without the RefCell, `wait` would
|
||||||
|
// hold a mutable reference that lives as long as its returned reference (i.e. the PollEvents),
|
||||||
|
// even though that reference is immutable. This is terribly inconvenient for the caller because
|
||||||
|
// the borrow checking would prevent them from using `delete` and `add` while the events are in
|
||||||
|
// scope.
|
||||||
|
events: EpollEvents,
|
||||||
|
|
||||||
|
// Hangup busy loop detection variables. See `check_for_hungup_busy_loop`.
|
||||||
|
hangups: Cell<usize>,
|
||||||
|
max_hangups: Cell<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PollToken> PollContext<T> {
|
||||||
|
/// Creates a new `PollContext`.
|
||||||
|
pub fn new() -> Result<PollContext<T>> {
|
||||||
|
Ok(PollContext {
|
||||||
|
epoll_ctx: EpollContext::new()?,
|
||||||
|
events: EpollEvents::new(),
|
||||||
|
hangups: Cell::new(0),
|
||||||
|
max_hangups: Cell::new(0),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds the given `fd` to this context and associates the given `token` with the `fd`'s
|
||||||
|
/// readable events.
|
||||||
|
///
|
||||||
|
/// A `fd` can only be added once and does not need to be kept open. If the `fd` is dropped and
|
||||||
|
/// there were no duplicated file descriptors (i.e. adding the same descriptor with a different
|
||||||
|
/// FD number) added to this context, events will not be reported by `wait` anymore.
|
||||||
|
pub fn add(&self, fd: &AsRawFd, token: T) -> Result<()> {
|
||||||
|
self.add_fd_with_events(fd, WatchingEvents::empty().set_read(), token)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds the given `fd` to this context, watching for the specified events and associates the
|
||||||
|
/// given 'token' with those events.
|
||||||
|
///
|
||||||
|
/// A `fd` can only be added once and does not need to be kept open. If the `fd` is dropped and
|
||||||
|
/// there were no duplicated file descriptors (i.e. adding the same descriptor with a different
|
||||||
|
/// FD number) added to this context, events will not be reported by `wait` anymore.
|
||||||
|
pub fn add_fd_with_events(&self, fd: &AsRawFd, events: WatchingEvents, token: T) -> Result<()> {
|
||||||
|
self.epoll_ctx.add_fd_with_events(fd, events, token)?;
|
||||||
|
self.hangups.set(0);
|
||||||
|
self.max_hangups.set(self.max_hangups.get() + 1);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If `fd` was previously added to this context, the watched events will be replaced with
|
||||||
|
/// `events` and the token associated with it will be replaced with the given `token`.
|
||||||
|
pub fn modify(&self, fd: &AsRawFd, events: WatchingEvents, token: T) -> Result<()> {
|
||||||
|
self.epoll_ctx.modify(fd, events, token)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deletes the given `fd` from this context.
|
||||||
|
///
|
||||||
|
/// If an `fd`'s token shows up in the list of hangup events, it should be removed using this
|
||||||
|
/// method or by closing/dropping (if and only if the fd was never dup()'d/fork()'d) the `fd`.
|
||||||
|
/// Failure to do so will cause the `wait` method to always return immediately, causing ~100%
|
||||||
|
/// CPU load.
|
||||||
|
pub fn delete(&self, fd: &AsRawFd) -> Result<()> {
|
||||||
|
self.epoll_ctx.delete(fd)?;
|
||||||
|
self.hangups.set(0);
|
||||||
|
self.max_hangups.set(self.max_hangups.get() - 1);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method determines if the the user of wait is misusing the `PollContext` by leaving FDs
|
||||||
|
// in this `PollContext` that have been shutdown or hungup on. Such an FD will cause `wait` to
|
||||||
|
// return instantly with a hungup event. If that FD is perpetually left in this context, a busy
|
||||||
|
// loop burning ~100% of one CPU will silently occur with no human visible malfunction.
|
||||||
|
//
|
||||||
|
// How do we know if the client of this context is ignoring hangups? A naive implementation
|
||||||
|
// would trigger if consecutive wait calls yield hangup events, but there are legitimate cases
|
||||||
|
// for this, such as two distinct sockets becoming hungup across two consecutive wait calls. A
|
||||||
|
// smarter implementation would only trigger if `delete` wasn't called between waits that
|
||||||
|
// yielded hangups. Sadly `delete` isn't the only way to remove an FD from this context. The
|
||||||
|
// other way is for the client to close the hungup FD, which automatically removes it from this
|
||||||
|
// context. Assuming that the client always uses close, this implementation would too eagerly
|
||||||
|
// trigger.
|
||||||
|
//
|
||||||
|
// The implementation used here keeps an upper bound of FDs in this context using a counter
|
||||||
|
// hooked into add/delete (which is imprecise because close can also remove FDs without us
|
||||||
|
// knowing). The number of consecutive (no add or delete in between) hangups yielded by wait
|
||||||
|
// calls is counted and compared to the upper bound. If the upper bound is exceeded by the
|
||||||
|
// consecutive hangups, the implementation triggers the check and logs.
|
||||||
|
//
|
||||||
|
// This implementation has false negatives because the upper bound can be completely too high,
|
||||||
|
// in the worst case caused by only using close instead of delete. However, this method has the
|
||||||
|
// advantage of always triggering eventually genuine busy loop cases, requires no dynamic
|
||||||
|
// allocations, is fast and constant time to compute, and has no false positives.
|
||||||
|
fn check_for_hungup_busy_loop(&self, new_hangups: usize) {
|
||||||
|
let old_hangups = self.hangups.get();
|
||||||
|
let max_hangups = self.max_hangups.get();
|
||||||
|
if old_hangups <= max_hangups && old_hangups + new_hangups > max_hangups {
|
||||||
|
warn!(
|
||||||
|
"busy poll wait loop with hungup FDs detected on thread {}",
|
||||||
|
thread::current().name().unwrap_or("")
|
||||||
|
);
|
||||||
|
// This panic is helpful for tests of this functionality.
|
||||||
|
#[cfg(test)]
|
||||||
|
panic!("hungup busy loop detected");
|
||||||
|
}
|
||||||
|
self.hangups.set(old_hangups + new_hangups);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Waits for any events to occur in FDs that were previously added to this context.
|
||||||
|
///
|
||||||
|
/// The events are level-triggered, meaning that if any events are unhandled (i.e. not reading
|
||||||
|
/// for readable events and not closing for hungup events), subsequent calls to `wait` will
|
||||||
|
/// return immediately. The consequence of not handling an event perpetually while calling
|
||||||
|
/// `wait` is that the callers loop will degenerated to busy loop polling, pinning a CPU to
|
||||||
|
/// ~100% usage.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
/// Panics if the returned `PollEvents` structure is not dropped before subsequent `wait` calls.
|
||||||
|
pub fn wait(&self) -> Result<PollEvents<T>> {
|
||||||
|
self.wait_timeout(Duration::new(i64::MAX as u64, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Like `wait` except will only block for a maximum of the given `timeout`.
|
||||||
|
///
|
||||||
|
/// This may return earlier than `timeout` with zero events if the duration indicated exceeds
|
||||||
|
/// system limits.
|
||||||
|
pub fn wait_timeout(&self, timeout: Duration) -> Result<PollEvents<T>> {
|
||||||
|
let events = self.epoll_ctx.wait_timeout(&self.events, timeout)?;
|
||||||
|
let hangups = events.iter_hungup().count();
|
||||||
|
self.check_for_hungup_busy_loop(hangups);
|
||||||
|
Ok(events)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PollToken> AsRawFd for PollContext<T> {
|
||||||
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
|
self.epoll_ctx.as_raw_fd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PollToken> IntoRawFd for PollContext<T> {
|
||||||
|
fn into_raw_fd(self) -> RawFd {
|
||||||
|
self.epoll_ctx.into_raw_fd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::eventfd::EventFd;
|
||||||
|
use std::os::unix::net::UnixStream;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_poll_context() {
|
||||||
|
let evt1 = EventFd::new(0).unwrap();
|
||||||
|
let evt2 = EventFd::new(0).unwrap();
|
||||||
|
evt1.write(1).unwrap();
|
||||||
|
evt2.write(1).unwrap();
|
||||||
|
let ctx: PollContext<u32> = PollContext::new().unwrap();
|
||||||
|
ctx.add(&evt1, 1).unwrap();
|
||||||
|
ctx.add(&evt2, 2).unwrap();
|
||||||
|
|
||||||
|
let mut evt_count = 0;
|
||||||
|
while evt_count < 2 {
|
||||||
|
for event in ctx.wait().unwrap().iter_readable() {
|
||||||
|
evt_count += 1;
|
||||||
|
match event.token() {
|
||||||
|
1 => {
|
||||||
|
evt1.read().unwrap();
|
||||||
|
ctx.delete(&evt1).unwrap();
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
evt2.read().unwrap();
|
||||||
|
ctx.delete(&evt2).unwrap();
|
||||||
|
}
|
||||||
|
_ => panic!("unexpected token"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(evt_count, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_poll_context_overflow() {
|
||||||
|
const EVT_COUNT: usize = POLL_CONTEXT_MAX_EVENTS * 2 + 1;
|
||||||
|
let ctx: PollContext<usize> = PollContext::new().unwrap();
|
||||||
|
let mut evts = Vec::with_capacity(EVT_COUNT);
|
||||||
|
for i in 0..EVT_COUNT {
|
||||||
|
let evt = EventFd::new(0).unwrap();
|
||||||
|
evt.write(1).unwrap();
|
||||||
|
ctx.add(&evt, i).unwrap();
|
||||||
|
evts.push(evt);
|
||||||
|
}
|
||||||
|
let mut evt_count = 0;
|
||||||
|
while evt_count < EVT_COUNT {
|
||||||
|
for event in ctx.wait().unwrap().iter_readable() {
|
||||||
|
evts[event.token()].read().unwrap();
|
||||||
|
evt_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn test_poll_context_hungup() {
|
||||||
|
let (s1, s2) = UnixStream::pair().unwrap();
|
||||||
|
let ctx: PollContext<u32> = PollContext::new().unwrap();
|
||||||
|
ctx.add(&s1, 1).unwrap();
|
||||||
|
|
||||||
|
// Causes s1 to receive hangup events, which we purposefully ignore to trip the detection
|
||||||
|
// logic in `PollContext`.
|
||||||
|
drop(s2);
|
||||||
|
|
||||||
|
// Should easily panic within this many iterations.
|
||||||
|
for _ in 0..1000 {
|
||||||
|
ctx.wait().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_poll_context_timeout() {
|
||||||
|
let ctx: PollContext<u32> = PollContext::new().unwrap();
|
||||||
|
let dur = Duration::from_millis(10);
|
||||||
|
let start_inst = Instant::now();
|
||||||
|
ctx.wait_timeout(dur).unwrap();
|
||||||
|
assert!(start_inst.elapsed() >= dur);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
215
vendor/git-643dc7ede01ca600/vmm-sys-util/src/seek_hole.rs
vendored
Normal file
215
vendor/git-643dc7ede01ca600/vmm-sys-util/src/seek_hole.rs
vendored
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{Error, Result};
|
||||||
|
use std::os::unix::io::AsRawFd;
|
||||||
|
|
||||||
|
#[cfg(target_env = "musl")]
|
||||||
|
use libc::{c_int, lseek64, ENXIO};
|
||||||
|
|
||||||
|
#[cfg(target_env = "gnu")]
|
||||||
|
use libc::{lseek64, ENXIO, SEEK_DATA, SEEK_HOLE};
|
||||||
|
|
||||||
|
/// A trait for seeking to the next hole or non-hole position in a file.
|
||||||
|
pub trait SeekHole {
|
||||||
|
/// Seek to the first hole in a file at a position greater than or equal to `offset`.
|
||||||
|
/// If no holes exist after `offset`, the seek position will be set to the end of the file.
|
||||||
|
/// If `offset` is at or after the end of the file, the seek position is unchanged, and None is returned.
|
||||||
|
/// Returns the current seek position after the seek or an error.
|
||||||
|
fn seek_hole(&mut self, offset: u64) -> Result<Option<u64>>;
|
||||||
|
|
||||||
|
/// Seek to the first data in a file at a position greater than or equal to `offset`.
|
||||||
|
/// If no data exists after `offset`, the seek position is unchanged, and None is returned.
|
||||||
|
/// Returns the current offset after the seek or an error.
|
||||||
|
fn seek_data(&mut self, offset: u64) -> Result<Option<u64>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_env = "musl")]
|
||||||
|
pub const SEEK_DATA: c_int = 3;
|
||||||
|
#[cfg(target_env = "musl")]
|
||||||
|
pub const SEEK_HOLE: c_int = 4;
|
||||||
|
|
||||||
|
/// Safe wrapper for `libc::lseek64()`
|
||||||
|
fn lseek(file: &mut File, offset: i64, whence: i32) -> Result<Option<u64>> {
|
||||||
|
// This is safe because we pass a known-good file descriptor.
|
||||||
|
let res = unsafe { lseek64(file.as_raw_fd(), offset, whence) };
|
||||||
|
|
||||||
|
if res < 0 {
|
||||||
|
// Convert ENXIO into None; pass any other error as-is.
|
||||||
|
let err = Error::last_os_error();
|
||||||
|
if let Some(errno) = Error::raw_os_error(&err) {
|
||||||
|
if errno == ENXIO {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err)
|
||||||
|
} else {
|
||||||
|
Ok(Some(res as u64))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SeekHole for File {
|
||||||
|
fn seek_hole(&mut self, offset: u64) -> Result<Option<u64>> {
|
||||||
|
lseek(self, offset as i64, SEEK_HOLE)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn seek_data(&mut self, offset: u64) -> Result<Option<u64>> {
|
||||||
|
lseek(self, offset as i64, SEEK_DATA)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::TempDir;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{Seek, SeekFrom, Write};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
fn seek_cur(file: &mut File) -> u64 {
|
||||||
|
file.seek(SeekFrom::Current(0)).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn seek_data() {
|
||||||
|
let tempdir = TempDir::new("/tmp/seek_data_test").unwrap();
|
||||||
|
let mut path = PathBuf::from(tempdir.as_path().unwrap());
|
||||||
|
path.push("test_file");
|
||||||
|
let mut file = File::create(&path).unwrap();
|
||||||
|
|
||||||
|
// Empty file
|
||||||
|
assert_eq!(file.seek_data(0).unwrap(), None);
|
||||||
|
assert_eq!(seek_cur(&mut file), 0);
|
||||||
|
|
||||||
|
// File with non-zero length consisting entirely of a hole
|
||||||
|
file.set_len(0x10000).unwrap();
|
||||||
|
assert_eq!(file.seek_data(0).unwrap(), None);
|
||||||
|
assert_eq!(seek_cur(&mut file), 0);
|
||||||
|
|
||||||
|
// seek_data at or after the end of the file should return None
|
||||||
|
assert_eq!(file.seek_data(0x10000).unwrap(), None);
|
||||||
|
assert_eq!(seek_cur(&mut file), 0);
|
||||||
|
assert_eq!(file.seek_data(0x10001).unwrap(), None);
|
||||||
|
assert_eq!(seek_cur(&mut file), 0);
|
||||||
|
|
||||||
|
// Write some data to [0x10000, 0x20000)
|
||||||
|
let b = [0x55u8; 0x10000];
|
||||||
|
file.seek(SeekFrom::Start(0x10000)).unwrap();
|
||||||
|
file.write_all(&b).unwrap();
|
||||||
|
assert_eq!(file.seek_data(0).unwrap(), Some(0x10000));
|
||||||
|
assert_eq!(seek_cur(&mut file), 0x10000);
|
||||||
|
|
||||||
|
// seek_data within data should return the same offset
|
||||||
|
assert_eq!(file.seek_data(0x10000).unwrap(), Some(0x10000));
|
||||||
|
assert_eq!(seek_cur(&mut file), 0x10000);
|
||||||
|
assert_eq!(file.seek_data(0x10001).unwrap(), Some(0x10001));
|
||||||
|
assert_eq!(seek_cur(&mut file), 0x10001);
|
||||||
|
assert_eq!(file.seek_data(0x1FFFF).unwrap(), Some(0x1FFFF));
|
||||||
|
assert_eq!(seek_cur(&mut file), 0x1FFFF);
|
||||||
|
|
||||||
|
// Extend the file to add another hole after the data
|
||||||
|
file.set_len(0x30000).unwrap();
|
||||||
|
assert_eq!(file.seek_data(0).unwrap(), Some(0x10000));
|
||||||
|
assert_eq!(seek_cur(&mut file), 0x10000);
|
||||||
|
assert_eq!(file.seek_data(0x1FFFF).unwrap(), Some(0x1FFFF));
|
||||||
|
assert_eq!(seek_cur(&mut file), 0x1FFFF);
|
||||||
|
assert_eq!(file.seek_data(0x20000).unwrap(), None);
|
||||||
|
assert_eq!(seek_cur(&mut file), 0x1FFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[allow(clippy::cyclomatic_complexity)]
|
||||||
|
fn seek_hole() {
|
||||||
|
let tempdir = TempDir::new("/tmp/seek_hole_test").unwrap();
|
||||||
|
let mut path = PathBuf::from(tempdir.as_path().unwrap());
|
||||||
|
path.push("test_file");
|
||||||
|
let mut file = File::create(&path).unwrap();
|
||||||
|
|
||||||
|
// Empty file
|
||||||
|
assert_eq!(file.seek_hole(0).unwrap(), None);
|
||||||
|
assert_eq!(seek_cur(&mut file), 0);
|
||||||
|
|
||||||
|
// File with non-zero length consisting entirely of a hole
|
||||||
|
file.set_len(0x10000).unwrap();
|
||||||
|
assert_eq!(file.seek_hole(0).unwrap(), Some(0));
|
||||||
|
assert_eq!(seek_cur(&mut file), 0);
|
||||||
|
assert_eq!(file.seek_hole(0xFFFF).unwrap(), Some(0xFFFF));
|
||||||
|
assert_eq!(seek_cur(&mut file), 0xFFFF);
|
||||||
|
|
||||||
|
// seek_hole at or after the end of the file should return None
|
||||||
|
file.seek(SeekFrom::Start(0)).unwrap();
|
||||||
|
assert_eq!(file.seek_hole(0x10000).unwrap(), None);
|
||||||
|
assert_eq!(seek_cur(&mut file), 0);
|
||||||
|
assert_eq!(file.seek_hole(0x10001).unwrap(), None);
|
||||||
|
assert_eq!(seek_cur(&mut file), 0);
|
||||||
|
|
||||||
|
// Write some data to [0x10000, 0x20000)
|
||||||
|
let b = [0x55u8; 0x10000];
|
||||||
|
file.seek(SeekFrom::Start(0x10000)).unwrap();
|
||||||
|
file.write_all(&b).unwrap();
|
||||||
|
|
||||||
|
// seek_hole within a hole should return the same offset
|
||||||
|
assert_eq!(file.seek_hole(0).unwrap(), Some(0));
|
||||||
|
assert_eq!(seek_cur(&mut file), 0);
|
||||||
|
assert_eq!(file.seek_hole(0xFFFF).unwrap(), Some(0xFFFF));
|
||||||
|
assert_eq!(seek_cur(&mut file), 0xFFFF);
|
||||||
|
|
||||||
|
// seek_hole within data should return the next hole (EOF)
|
||||||
|
file.seek(SeekFrom::Start(0)).unwrap();
|
||||||
|
assert_eq!(file.seek_hole(0x10000).unwrap(), Some(0x20000));
|
||||||
|
assert_eq!(seek_cur(&mut file), 0x20000);
|
||||||
|
file.seek(SeekFrom::Start(0)).unwrap();
|
||||||
|
assert_eq!(file.seek_hole(0x10001).unwrap(), Some(0x20000));
|
||||||
|
assert_eq!(seek_cur(&mut file), 0x20000);
|
||||||
|
file.seek(SeekFrom::Start(0)).unwrap();
|
||||||
|
assert_eq!(file.seek_hole(0x1FFFF).unwrap(), Some(0x20000));
|
||||||
|
assert_eq!(seek_cur(&mut file), 0x20000);
|
||||||
|
|
||||||
|
// seek_hole at EOF after data should return None
|
||||||
|
file.seek(SeekFrom::Start(0)).unwrap();
|
||||||
|
assert_eq!(file.seek_hole(0x20000).unwrap(), None);
|
||||||
|
assert_eq!(seek_cur(&mut file), 0);
|
||||||
|
|
||||||
|
// Extend the file to add another hole after the data
|
||||||
|
file.set_len(0x30000).unwrap();
|
||||||
|
assert_eq!(file.seek_hole(0).unwrap(), Some(0));
|
||||||
|
assert_eq!(seek_cur(&mut file), 0);
|
||||||
|
assert_eq!(file.seek_hole(0xFFFF).unwrap(), Some(0xFFFF));
|
||||||
|
assert_eq!(seek_cur(&mut file), 0xFFFF);
|
||||||
|
file.seek(SeekFrom::Start(0)).unwrap();
|
||||||
|
assert_eq!(file.seek_hole(0x10000).unwrap(), Some(0x20000));
|
||||||
|
assert_eq!(seek_cur(&mut file), 0x20000);
|
||||||
|
file.seek(SeekFrom::Start(0)).unwrap();
|
||||||
|
assert_eq!(file.seek_hole(0x1FFFF).unwrap(), Some(0x20000));
|
||||||
|
assert_eq!(seek_cur(&mut file), 0x20000);
|
||||||
|
file.seek(SeekFrom::Start(0)).unwrap();
|
||||||
|
assert_eq!(file.seek_hole(0x20000).unwrap(), Some(0x20000));
|
||||||
|
assert_eq!(seek_cur(&mut file), 0x20000);
|
||||||
|
file.seek(SeekFrom::Start(0)).unwrap();
|
||||||
|
assert_eq!(file.seek_hole(0x20001).unwrap(), Some(0x20001));
|
||||||
|
assert_eq!(seek_cur(&mut file), 0x20001);
|
||||||
|
|
||||||
|
// seek_hole at EOF after a hole should return None
|
||||||
|
file.seek(SeekFrom::Start(0)).unwrap();
|
||||||
|
assert_eq!(file.seek_hole(0x30000).unwrap(), None);
|
||||||
|
assert_eq!(seek_cur(&mut file), 0);
|
||||||
|
|
||||||
|
// Write some data to [0x20000, 0x30000)
|
||||||
|
file.seek(SeekFrom::Start(0x20000)).unwrap();
|
||||||
|
file.write_all(&b).unwrap();
|
||||||
|
|
||||||
|
// seek_hole within [0x20000, 0x30000) should now find the hole at EOF
|
||||||
|
assert_eq!(file.seek_hole(0x20000).unwrap(), Some(0x30000));
|
||||||
|
assert_eq!(seek_cur(&mut file), 0x30000);
|
||||||
|
file.seek(SeekFrom::Start(0)).unwrap();
|
||||||
|
assert_eq!(file.seek_hole(0x20001).unwrap(), Some(0x30000));
|
||||||
|
assert_eq!(seek_cur(&mut file), 0x30000);
|
||||||
|
file.seek(SeekFrom::Start(0)).unwrap();
|
||||||
|
assert_eq!(file.seek_hole(0x30000).unwrap(), None);
|
||||||
|
assert_eq!(seek_cur(&mut file), 0);
|
||||||
|
}
|
||||||
|
}
|
423
vendor/git-643dc7ede01ca600/vmm-sys-util/src/signal.rs
vendored
Normal file
423
vendor/git-643dc7ede01ca600/vmm-sys-util/src/signal.rs
vendored
Normal file
@ -0,0 +1,423 @@
|
|||||||
|
// Copyright 2019 Intel Corporation. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
|
||||||
|
use libc::{
|
||||||
|
c_int, c_void, pthread_kill, pthread_sigmask, pthread_t, sigaction, sigaddset, sigemptyset,
|
||||||
|
siginfo_t, sigismember, sigpending, sigset_t, sigtimedwait, timespec, EAGAIN, EINTR, EINVAL,
|
||||||
|
SIGHUP, SIGSYS, SIG_BLOCK, SIG_UNBLOCK,
|
||||||
|
};
|
||||||
|
|
||||||
|
use errno;
|
||||||
|
use std::fmt::{self, Display};
|
||||||
|
use std::io;
|
||||||
|
use std::mem;
|
||||||
|
use std::os::unix::thread::JoinHandleExt;
|
||||||
|
use std::ptr::{null, null_mut};
|
||||||
|
use std::result;
|
||||||
|
use std::thread::JoinHandle;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// Couldn't create a sigset.
|
||||||
|
CreateSigset(errno::Error),
|
||||||
|
/// The wrapped signal has already been blocked.
|
||||||
|
SignalAlreadyBlocked(c_int),
|
||||||
|
/// Failed to check if the requested signal is in the blocked set already.
|
||||||
|
CompareBlockedSignals(errno::Error),
|
||||||
|
/// The signal could not be blocked.
|
||||||
|
BlockSignal(errno::Error),
|
||||||
|
/// The signal mask could not be retrieved.
|
||||||
|
RetrieveSignalMask(i32),
|
||||||
|
/// The signal could not be unblocked.
|
||||||
|
UnblockSignal(errno::Error),
|
||||||
|
/// Failed to wait for given signal.
|
||||||
|
ClearWaitPending(errno::Error),
|
||||||
|
/// Failed to get pending signals.
|
||||||
|
ClearGetPending(errno::Error),
|
||||||
|
/// Failed to check if given signal is in the set of pending signals.
|
||||||
|
ClearCheckPending(errno::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
use self::Error::*;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
CreateSigset(e) => write!(f, "couldn't create a sigset: {}", e),
|
||||||
|
SignalAlreadyBlocked(num) => write!(f, "signal {} already blocked", num),
|
||||||
|
CompareBlockedSignals(e) => write!(
|
||||||
|
f,
|
||||||
|
"failed to check whether requested signal is in the blocked set: {}",
|
||||||
|
e,
|
||||||
|
),
|
||||||
|
BlockSignal(e) => write!(f, "signal could not be blocked: {}", e),
|
||||||
|
RetrieveSignalMask(errno) => write!(
|
||||||
|
f,
|
||||||
|
"failed to retrieve signal mask: {}",
|
||||||
|
io::Error::from_raw_os_error(*errno),
|
||||||
|
),
|
||||||
|
UnblockSignal(e) => write!(f, "signal could not be unblocked: {}", e),
|
||||||
|
ClearWaitPending(e) => write!(f, "failed to wait for given signal: {}", e),
|
||||||
|
ClearGetPending(e) => write!(f, "failed to get pending signals: {}", e),
|
||||||
|
ClearCheckPending(e) => write!(
|
||||||
|
f,
|
||||||
|
"failed to check whether given signal is in the pending set: {}",
|
||||||
|
e,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type SignalResult<T> = result::Result<T, Error>;
|
||||||
|
type SiginfoHandler = extern "C" fn(num: c_int, info: *mut siginfo_t, _unused: *mut c_void) -> ();
|
||||||
|
|
||||||
|
pub enum SignalHandler {
|
||||||
|
Siginfo(SiginfoHandler),
|
||||||
|
// TODO add a`SimpleHandler` when `libc` adds `sa_handler` support to `sigaction`.
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SignalHandler {
|
||||||
|
fn set_flags(act: &mut sigaction, flag: c_int) {
|
||||||
|
act.sa_flags = flag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Fills a `sigaction` structure from of the signal handler.
|
||||||
|
/// Refer to http://man7.org/linux/man-pages/man7/signal.7.html
|
||||||
|
impl Into<sigaction> for SignalHandler {
|
||||||
|
fn into(self) -> sigaction {
|
||||||
|
let mut act: sigaction = unsafe { mem::zeroed() };
|
||||||
|
match self {
|
||||||
|
SignalHandler::Siginfo(function) => {
|
||||||
|
act.sa_sigaction = function as *const () as usize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
act
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn __libc_current_sigrtmin() -> c_int;
|
||||||
|
fn __libc_current_sigrtmax() -> c_int;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the minimum (inclusive) real-time signal number.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn SIGRTMIN() -> c_int {
|
||||||
|
unsafe { __libc_current_sigrtmin() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the maximum (inclusive) real-time signal number.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn SIGRTMAX() -> c_int {
|
||||||
|
unsafe { __libc_current_sigrtmax() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verifies that a signal number is valid: for VCPU signals, it needs to be enclosed within the OS
|
||||||
|
/// limits for realtime signals, and the remaining ones need to be between the minimum (SIGHUP) and
|
||||||
|
/// maximum (SIGSYS) values.
|
||||||
|
pub fn validate_signal_num(num: c_int, for_vcpu: bool) -> errno::Result<c_int> {
|
||||||
|
if for_vcpu {
|
||||||
|
let actual_num = num + SIGRTMIN();
|
||||||
|
if actual_num <= SIGRTMAX() {
|
||||||
|
return Ok(actual_num);
|
||||||
|
}
|
||||||
|
} else if SIGHUP <= num && num <= SIGSYS {
|
||||||
|
return Ok(num);
|
||||||
|
}
|
||||||
|
Err(errno::Error::new(EINVAL))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Registers `handler` as the signal handler of signum `num`.
|
||||||
|
///
|
||||||
|
/// Uses `sigaction` to register the handler.
|
||||||
|
///
|
||||||
|
/// This is considered unsafe because the given handler will be called asynchronously, interrupting
|
||||||
|
/// whatever the thread was doing and therefore must only do async-signal-safe operations.
|
||||||
|
/// flags: SA_SIGINFO or SA_RESTART if wants to restart after signal received.
|
||||||
|
pub unsafe fn register_signal_handler(
|
||||||
|
num: i32,
|
||||||
|
handler: SignalHandler,
|
||||||
|
for_vcpu: bool,
|
||||||
|
flag: c_int,
|
||||||
|
) -> errno::Result<()> {
|
||||||
|
let num = validate_signal_num(num, for_vcpu)?;
|
||||||
|
let mut act: sigaction = handler.into();
|
||||||
|
SignalHandler::set_flags(&mut act, flag);
|
||||||
|
match sigaction(num, &act, null_mut()) {
|
||||||
|
0 => Ok(()),
|
||||||
|
_ => errno::errno_result(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates `sigset` from an array of signal numbers.
|
||||||
|
///
|
||||||
|
/// This is a helper function used when we want to manipulate signals.
|
||||||
|
pub fn create_sigset(signals: &[c_int]) -> errno::Result<sigset_t> {
|
||||||
|
// sigset will actually be initialized by sigemptyset below.
|
||||||
|
let mut sigset: sigset_t = unsafe { mem::zeroed() };
|
||||||
|
|
||||||
|
// Safe - return value is checked.
|
||||||
|
let ret = unsafe { sigemptyset(&mut sigset) };
|
||||||
|
if ret < 0 {
|
||||||
|
return errno::errno_result();
|
||||||
|
}
|
||||||
|
|
||||||
|
for signal in signals {
|
||||||
|
// Safe - return value is checked.
|
||||||
|
let ret = unsafe { sigaddset(&mut sigset, *signal) };
|
||||||
|
if ret < 0 {
|
||||||
|
return errno::errno_result();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(sigset)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves the signal mask of the current thread as a vector of c_ints.
|
||||||
|
pub fn get_blocked_signals() -> SignalResult<Vec<c_int>> {
|
||||||
|
let mut mask = Vec::new();
|
||||||
|
|
||||||
|
// Safe - return values are checked.
|
||||||
|
unsafe {
|
||||||
|
let mut old_sigset: sigset_t = mem::zeroed();
|
||||||
|
let ret = pthread_sigmask(SIG_BLOCK, null(), &mut old_sigset as *mut sigset_t);
|
||||||
|
if ret < 0 {
|
||||||
|
return Err(Error::RetrieveSignalMask(ret));
|
||||||
|
}
|
||||||
|
|
||||||
|
for num in 0..=SIGRTMAX() {
|
||||||
|
if sigismember(&old_sigset, num) > 0 {
|
||||||
|
mask.push(num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(mask)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Masks given signal.
|
||||||
|
///
|
||||||
|
/// If signal is already blocked the call will fail with Error::SignalAlreadyBlocked
|
||||||
|
/// result.
|
||||||
|
pub fn block_signal(num: c_int) -> SignalResult<()> {
|
||||||
|
let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
|
||||||
|
|
||||||
|
// Safe - return values are checked.
|
||||||
|
unsafe {
|
||||||
|
let mut old_sigset: sigset_t = mem::zeroed();
|
||||||
|
let ret = pthread_sigmask(SIG_BLOCK, &sigset, &mut old_sigset as *mut sigset_t);
|
||||||
|
if ret < 0 {
|
||||||
|
return Err(Error::BlockSignal(errno::Error::last()));
|
||||||
|
}
|
||||||
|
let ret = sigismember(&old_sigset, num);
|
||||||
|
if ret < 0 {
|
||||||
|
return Err(Error::CompareBlockedSignals(errno::Error::last()));
|
||||||
|
} else if ret > 0 {
|
||||||
|
return Err(Error::SignalAlreadyBlocked(num));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unmasks given signal.
|
||||||
|
pub fn unblock_signal(num: c_int) -> SignalResult<()> {
|
||||||
|
let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
|
||||||
|
|
||||||
|
// Safe - return value is checked.
|
||||||
|
let ret = unsafe { pthread_sigmask(SIG_UNBLOCK, &sigset, null_mut()) };
|
||||||
|
if ret < 0 {
|
||||||
|
return Err(Error::UnblockSignal(errno::Error::last()));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clears pending signal.
|
||||||
|
pub fn clear_signal(num: c_int) -> SignalResult<()> {
|
||||||
|
let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
|
||||||
|
|
||||||
|
while {
|
||||||
|
// This is safe as we are rigorously checking return values
|
||||||
|
// of libc calls.
|
||||||
|
unsafe {
|
||||||
|
let mut siginfo: siginfo_t = mem::zeroed();
|
||||||
|
let ts = timespec {
|
||||||
|
tv_sec: 0,
|
||||||
|
tv_nsec: 0,
|
||||||
|
};
|
||||||
|
// Attempt to consume one instance of pending signal. If signal
|
||||||
|
// is not pending, the call will fail with EAGAIN or EINTR.
|
||||||
|
let ret = sigtimedwait(&sigset, &mut siginfo, &ts);
|
||||||
|
if ret < 0 {
|
||||||
|
let e = errno::Error::last();
|
||||||
|
match e.errno() {
|
||||||
|
EAGAIN | EINTR => {}
|
||||||
|
_ => {
|
||||||
|
return Err(Error::ClearWaitPending(errno::Error::last()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This sigset will be actually filled with `sigpending` call.
|
||||||
|
let mut chkset: sigset_t = mem::zeroed();
|
||||||
|
// See if more instances of the signal are pending.
|
||||||
|
let ret = sigpending(&mut chkset);
|
||||||
|
if ret < 0 {
|
||||||
|
return Err(Error::ClearGetPending(errno::Error::last()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let ret = sigismember(&chkset, num);
|
||||||
|
if ret < 0 {
|
||||||
|
return Err(Error::ClearCheckPending(errno::Error::last()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is do-while loop condition.
|
||||||
|
ret != 0
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait for threads that can be signalled via `pthread_kill`.
|
||||||
|
///
|
||||||
|
/// Note that this is only useful for signals between SIGRTMIN and SIGRTMAX because these are
|
||||||
|
/// guaranteed to not be used by the C runtime.
|
||||||
|
///
|
||||||
|
/// This is marked unsafe because the implementation of this trait must guarantee that the returned
|
||||||
|
/// pthread_t is valid and has a lifetime at least that of the trait object.
|
||||||
|
pub unsafe trait Killable {
|
||||||
|
fn pthread_handle(&self) -> pthread_t;
|
||||||
|
|
||||||
|
/// Sends the signal `num + SIGRTMIN` to this killable thread.
|
||||||
|
///
|
||||||
|
/// The value of `num + SIGRTMIN` must not exceed `SIGRTMAX`.
|
||||||
|
fn kill(&self, num: i32) -> errno::Result<()> {
|
||||||
|
let num = validate_signal_num(num, true)?;
|
||||||
|
|
||||||
|
// Safe because we ensure we are using a valid pthread handle, a valid signal number, and
|
||||||
|
// check the return result.
|
||||||
|
let ret = unsafe { pthread_kill(self.pthread_handle(), num) };
|
||||||
|
if ret < 0 {
|
||||||
|
return errno::errno_result();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safe because we fulfill our contract of returning a genuine pthread handle.
|
||||||
|
unsafe impl<T> Killable for JoinHandle<T> {
|
||||||
|
fn pthread_handle(&self) -> pthread_t {
|
||||||
|
// JoinHandleExt::as_pthread_t gives c_ulong, convert it to the
|
||||||
|
// type that the libc crate expects
|
||||||
|
assert_eq!(mem::size_of::<pthread_t>(), mem::size_of::<usize>());
|
||||||
|
self.as_pthread_t() as usize as pthread_t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use libc::SA_SIGINFO;
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
static mut SIGNAL_HANDLER_CALLED: bool = false;
|
||||||
|
|
||||||
|
extern "C" fn handle_signal(_: c_int, _: *mut siginfo_t, _: *mut c_void) {
|
||||||
|
unsafe {
|
||||||
|
SIGNAL_HANDLER_CALLED = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_register_signal_handler() {
|
||||||
|
unsafe {
|
||||||
|
// testing bad value
|
||||||
|
assert!(register_signal_handler(
|
||||||
|
SIGRTMAX(),
|
||||||
|
SignalHandler::Siginfo(handle_signal),
|
||||||
|
true,
|
||||||
|
SA_SIGINFO
|
||||||
|
)
|
||||||
|
.is_err());
|
||||||
|
format!(
|
||||||
|
"{:?}",
|
||||||
|
register_signal_handler(
|
||||||
|
SIGRTMAX(),
|
||||||
|
SignalHandler::Siginfo(handle_signal),
|
||||||
|
true,
|
||||||
|
SA_SIGINFO
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert!(register_signal_handler(
|
||||||
|
0,
|
||||||
|
SignalHandler::Siginfo(handle_signal),
|
||||||
|
true,
|
||||||
|
SA_SIGINFO
|
||||||
|
)
|
||||||
|
.is_ok());
|
||||||
|
assert!(register_signal_handler(
|
||||||
|
libc::SIGSYS,
|
||||||
|
SignalHandler::Siginfo(handle_signal),
|
||||||
|
false,
|
||||||
|
SA_SIGINFO
|
||||||
|
)
|
||||||
|
.is_ok());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[allow(clippy::empty_loop)]
|
||||||
|
fn test_killing_thread() {
|
||||||
|
let killable = thread::spawn(|| thread::current().id());
|
||||||
|
let killable_id = killable.join().unwrap();
|
||||||
|
assert_ne!(killable_id, thread::current().id());
|
||||||
|
|
||||||
|
// We install a signal handler for the specified signal; otherwise the whole process will
|
||||||
|
// be brought down when the signal is received, as part of the default behaviour. Signal
|
||||||
|
// handlers are global, so we install this before starting the thread.
|
||||||
|
unsafe {
|
||||||
|
register_signal_handler(0, SignalHandler::Siginfo(handle_signal), true, SA_SIGINFO)
|
||||||
|
.expect("failed to register vcpu signal handler");
|
||||||
|
}
|
||||||
|
|
||||||
|
let killable = thread::spawn(|| loop {});
|
||||||
|
|
||||||
|
let res = killable.kill(SIGRTMAX());
|
||||||
|
assert!(res.is_err());
|
||||||
|
format!("{:?}", res);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
assert!(!SIGNAL_HANDLER_CALLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(killable.kill(0).is_ok());
|
||||||
|
|
||||||
|
// We're waiting to detect that the signal handler has been called.
|
||||||
|
const MAX_WAIT_ITERS: u32 = 20;
|
||||||
|
let mut iter_count = 0;
|
||||||
|
loop {
|
||||||
|
thread::sleep(Duration::from_millis(100));
|
||||||
|
|
||||||
|
if unsafe { SIGNAL_HANDLER_CALLED } {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
iter_count += 1;
|
||||||
|
// timeout if we wait too long
|
||||||
|
assert!(iter_count <= MAX_WAIT_ITERS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Our signal handler doesn't do anything which influences the killable thread, so the
|
||||||
|
// previous signal is effectively ignored. If we were to join killable here, we would block
|
||||||
|
// forever as the loop keeps running. Since we don't join, the thread will become detached
|
||||||
|
// as the handle is dropped, and will be killed when the process/main thread exits.
|
||||||
|
}
|
||||||
|
}
|
643
vendor/git-643dc7ede01ca600/vmm-sys-util/src/syslog.rs
vendored
Normal file
643
vendor/git-643dc7ede01ca600/vmm-sys-util/src/syslog.rs
vendored
Normal file
@ -0,0 +1,643 @@
|
|||||||
|
// Copyright 2019 Intel Corporation. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
|
||||||
|
//! Facilities for sending log message to syslog.
|
||||||
|
//!
|
||||||
|
//! Every function exported by this module is thread-safe. Each function will silently fail until
|
||||||
|
//! `syslog::init()` is called and returns `Ok`.
|
||||||
|
//!
|
||||||
|
//! # Examples
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! #[macro_use]
|
||||||
|
//! extern crate vmm_sys_util;
|
||||||
|
//!
|
||||||
|
//! use vmm_sys_util::syslog::init;
|
||||||
|
//! fn main() {
|
||||||
|
//! if let Err(e) = init() {
|
||||||
|
//! println!("failed to initiailize syslog: {}", e);
|
||||||
|
//! return;
|
||||||
|
//! }
|
||||||
|
//! warn!("this is your {} warning", "final");
|
||||||
|
//! error!("something went horribly wrong: {}", "out of RAMs");
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
use std::ffi::CString;
|
||||||
|
use std::ffi::{OsStr, OsString};
|
||||||
|
use std::fmt::{self, Display};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io;
|
||||||
|
use std::io::{stderr, Cursor, ErrorKind, Write};
|
||||||
|
use std::mem;
|
||||||
|
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||||
|
use std::os::unix::net::UnixDatagram;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::ptr::null;
|
||||||
|
use std::str::from_utf8;
|
||||||
|
use std::sync::{Mutex as StdMutex, MutexGuard, Once, ONCE_INIT};
|
||||||
|
|
||||||
|
use libc::{
|
||||||
|
c_char, c_long, closelog, fcntl, gethostname, localtime_r, openlog, pid_t, syscall, time,
|
||||||
|
time_t, tm, F_GETFD, LOG_NDELAY, LOG_PERROR, LOG_PID, LOG_USER,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Temporary define linux-x86_64 syscall value here.
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
pub const SYS_getpid: c_long = 39;
|
||||||
|
|
||||||
|
const SYSLOG_PATH: &str = "/dev/log";
|
||||||
|
|
||||||
|
/// The priority (i.e. severity) of a syslog message.
|
||||||
|
///
|
||||||
|
/// See syslog man pages for information on their semantics.
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum Priority {
|
||||||
|
Emergency = 0,
|
||||||
|
Alert = 1,
|
||||||
|
Critical = 2,
|
||||||
|
Error = 3,
|
||||||
|
Warning = 4,
|
||||||
|
Notice = 5,
|
||||||
|
Info = 6,
|
||||||
|
Debug = 7,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Priority {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Priority::Emergency => write!(f, "EMERGENCY"),
|
||||||
|
Priority::Alert => write!(f, "ALERT"),
|
||||||
|
Priority::Critical => write!(f, "CRITICAL"),
|
||||||
|
Priority::Error => write!(f, "ERROR"),
|
||||||
|
Priority::Warning => write!(f, "WARNING"),
|
||||||
|
Priority::Notice => write!(f, "NOTICE"),
|
||||||
|
Priority::Info => write!(f, "INFO"),
|
||||||
|
Priority::Debug => write!(f, "DEBUG"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The facility of a syslog message.
|
||||||
|
///
|
||||||
|
/// See syslog man pages for information on their semantics.
|
||||||
|
pub enum Facility {
|
||||||
|
Kernel = 0,
|
||||||
|
User = 1 << 3,
|
||||||
|
Mail = 2 << 3,
|
||||||
|
Daemon = 3 << 3,
|
||||||
|
Auth = 4 << 3,
|
||||||
|
Syslog = 5 << 3,
|
||||||
|
Lpr = 6 << 3,
|
||||||
|
News = 7 << 3,
|
||||||
|
Uucp = 8 << 3,
|
||||||
|
Local0 = 16 << 3,
|
||||||
|
Local1 = 17 << 3,
|
||||||
|
Local2 = 18 << 3,
|
||||||
|
Local3 = 19 << 3,
|
||||||
|
Local4 = 20 << 3,
|
||||||
|
Local5 = 21 << 3,
|
||||||
|
Local6 = 22 << 3,
|
||||||
|
Local7 = 23 << 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Errors returned by `syslog::init()`.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// Initialization was never attempted.
|
||||||
|
NeverInitialized,
|
||||||
|
/// Initialization has previously failed and can not be retried.
|
||||||
|
Poisoned,
|
||||||
|
/// Error while creating socket.
|
||||||
|
Socket(io::Error),
|
||||||
|
/// Error while attempting to connect socket.
|
||||||
|
Connect(io::Error),
|
||||||
|
// There was an error using `open` to get the lowest file descriptor.
|
||||||
|
GetLowestFd(io::Error),
|
||||||
|
// The guess of libc's file descriptor for the syslog connection was invalid.
|
||||||
|
InvalidFd,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
use self::Error::*;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
NeverInitialized => write!(f, "initialization was never attempted"),
|
||||||
|
Poisoned => write!(f, "initialization previously failed and cannot be retried"),
|
||||||
|
Socket(e) => write!(f, "failed to create socket: {}", e),
|
||||||
|
Connect(e) => write!(f, "failed to connect socket: {}", e),
|
||||||
|
GetLowestFd(e) => write!(f, "failed to get lowest file descriptor: {}", e),
|
||||||
|
InvalidFd => write!(f, "guess of fd for syslog connection was invalid"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_hostname() -> Result<String, ()> {
|
||||||
|
let mut hostname: [u8; 256] = [b'\0'; 256];
|
||||||
|
// Safe because we give a valid pointer to a buffer of the indicated length and check for the
|
||||||
|
// result.
|
||||||
|
let ret = unsafe { gethostname(hostname.as_mut_ptr() as *mut c_char, hostname.len()) };
|
||||||
|
if ret == -1 {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let len = hostname.iter().position(|&v| v == b'\0').ok_or(())?;
|
||||||
|
|
||||||
|
Ok(from_utf8(&hostname[..len]).map_err(|_| ())?.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_proc_name() -> Option<String> {
|
||||||
|
env::args_os()
|
||||||
|
.next()
|
||||||
|
.map(PathBuf::from)
|
||||||
|
.and_then(|s| s.file_name().map(OsStr::to_os_string))
|
||||||
|
.map(OsString::into_string)
|
||||||
|
.and_then(Result::ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uses libc's openlog function to get a socket to the syslogger. By getting the socket this way, as
|
||||||
|
// opposed to connecting to the syslogger directly, libc's internal state gets initialized for other
|
||||||
|
// libraries (e.g. minijail) that make use of libc's syslog function. Note that this function
|
||||||
|
// depends on no other threads or signal handlers being active in this process because they might
|
||||||
|
// create FDs.
|
||||||
|
//
|
||||||
|
// TODO(zachr): Once https://android-review.googlesource.com/470998 lands, there won't be any
|
||||||
|
// libraries in use that hard depend on libc's syslogger. Remove this and go back to making the
|
||||||
|
// connection directly once minjail is ready.
|
||||||
|
fn openlog_and_get_socket() -> Result<UnixDatagram, Error> {
|
||||||
|
// closelog first in case there was already a file descriptor open. Safe because it takes no
|
||||||
|
// arguments and just closes an open file descriptor. Does nothing if the file descriptor
|
||||||
|
// was not already open.
|
||||||
|
unsafe {
|
||||||
|
closelog();
|
||||||
|
}
|
||||||
|
|
||||||
|
let file_path = CString::new("/dev/null").unwrap();
|
||||||
|
unsafe {
|
||||||
|
// Ordinarily libc's FD for the syslog connection can't be accessed, but we can guess that the
|
||||||
|
// FD that openlog will be getting is the lowest unused FD. To guarantee that an FD is opened in
|
||||||
|
// this function we use the LOG_NDELAY to tell openlog to connect to the syslog now. To get the
|
||||||
|
// lowest unused FD, we open a dummy file (which the manual says will always return the lowest
|
||||||
|
// fd), and then close that fd. Voilà, we now know the lowest numbered FD. The call to openlog
|
||||||
|
// will make use of that FD, and then we just wrap a `UnixDatagram` around it for ease of use.
|
||||||
|
let fd = libc::open(file_path.as_ptr(), libc::O_RDONLY);
|
||||||
|
if fd < 0 {
|
||||||
|
let err = io::Error::last_os_error();
|
||||||
|
return Err(Error::GetLowestFd(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safe because openlog accesses no pointers because `ident` is null, only valid flags are
|
||||||
|
// used, and it returns no error.
|
||||||
|
openlog(null(), LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_USER);
|
||||||
|
// For safety, ensure the fd we guessed is valid. The `fcntl` call itself only reads the
|
||||||
|
// file descriptor table of the current process, which is trivially safe.
|
||||||
|
if fcntl(fd, F_GETFD) >= 0 {
|
||||||
|
Ok(UnixDatagram::from_raw_fd(fd))
|
||||||
|
} else {
|
||||||
|
Err(Error::InvalidFd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct State {
|
||||||
|
stderr: bool,
|
||||||
|
socket: Option<UnixDatagram>,
|
||||||
|
file: Option<File>,
|
||||||
|
hostname: Option<String>,
|
||||||
|
proc_name: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
fn new() -> Result<State, Error> {
|
||||||
|
let s = openlog_and_get_socket()?;
|
||||||
|
Ok(State {
|
||||||
|
stderr: true,
|
||||||
|
socket: Some(s),
|
||||||
|
file: None,
|
||||||
|
hostname: get_hostname().ok(),
|
||||||
|
proc_name: get_proc_name(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static STATE_ONCE: Once = ONCE_INIT;
|
||||||
|
static mut STATE: *const StdMutex<State> = 0 as *const _;
|
||||||
|
|
||||||
|
fn new_mutex_ptr<T>(inner: T) -> *const StdMutex<T> {
|
||||||
|
Box::into_raw(Box::new(StdMutex::new(inner)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize the syslog connection and internal variables.
|
||||||
|
///
|
||||||
|
/// This should only be called once per process before any other threads have been spawned or any
|
||||||
|
/// signal handlers have been registered. Every call made after the first will have no effect
|
||||||
|
/// besides return `Ok` or `Err` appropriately.
|
||||||
|
pub fn init() -> Result<(), Error> {
|
||||||
|
let mut err = Error::Poisoned;
|
||||||
|
STATE_ONCE.call_once(|| match State::new() {
|
||||||
|
// Safe because STATE mutation is guarded by `Once`.
|
||||||
|
Ok(state) => unsafe { STATE = new_mutex_ptr(state) },
|
||||||
|
Err(e) => err = e,
|
||||||
|
});
|
||||||
|
|
||||||
|
if unsafe { STATE.is_null() } {
|
||||||
|
Err(err)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lock() -> Result<MutexGuard<'static, State>, Error> {
|
||||||
|
// Safe because we assume that STATE is always in either a valid or NULL state.
|
||||||
|
let state_ptr = unsafe { STATE };
|
||||||
|
if state_ptr.is_null() {
|
||||||
|
return Err(Error::NeverInitialized);
|
||||||
|
}
|
||||||
|
// Safe because STATE only mutates once and we checked for NULL.
|
||||||
|
let state = unsafe { &*state_ptr };
|
||||||
|
let guard = match state.lock() {
|
||||||
|
Ok(guard) => guard,
|
||||||
|
_ => panic!("mutex is poisoned"),
|
||||||
|
};
|
||||||
|
Ok(guard)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempts to lock and retrieve the state. Returns from the function silently on failure.
|
||||||
|
macro_rules! lock {
|
||||||
|
() => {
|
||||||
|
match lock() {
|
||||||
|
Ok(s) => s,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replaces the hostname reported in each syslog message.
|
||||||
|
///
|
||||||
|
/// The default hostname is whatever `gethostname()` returned when `vmm_sys_util::syslog::init()` was first
|
||||||
|
/// called.
|
||||||
|
///
|
||||||
|
/// Does nothing if syslog was never initialized.
|
||||||
|
pub fn set_hostname<T: Into<String>>(hostname: T) {
|
||||||
|
let mut state = lock!();
|
||||||
|
state.hostname = Some(hostname.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replaces the process name reported in each syslog message.
|
||||||
|
///
|
||||||
|
/// The default process name is the _file name_ of `argv[0]`. For example, if this program was
|
||||||
|
/// invoked as
|
||||||
|
///
|
||||||
|
/// ```bash
|
||||||
|
/// $ path/to/app --delete everything
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// the default process name would be _app_.
|
||||||
|
///
|
||||||
|
/// Does nothing if syslog was never initialized.
|
||||||
|
pub fn set_proc_name<T: Into<String>>(proc_name: T) {
|
||||||
|
let mut state = lock!();
|
||||||
|
state.proc_name = Some(proc_name.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enables or disables echoing log messages to the syslog.
|
||||||
|
///
|
||||||
|
/// The default behavior is **enabled**.
|
||||||
|
///
|
||||||
|
/// If `enable` goes from `true` to `false`, the syslog connection is closed. The connection is
|
||||||
|
/// reopened if `enable` is set to `true` after it became `false`.
|
||||||
|
///
|
||||||
|
/// Returns an error if syslog was never initialized or the syslog connection failed to be
|
||||||
|
/// established.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `enable` - `true` to enable echoing to syslog, `false` to disable echoing to syslog.
|
||||||
|
pub fn echo_syslog(enable: bool) -> Result<(), Error> {
|
||||||
|
let state_ptr = unsafe { STATE };
|
||||||
|
if state_ptr.is_null() {
|
||||||
|
return Err(Error::NeverInitialized);
|
||||||
|
}
|
||||||
|
let mut state = lock().map_err(|_| Error::Poisoned)?;
|
||||||
|
|
||||||
|
match state.socket.take() {
|
||||||
|
Some(_) if enable => {}
|
||||||
|
Some(s) => {
|
||||||
|
// Because `openlog_and_get_socket` actually just "borrows" the syslog FD, this module
|
||||||
|
// does not own the syslog connection and therefore should not destroy it.
|
||||||
|
mem::forget(s);
|
||||||
|
}
|
||||||
|
None if enable => {
|
||||||
|
let s = openlog_and_get_socket()?;
|
||||||
|
state.socket = Some(s);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replaces the optional `File` to echo log messages to.
|
||||||
|
///
|
||||||
|
/// The default behavior is to not echo to a file. Passing `None` to this function restores that
|
||||||
|
/// behavior.
|
||||||
|
///
|
||||||
|
/// Does nothing if syslog was never initialized.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `file` - `Some(file)` to echo to `file`, `None` to disable echoing to the file previously passed to `echo_file`.
|
||||||
|
pub fn echo_file(file: Option<File>) {
|
||||||
|
let mut state = lock!();
|
||||||
|
state.file = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enables or disables echoing log messages to the `std::io::stderr()`.
|
||||||
|
///
|
||||||
|
/// The default behavior is **enabled**.
|
||||||
|
///
|
||||||
|
/// Does nothing if syslog was never initialized.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `enable` - `true` to enable echoing to stderr, `false` to disable echoing to stderr.
|
||||||
|
pub fn echo_stderr(enable: bool) {
|
||||||
|
let mut state = lock!();
|
||||||
|
state.stderr = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves the file descriptors owned by the global syslogger.
|
||||||
|
///
|
||||||
|
/// Does nothing if syslog was never initialized. If their are any file descriptors, they will be
|
||||||
|
/// pushed into `fds`.
|
||||||
|
///
|
||||||
|
/// Note that the `stderr` file descriptor is never added, as it is not owned by syslog.
|
||||||
|
#[allow(clippy::redundant_closure)]
|
||||||
|
pub fn push_fds(fds: &mut Vec<RawFd>) {
|
||||||
|
let state = lock!();
|
||||||
|
fds.extend(state.socket.iter().map(|s| s.as_raw_fd()));
|
||||||
|
fds.extend(state.file.iter().map(|f| f.as_raw_fd()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Should only be called after `init()` was called.
|
||||||
|
fn send_buf(socket: &UnixDatagram, buf: &[u8]) {
|
||||||
|
const SEND_RETRY: usize = 2;
|
||||||
|
|
||||||
|
for _ in 0..SEND_RETRY {
|
||||||
|
match socket.send(&buf[..]) {
|
||||||
|
Ok(_) => break,
|
||||||
|
Err(e) => match e.kind() {
|
||||||
|
ErrorKind::ConnectionRefused
|
||||||
|
| ErrorKind::ConnectionReset
|
||||||
|
| ErrorKind::ConnectionAborted
|
||||||
|
| ErrorKind::NotConnected => {
|
||||||
|
let res = socket.connect(SYSLOG_PATH);
|
||||||
|
if res.is_err() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_localtime() -> tm {
|
||||||
|
unsafe {
|
||||||
|
// Safe because tm is just a struct of plain data.
|
||||||
|
let mut tm: tm = mem::zeroed();
|
||||||
|
let mut now: time_t = 0;
|
||||||
|
// Safe because we give time a valid pointer and can never fail.
|
||||||
|
time(&mut now as *mut _);
|
||||||
|
// Safe because we give localtime_r valid pointers and can never fail.
|
||||||
|
localtime_r(&now, &mut tm as *mut _);
|
||||||
|
tm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Records a log message with the given details.
|
||||||
|
///
|
||||||
|
/// Note that this will fail silently if syslog was not initialized.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `pri` - The `Priority` (i.e. severity) of the log message.
|
||||||
|
/// * `fac` - The `Facility` of the log message. Usually `Facility::User` should be used.
|
||||||
|
/// * `file_name` - Name of the file that generated the log.
|
||||||
|
/// * `line` - Line number within `file_name` that generated the log.
|
||||||
|
/// * `args` - The log's message to record, in the form of `format_args!()` return value
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use vmm_sys_util::syslog::{init, log, Priority, Facility};
|
||||||
|
/// # fn main() {
|
||||||
|
/// # if let Err(e) = init() {
|
||||||
|
/// # println!("failed to initiailize syslog: {}", e);
|
||||||
|
/// # return;
|
||||||
|
/// # }
|
||||||
|
/// log(Priority::Error,
|
||||||
|
/// Facility::User,
|
||||||
|
/// file!(),
|
||||||
|
/// line!(),
|
||||||
|
/// format_args!("hello syslog"));
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[allow(clippy::redundant_closure)]
|
||||||
|
pub fn log(pri: Priority, fac: Facility, file_name: &str, line: u32, args: fmt::Arguments) {
|
||||||
|
const MONTHS: [&str; 12] = [
|
||||||
|
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut state = lock!();
|
||||||
|
let mut buf = [0u8; 1024];
|
||||||
|
if let Some(ref socket) = state.socket {
|
||||||
|
let tm = get_localtime();
|
||||||
|
let prifac = (pri as u8) | (fac as u8);
|
||||||
|
let (res, len) = {
|
||||||
|
let mut buf_cursor = Cursor::new(&mut buf[..]);
|
||||||
|
(
|
||||||
|
write!(
|
||||||
|
&mut buf_cursor,
|
||||||
|
"<{}>{} {:02} {:02}:{:02}:{:02} {} {}[{}]: [{}:{}] {}",
|
||||||
|
prifac,
|
||||||
|
MONTHS[tm.tm_mon as usize],
|
||||||
|
tm.tm_mday,
|
||||||
|
tm.tm_hour,
|
||||||
|
tm.tm_min,
|
||||||
|
tm.tm_sec,
|
||||||
|
state.hostname.as_ref().map(|s| s.as_ref()).unwrap_or("-"),
|
||||||
|
state.proc_name.as_ref().map(|s| s.as_ref()).unwrap_or("-"),
|
||||||
|
unsafe { syscall(SYS_getpid as c_long) as pid_t },
|
||||||
|
//getpid(),
|
||||||
|
file_name,
|
||||||
|
line,
|
||||||
|
args
|
||||||
|
),
|
||||||
|
buf_cursor.position() as usize,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if res.is_ok() {
|
||||||
|
send_buf(&socket, &buf[..len]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let (res, len) = {
|
||||||
|
let mut buf_cursor = Cursor::new(&mut buf[..]);
|
||||||
|
(
|
||||||
|
writeln!(&mut buf_cursor, "[{}:{}:{}] {}", pri, file_name, line, args),
|
||||||
|
buf_cursor.position() as usize,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if res.is_ok() {
|
||||||
|
if let Some(ref mut file) = state.file {
|
||||||
|
let _ = file.write_all(&buf[..len]);
|
||||||
|
}
|
||||||
|
if state.stderr {
|
||||||
|
let _ = stderr().write_all(&buf[..len]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A macro for logging at an arbitrary priority level.
|
||||||
|
///
|
||||||
|
/// Note that this will fail silently if syslog was not initialized.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! log {
|
||||||
|
($pri:expr, $($args:tt)+) => ({
|
||||||
|
$crate::syslog::log($pri, $crate::syslog::Facility::User, file!(), line!(), format_args!($($args)+))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A macro for logging an error.
|
||||||
|
///
|
||||||
|
/// Note that this will fail silently if syslog was not initialized.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! error {
|
||||||
|
($($args:tt)+) => (log!($crate::syslog::Priority::Error, $($args)*))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A macro for logging a warning.
|
||||||
|
///
|
||||||
|
/// Note that this will fail silently if syslog was not initialized.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! warn {
|
||||||
|
($($args:tt)+) => (log!($crate::syslog::Priority::Warning, $($args)*))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A macro for logging info.
|
||||||
|
///
|
||||||
|
/// Note that this will fail silently if syslog was not initialized.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! info {
|
||||||
|
($($args:tt)+) => (log!($crate::syslog::Priority::Info, $($args)*))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A macro for logging debug information.
|
||||||
|
///
|
||||||
|
/// Note that this will fail silently if syslog was not initialized.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! debug {
|
||||||
|
($($args:tt)+) => (log!($crate::syslog::Priority::Debug, $($args)*))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use libc::{shm_open, shm_unlink, O_CREAT, O_EXCL, O_RDWR};
|
||||||
|
|
||||||
|
use std::ffi::CStr;
|
||||||
|
use std::io::{Read, Seek, SeekFrom};
|
||||||
|
use std::os::unix::io::FromRawFd;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_init_syslog() {
|
||||||
|
init().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fds() {
|
||||||
|
init().unwrap();
|
||||||
|
let mut fds = Vec::new();
|
||||||
|
push_fds(&mut fds);
|
||||||
|
assert!(!fds.is_empty());
|
||||||
|
for fd in fds {
|
||||||
|
assert!(fd >= 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_syslog_log() {
|
||||||
|
init().unwrap();
|
||||||
|
log(
|
||||||
|
Priority::Error,
|
||||||
|
Facility::User,
|
||||||
|
file!(),
|
||||||
|
line!(),
|
||||||
|
format_args!("hello syslog"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_proc_name() {
|
||||||
|
init().unwrap();
|
||||||
|
log(
|
||||||
|
Priority::Error,
|
||||||
|
Facility::User,
|
||||||
|
file!(),
|
||||||
|
line!(),
|
||||||
|
format_args!("before proc name"),
|
||||||
|
);
|
||||||
|
set_proc_name("sys_util-test");
|
||||||
|
log(
|
||||||
|
Priority::Error,
|
||||||
|
Facility::User,
|
||||||
|
file!(),
|
||||||
|
line!(),
|
||||||
|
format_args!("after proc name"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[allow(clippy::zero_prefixed_literal)]
|
||||||
|
fn test_syslog_file() {
|
||||||
|
init().unwrap();
|
||||||
|
let shm_name = CStr::from_bytes_with_nul(b"/crosvm_shm\0").unwrap();
|
||||||
|
let mut file = unsafe {
|
||||||
|
shm_unlink(shm_name.as_ptr());
|
||||||
|
let fd = shm_open(shm_name.as_ptr(), O_RDWR | O_CREAT | O_EXCL, 0666);
|
||||||
|
assert!(fd >= 0, "error creating shared memory;");
|
||||||
|
File::from_raw_fd(fd)
|
||||||
|
};
|
||||||
|
|
||||||
|
let syslog_file = file.try_clone().expect("error cloning shared memory file");
|
||||||
|
echo_file(Some(syslog_file));
|
||||||
|
|
||||||
|
const TEST_STR: &str = "hello shared memory file";
|
||||||
|
log(
|
||||||
|
Priority::Error,
|
||||||
|
Facility::User,
|
||||||
|
file!(),
|
||||||
|
line!(),
|
||||||
|
format_args!("{}", TEST_STR),
|
||||||
|
);
|
||||||
|
|
||||||
|
file.seek(SeekFrom::Start(0))
|
||||||
|
.expect("error seeking shared memory file");
|
||||||
|
let mut buf = String::new();
|
||||||
|
file.read_to_string(&mut buf)
|
||||||
|
.expect("error reading shared memory file");
|
||||||
|
assert!(buf.contains(TEST_STR));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_macros() {
|
||||||
|
init().unwrap();
|
||||||
|
error!("this is an error {}", 3);
|
||||||
|
warn!("this is a warning {}", "uh oh");
|
||||||
|
info!("this is info {}", true);
|
||||||
|
debug!("this is debug info {:?}", Some("helpful stuff"));
|
||||||
|
}
|
||||||
|
}
|
104
vendor/git-643dc7ede01ca600/vmm-sys-util/src/tempdir.rs
vendored
Normal file
104
vendor/git-643dc7ede01ca600/vmm-sys-util/src/tempdir.rs
vendored
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
use std::ffi::CString;
|
||||||
|
use std::ffi::OsStr;
|
||||||
|
use std::ffi::OsString;
|
||||||
|
use std::fs;
|
||||||
|
use std::os::unix::ffi::OsStringExt;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use libc;
|
||||||
|
|
||||||
|
use crate::{errno_result, Result};
|
||||||
|
|
||||||
|
/// Create and remove a temporary directory. The directory will be maintained for the lifetime of
|
||||||
|
/// the `TempDir` object.
|
||||||
|
pub struct TempDir {
|
||||||
|
path: Option<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TempDir {
|
||||||
|
/// Creates a new tempory directory.
|
||||||
|
/// The directory will be removed when the object goes out of scope.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use std::path::Path;
|
||||||
|
/// # use std::path::PathBuf;
|
||||||
|
/// # use vmm_sys_util::TempDir;
|
||||||
|
/// # fn test_create_temp_dir() -> Result<(), ()> {
|
||||||
|
/// let t = TempDir::new("/tmp/testdir").map_err(|_| ())?;
|
||||||
|
/// assert!(t.as_path().unwrap().exists());
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub fn new<P: AsRef<OsStr>>(prefix: P) -> Result<TempDir> {
|
||||||
|
let mut dir_string = prefix.as_ref().to_os_string();
|
||||||
|
dir_string.push("XXXXXX");
|
||||||
|
// unwrap this result as the internal bytes can't have a null with a valid path.
|
||||||
|
let dir_name = CString::new(dir_string.into_vec()).unwrap();
|
||||||
|
let mut dir_bytes = dir_name.into_bytes_with_nul();
|
||||||
|
let ret = unsafe {
|
||||||
|
// Creating the directory isn't unsafe. The fact that it modifies the guts of the path
|
||||||
|
// is also OK because it only overwrites the last 6 Xs added above.
|
||||||
|
libc::mkdtemp(dir_bytes.as_mut_ptr() as *mut libc::c_char)
|
||||||
|
};
|
||||||
|
if ret.is_null() {
|
||||||
|
return errno_result();
|
||||||
|
}
|
||||||
|
dir_bytes.pop(); // Remove the null becasue from_vec can't handle it.
|
||||||
|
Ok(TempDir {
|
||||||
|
path: Some(PathBuf::from(OsString::from_vec(dir_bytes))),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes the temporary directory. Calling this is optional as dropping a `TempDir` object
|
||||||
|
/// will also remove the directory. Calling remove explicitly allows for better error handling.
|
||||||
|
pub fn remove(mut self) -> Result<()> {
|
||||||
|
let path = self.path.take();
|
||||||
|
path.map_or(Ok(()), fs::remove_dir_all)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the path to the tempdir if it is currently valid
|
||||||
|
pub fn as_path(&self) -> Option<&Path> {
|
||||||
|
self.path.as_ref().map(|ref p| p.as_path())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TempDir {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let Some(ref p) = self.path {
|
||||||
|
// Nothing can be done here if this returns an error.
|
||||||
|
let _ = fs::remove_dir_all(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create_dir() {
|
||||||
|
let t = TempDir::new("/tmp/asdf").unwrap();
|
||||||
|
let path = t.as_path().unwrap();
|
||||||
|
assert!(path.exists());
|
||||||
|
assert!(path.is_dir());
|
||||||
|
assert!(path.starts_with("/tmp/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn remove_dir() {
|
||||||
|
let t = TempDir::new("/tmp/asdf").unwrap();
|
||||||
|
let path = t.as_path().unwrap().to_owned();
|
||||||
|
assert!(t.remove().is_ok());
|
||||||
|
assert!(!path.exists());
|
||||||
|
}
|
||||||
|
}
|
155
vendor/git-643dc7ede01ca600/vmm-sys-util/src/terminal.rs
vendored
Normal file
155
vendor/git-643dc7ede01ca600/vmm-sys-util/src/terminal.rs
vendored
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
// Copyright 2019 Intel Corporation. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
|
||||||
|
use std::io::StdinLock;
|
||||||
|
use std::mem::zeroed;
|
||||||
|
use std::os::unix::io::RawFd;
|
||||||
|
|
||||||
|
use libc::{
|
||||||
|
c_int, fcntl, isatty, read, tcgetattr, tcsetattr, termios, ECHO, F_GETFL, F_SETFL, ICANON,
|
||||||
|
ISIG, O_NONBLOCK, STDIN_FILENO, TCSANOW,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::errno::{errno_result, Result};
|
||||||
|
|
||||||
|
fn modify_mode<F: FnOnce(&mut termios)>(fd: RawFd, f: F) -> Result<()> {
|
||||||
|
// Safe because we check the return value of isatty.
|
||||||
|
if unsafe { isatty(fd) } != 1 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following pair are safe because termios gets totally overwritten by tcgetattr and we
|
||||||
|
// check the return result.
|
||||||
|
let mut termios: termios = unsafe { zeroed() };
|
||||||
|
let ret = unsafe { tcgetattr(fd, &mut termios as *mut _) };
|
||||||
|
if ret < 0 {
|
||||||
|
return errno_result();
|
||||||
|
}
|
||||||
|
let mut new_termios = termios;
|
||||||
|
f(&mut new_termios);
|
||||||
|
// Safe because the syscall will only read the extent of termios and we check the return result.
|
||||||
|
let ret = unsafe { tcsetattr(fd, TCSANOW, &new_termios as *const _) };
|
||||||
|
if ret < 0 {
|
||||||
|
return errno_result();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_flags(fd: RawFd) -> Result<c_int> {
|
||||||
|
// Safe because no third parameter is expected and we check the return result.
|
||||||
|
let ret = unsafe { fcntl(fd, F_GETFL) };
|
||||||
|
if ret < 0 {
|
||||||
|
return errno_result();
|
||||||
|
}
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_flags(fd: RawFd, flags: c_int) -> Result<()> {
|
||||||
|
// Safe because we supply the third parameter and we check the return result.
|
||||||
|
let ret = unsafe { fcntl(fd, F_SETFL, flags) };
|
||||||
|
if ret < 0 {
|
||||||
|
return errno_result();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait for file descriptors that are TTYs, according to `isatty(3)`.
|
||||||
|
///
|
||||||
|
/// This is marked unsafe because the implementation must promise that the returned RawFd is a valid
|
||||||
|
/// fd and that the lifetime of the returned fd is at least that of the trait object.
|
||||||
|
pub unsafe trait Terminal {
|
||||||
|
/// Gets the file descriptor of the TTY.
|
||||||
|
fn tty_fd(&self) -> RawFd;
|
||||||
|
|
||||||
|
/// Set this terminal's mode to canonical mode (`ICANON | ECHO | ISIG`).
|
||||||
|
fn set_canon_mode(&self) -> Result<()> {
|
||||||
|
modify_mode(self.tty_fd(), |t| t.c_lflag |= ICANON | ECHO | ISIG)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set this terminal's mode to raw mode (`!(ICANON | ECHO | ISIG)`).
|
||||||
|
fn set_raw_mode(&self) -> Result<()> {
|
||||||
|
modify_mode(self.tty_fd(), |t| t.c_lflag &= !(ICANON | ECHO | ISIG))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the non-blocking mode of this terminal's file descriptor.
|
||||||
|
///
|
||||||
|
/// If `non_block` is `true`, then `read_raw` will not block. If `non_block` is `false`, then
|
||||||
|
/// `read_raw` may block if there is nothing to read.
|
||||||
|
fn set_non_block(&self, non_block: bool) -> Result<()> {
|
||||||
|
let old_flags = get_flags(self.tty_fd())?;
|
||||||
|
let new_flags = if non_block {
|
||||||
|
old_flags | O_NONBLOCK
|
||||||
|
} else {
|
||||||
|
old_flags & !O_NONBLOCK
|
||||||
|
};
|
||||||
|
if new_flags != old_flags {
|
||||||
|
set_flags(self.tty_fd(), new_flags)?
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads up to `out.len()` bytes from this terminal without any buffering.
|
||||||
|
///
|
||||||
|
/// This may block, depending on if non-blocking was enabled with `set_non_block` or if there
|
||||||
|
/// are any bytes to read. If there is at least one byte that is readable, this will not block.
|
||||||
|
fn read_raw(&self, out: &mut [u8]) -> Result<usize> {
|
||||||
|
// Safe because read will only modify the pointer up to the length we give it and we check
|
||||||
|
// the return result.
|
||||||
|
let ret = unsafe { read(self.tty_fd(), out.as_mut_ptr() as *mut _, out.len()) };
|
||||||
|
if ret < 0 {
|
||||||
|
return errno_result();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ret as usize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safe because we return a genuine terminal fd that never changes and shares our lifetime.
|
||||||
|
unsafe impl<'a> Terminal for StdinLock<'a> {
|
||||||
|
fn tty_fd(&self) -> RawFd {
|
||||||
|
STDIN_FILENO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io;
|
||||||
|
use std::os::unix::io::AsRawFd;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
unsafe impl Terminal for File {
|
||||||
|
fn tty_fd(&self) -> RawFd {
|
||||||
|
self.as_raw_fd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_a_tty() {
|
||||||
|
let stdin_handle = io::stdin();
|
||||||
|
let stdin = stdin_handle.lock();
|
||||||
|
|
||||||
|
assert!(stdin.set_canon_mode().is_ok());
|
||||||
|
assert!(stdin.set_raw_mode().is_ok());
|
||||||
|
assert!(stdin.set_raw_mode().is_ok());
|
||||||
|
assert!(stdin.set_canon_mode().is_ok());
|
||||||
|
assert!(stdin.set_non_block(true).is_ok());
|
||||||
|
let mut out = [0u8; 0];
|
||||||
|
assert!(stdin.read_raw(&mut out[..]).is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_a_non_tty() {
|
||||||
|
let file = File::open(Path::new("/dev/zero")).unwrap();
|
||||||
|
assert!(file.set_canon_mode().is_ok());
|
||||||
|
}
|
||||||
|
}
|
173
vendor/git-643dc7ede01ca600/vmm-sys-util/src/timerfd.rs
vendored
Normal file
173
vendor/git-643dc7ede01ca600/vmm-sys-util/src/timerfd.rs
vendored
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
// Copyright 2019 Intel Corporation. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE-BSD-3-clause file.
|
||||||
|
|
||||||
|
use std::fs::File;
|
||||||
|
use std::mem;
|
||||||
|
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
||||||
|
use std::ptr;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use libc::{self, timerfd_create, timerfd_gettime, timerfd_settime, CLOCK_MONOTONIC, TFD_CLOEXEC};
|
||||||
|
|
||||||
|
use crate::errno::{errno_result, Result};
|
||||||
|
|
||||||
|
/// A safe wrapper around a Linux timerfd (man 2 timerfd_create).
|
||||||
|
pub struct TimerFd(File);
|
||||||
|
|
||||||
|
impl TimerFd {
|
||||||
|
/// Creates a new [`TimerFd`](struct.TimerFd.html).
|
||||||
|
///
|
||||||
|
/// The timer is initally disarmed and must be armed by calling [`reset`](fn.reset.html).
|
||||||
|
pub fn new() -> Result<TimerFd> {
|
||||||
|
// Safe because this doesn't modify any memory and we check the return value.
|
||||||
|
let ret = unsafe { timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC) };
|
||||||
|
if ret < 0 {
|
||||||
|
return errno_result();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safe because we uniquely own the file descriptor.
|
||||||
|
Ok(TimerFd(unsafe { File::from_raw_fd(ret) }))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the timer to expire after `dur`.
|
||||||
|
///
|
||||||
|
/// If `interval` is not `None` it represents the period for repeated expirations after the
|
||||||
|
/// initial expiration. Otherwise the timer will expire just once. Cancels any existing duration and repeating interval.
|
||||||
|
pub fn reset(&mut self, dur: Duration, interval: Option<Duration>) -> Result<()> {
|
||||||
|
// Safe because we are zero-initializing a struct with only primitive member fields.
|
||||||
|
let mut spec: libc::itimerspec = unsafe { mem::zeroed() };
|
||||||
|
spec.it_value.tv_sec = dur.as_secs() as libc::time_t;
|
||||||
|
// nsec always fits in i32 because subsec_nanos is defined to be less than one billion.
|
||||||
|
let nsec = dur.subsec_nanos() as i32;
|
||||||
|
spec.it_value.tv_nsec = libc::c_long::from(nsec);
|
||||||
|
|
||||||
|
if let Some(int) = interval {
|
||||||
|
spec.it_interval.tv_sec = int.as_secs() as libc::time_t;
|
||||||
|
// nsec always fits in i32 because subsec_nanos is defined to be less than one billion.
|
||||||
|
let nsec = int.subsec_nanos() as i32;
|
||||||
|
spec.it_interval.tv_nsec = libc::c_long::from(nsec);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safe because this doesn't modify any memory and we check the return value.
|
||||||
|
let ret = unsafe { timerfd_settime(self.as_raw_fd(), 0, &spec, ptr::null_mut()) };
|
||||||
|
if ret < 0 {
|
||||||
|
return errno_result();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Waits until the timer expires.
|
||||||
|
///
|
||||||
|
/// The return value represents the number of times the timer
|
||||||
|
/// has expired since the last time `wait` was called. If the timer has not yet expired once
|
||||||
|
/// this call will block until it does.
|
||||||
|
pub fn wait(&mut self) -> Result<u64> {
|
||||||
|
let mut count = 0u64;
|
||||||
|
|
||||||
|
// Safe because this will only modify |buf| and we check the return value.
|
||||||
|
let ret = unsafe {
|
||||||
|
libc::read(
|
||||||
|
self.as_raw_fd(),
|
||||||
|
&mut count as *mut _ as *mut libc::c_void,
|
||||||
|
mem::size_of_val(&count),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if ret < 0 {
|
||||||
|
return errno_result();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The bytes in the buffer are guaranteed to be in native byte-order so we don't need to
|
||||||
|
// use from_le or from_be.
|
||||||
|
Ok(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the timer is currently armed.
|
||||||
|
pub fn is_armed(&self) -> Result<bool> {
|
||||||
|
// Safe because we are zero-initializing a struct with only primitive member fields.
|
||||||
|
let mut spec: libc::itimerspec = unsafe { mem::zeroed() };
|
||||||
|
|
||||||
|
// Safe because timerfd_gettime is trusted to only modify `spec`.
|
||||||
|
let ret = unsafe { timerfd_gettime(self.as_raw_fd(), &mut spec) };
|
||||||
|
if ret < 0 {
|
||||||
|
return errno_result();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(spec.it_value.tv_sec != 0 || spec.it_value.tv_nsec != 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Disarms the timer.
|
||||||
|
pub fn clear(&mut self) -> Result<()> {
|
||||||
|
// Safe because we are zero-initializing a struct with only primitive member fields.
|
||||||
|
let spec: libc::itimerspec = unsafe { mem::zeroed() };
|
||||||
|
|
||||||
|
// Safe because this doesn't modify any memory and we check the return value.
|
||||||
|
let ret = unsafe { timerfd_settime(self.as_raw_fd(), 0, &spec, ptr::null_mut()) };
|
||||||
|
if ret < 0 {
|
||||||
|
return errno_result();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRawFd for TimerFd {
|
||||||
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
|
self.0.as_raw_fd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromRawFd for TimerFd {
|
||||||
|
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||||
|
TimerFd(File::from_raw_fd(fd))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoRawFd for TimerFd {
|
||||||
|
fn into_raw_fd(self) -> RawFd {
|
||||||
|
self.0.into_raw_fd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::thread::sleep;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_one_shot() {
|
||||||
|
let mut tfd = TimerFd::new().expect("failed to create timerfd");
|
||||||
|
assert_eq!(tfd.is_armed().unwrap(), false);
|
||||||
|
|
||||||
|
let dur = Duration::from_millis(200);
|
||||||
|
let now = Instant::now();
|
||||||
|
tfd.reset(dur, None).expect("failed to arm timer");
|
||||||
|
|
||||||
|
assert_eq!(tfd.is_armed().unwrap(), true);
|
||||||
|
|
||||||
|
let count = tfd.wait().expect("unable to wait for timer");
|
||||||
|
|
||||||
|
assert_eq!(count, 1);
|
||||||
|
assert!(now.elapsed() >= dur);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_repeating() {
|
||||||
|
let mut tfd = TimerFd::new().expect("failed to create timerfd");
|
||||||
|
|
||||||
|
let dur = Duration::from_millis(200);
|
||||||
|
let interval = Duration::from_millis(100);
|
||||||
|
tfd.reset(dur, Some(interval)).expect("failed to arm timer");
|
||||||
|
|
||||||
|
sleep(dur * 3);
|
||||||
|
|
||||||
|
let count = tfd.wait().expect("unable to wait for timer");
|
||||||
|
assert!(count >= 5, "count = {}", count);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
172
vendor/git-643dc7ede01ca600/vmm-sys-util/src/write_zeroes.rs
vendored
Normal file
172
vendor/git-643dc7ede01ca600/vmm-sys-util/src/write_zeroes.rs
vendored
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
use std::cmp::min;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{self, Seek, SeekFrom, Write};
|
||||||
|
|
||||||
|
use crate::fallocate;
|
||||||
|
use crate::FallocateMode;
|
||||||
|
|
||||||
|
/// A trait for deallocating space in a file.
|
||||||
|
pub trait PunchHole {
|
||||||
|
/// Replace a range of bytes with a hole.
|
||||||
|
fn punch_hole(&mut self, offset: u64, length: u64) -> io::Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PunchHole for File {
|
||||||
|
fn punch_hole(&mut self, offset: u64, length: u64) -> io::Result<()> {
|
||||||
|
fallocate(self, FallocateMode::PunchHole, true, offset, length as u64)
|
||||||
|
.map_err(|e| io::Error::from_raw_os_error(e.errno()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A trait for writing zeroes to a stream.
|
||||||
|
pub trait WriteZeroes {
|
||||||
|
/// Write `length` bytes of zeroes to the stream, returning how many bytes were written.
|
||||||
|
fn write_zeroes(&mut self, length: usize) -> io::Result<usize>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PunchHole + Seek + Write> WriteZeroes for T {
|
||||||
|
fn write_zeroes(&mut self, length: usize) -> io::Result<usize> {
|
||||||
|
// Try to punch a hole first.
|
||||||
|
let offset = self.seek(SeekFrom::Current(0))?;
|
||||||
|
if let Ok(()) = self.punch_hole(offset, length as u64) {
|
||||||
|
// Advance the seek cursor as if we had done a real write().
|
||||||
|
self.seek(SeekFrom::Current(length as i64))?;
|
||||||
|
return Ok(length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fall back to write()
|
||||||
|
|
||||||
|
// punch_hole() failed; fall back to writing a buffer of zeroes
|
||||||
|
// until we have written up to length.
|
||||||
|
let buf_size = min(length, 0x10000);
|
||||||
|
let buf = vec![0u8; buf_size];
|
||||||
|
let mut nwritten: usize = 0;
|
||||||
|
while nwritten < length {
|
||||||
|
let remaining = length - nwritten;
|
||||||
|
let write_size = min(remaining, buf_size);
|
||||||
|
nwritten += self.write(&buf[0..write_size])?;
|
||||||
|
}
|
||||||
|
Ok(length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[allow(clippy::unused_io_amount)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::fs::OpenOptions;
|
||||||
|
use std::io::{Read, Seek, SeekFrom};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use crate::TempDir;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simple_test() {
|
||||||
|
let tempdir = TempDir::new("/tmp/write_zeroes_test").unwrap();
|
||||||
|
let mut path = PathBuf::from(tempdir.as_path().unwrap());
|
||||||
|
path.push("file");
|
||||||
|
let mut f = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.open(&path)
|
||||||
|
.unwrap();
|
||||||
|
f.set_len(16384).unwrap();
|
||||||
|
|
||||||
|
// Write buffer of non-zero bytes to offset 1234
|
||||||
|
let orig_data = [0x55u8; 5678];
|
||||||
|
f.seek(SeekFrom::Start(1234)).unwrap();
|
||||||
|
f.write(&orig_data).unwrap();
|
||||||
|
|
||||||
|
// Read back the data plus some overlap on each side
|
||||||
|
let mut readback = [0u8; 16384];
|
||||||
|
f.seek(SeekFrom::Start(0)).unwrap();
|
||||||
|
f.read(&mut readback).unwrap();
|
||||||
|
// Bytes before the write should still be 0
|
||||||
|
for read in readback[0..1234].iter() {
|
||||||
|
assert_eq!(*read, 0);
|
||||||
|
}
|
||||||
|
// Bytes that were just written should be 0x55
|
||||||
|
for read in readback[1234..(1234 + 5678)].iter() {
|
||||||
|
assert_eq!(*read, 0x55);
|
||||||
|
}
|
||||||
|
// Bytes after the written area should still be 0
|
||||||
|
for read in readback[(1234 + 5678)..].iter() {
|
||||||
|
assert_eq!(*read, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overwrite some of the data with zeroes
|
||||||
|
f.seek(SeekFrom::Start(2345)).unwrap();
|
||||||
|
f.write_zeroes(4321).expect("write_zeroes failed");
|
||||||
|
// Verify seek position after write_zeroes()
|
||||||
|
assert_eq!(f.seek(SeekFrom::Current(0)).unwrap(), 2345 + 4321);
|
||||||
|
|
||||||
|
// Read back the data and verify that it is now zero
|
||||||
|
f.seek(SeekFrom::Start(0)).unwrap();
|
||||||
|
f.read(&mut readback).unwrap();
|
||||||
|
// Bytes before the write should still be 0
|
||||||
|
for read in readback[0..1234].iter() {
|
||||||
|
assert_eq!(*read, 0);
|
||||||
|
}
|
||||||
|
// Original data should still exist before the write_zeroes region
|
||||||
|
for read in readback[1234..2345].iter() {
|
||||||
|
assert_eq!(*read, 0x55);
|
||||||
|
}
|
||||||
|
// The write_zeroes region should now be zero
|
||||||
|
for read in readback[2345..(2345 + 4321)].iter() {
|
||||||
|
assert_eq!(*read, 0);
|
||||||
|
}
|
||||||
|
// Original data should still exist after the write_zeroes region
|
||||||
|
for read in readback[(2345 + 4321)..(1234 + 5678)].iter() {
|
||||||
|
assert_eq!(*read, 0x55);
|
||||||
|
}
|
||||||
|
// The rest of the file should still be 0
|
||||||
|
for read in readback[(1234 + 5678)..].iter() {
|
||||||
|
assert_eq!(*read, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn large_write_zeroes() {
|
||||||
|
let tempdir = TempDir::new("/tmp/write_zeroes_test").unwrap();
|
||||||
|
let mut path = PathBuf::from(tempdir.as_path().unwrap());
|
||||||
|
path.push("file");
|
||||||
|
let mut f = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.open(&path)
|
||||||
|
.unwrap();
|
||||||
|
f.set_len(16384).unwrap();
|
||||||
|
|
||||||
|
// Write buffer of non-zero bytes
|
||||||
|
let orig_data = [0x55u8; 0x20000];
|
||||||
|
f.seek(SeekFrom::Start(0)).unwrap();
|
||||||
|
f.write(&orig_data).unwrap();
|
||||||
|
|
||||||
|
// Overwrite some of the data with zeroes
|
||||||
|
f.seek(SeekFrom::Start(0)).unwrap();
|
||||||
|
f.write_zeroes(0x10001).expect("write_zeroes failed");
|
||||||
|
// Verify seek position after write_zeroes()
|
||||||
|
assert_eq!(f.seek(SeekFrom::Current(0)).unwrap(), 0x10001);
|
||||||
|
|
||||||
|
// Read back the data and verify that it is now zero
|
||||||
|
let mut readback = [0u8; 0x20000];
|
||||||
|
f.seek(SeekFrom::Start(0)).unwrap();
|
||||||
|
f.read(&mut readback).unwrap();
|
||||||
|
// The write_zeroes region should now be zero
|
||||||
|
for read in readback[0..0x10001].iter() {
|
||||||
|
assert_eq!(*read, 0);
|
||||||
|
}
|
||||||
|
// Original data should still exist after the write_zeroes region
|
||||||
|
for read in readback[0x10001..0x20000].iter() {
|
||||||
|
assert_eq!(*read, 0x55);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
wget http://mirror.centos.org/centos/7/os/x86_64/Packages/kernel-3.10.0-957.el7.x86_64.rpm
|
wget http://ftp.debian.org/debian/pool/main/l/linux/linux-image-4.9.0-9-amd64_4.9.168-1_amd64.deb -P $BUILDKITE_BUILD_CHECKOUT_PATH/linux-loader/src/loader
|
||||||
rpm2cpio kernel-3.10.0-957.el7.x86_64.rpm | cpio -idmv ./boot/vmlinuz-3.10.0-957.el7.x86_64
|
dpkg-deb -x $BUILDKITE_BUILD_CHECKOUT_PATH/linux-loader/src/loader/linux-image-4.9.0-9-amd64_4.9.168-1_amd64.deb
|
||||||
|
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
{"files":{".buildkite/hooks/post-checkout":"4433e2001686837e6bd1a6baef67daacd07434817a04fcb7df8332ee16c51740",".buildkite/pipeline.yml":"8d0550f4a793c4b056189e0612afc50d6d8a686535ee81262318ae33d72611e3",".gitignore/.gitignore":"6b937008e0a58a438c32574627db6961a4d2aff4bf5c703d4e45cb56ef3b168a","Cargo.toml":"f2754a32f2dacc0f8695ee9780193badc85995954ed452d0df4ca1ef8517d089","DESIGN.md":"d877f3093cf94402528a54a97e833fc79d4cbc07934031035f60a2d8d0a542d4","LICENSE-APACHE":"000b4962e6b27176a0ff89cce4be555b16472cafb5671eb2804a8fdac6854793","LICENSE-BSD-3-Clause":"a6d3ebd1c2f37d4fd83d0676621f695fc0cc2d8c6e646cdbb831b46e0650c208","README.md":"3e585f0ceb915bf4734075d2f0a91b626ff2363079baebcf7592a8d51d2c7931","src/cmdline/mod.rs":"30f57b492618155be6129311d0182688e5d1ecd9a3b5fdc9b742cd0c0e1f85da","src/lib.rs":"67d3e4a9ed48495c00fe6698fc606693b15a006fb0599cb18b946ea3929cd0f6","src/loader/bootparam.rs":"054b5a196873965cb48b9e9fa99c2505f523f9c71ca8ca0fad3af02491811fe6","src/loader/elf.rs":"f4e4eb6ffcb114bbf3242a9c72ea7e99631487d63bbbfbcf641bea42b3aba2e1","src/loader/mod.rs":"6bc6b4f5e90cbf15f554c3c0e4752226794053fc4c0781a7a7828124de1b1ec7","src/loader/struct_util.rs":"a98c2854ebd3a0c0ed11e01e474f2da15fb9200754129223710d62cc88ab253a","src/loader/test_elf.bin":"dda390f7546c7ba36bab412a93add96533806154824b77aafc8c153231f3f161","tests/conftest.py":"ee2baacd9da7ac04ffbfd580a7d4fe8a8b166a16e1eeed2d488f7b820abab433","tests/coverage":"69eaa47e0089d5a3e2844fe7ca823b67ff712e382f6c34b0300797a415b7f3e9","tests/test_coverage.py":"2f4bbb571bf52ad796f9f47a3aaace61ee92ab9788980496bb1652826f224150"},"package":null}
|
{"files":{".buildkite/hooks/post-checkout":"44e0e9b8a3776276b79ffd5bdab3495f1dfe1e0c2ee1fff884347bf3ce2cb8e8",".buildkite/pipeline.yml":"8d0550f4a793c4b056189e0612afc50d6d8a686535ee81262318ae33d72611e3",".gitignore/.gitignore":"6b937008e0a58a438c32574627db6961a4d2aff4bf5c703d4e45cb56ef3b168a","Cargo.toml":"0dcfd317a1849d1f80f210151ccb25dcf2a3ecb8238f519125c5fb8f4c510aba","DESIGN.md":"d877f3093cf94402528a54a97e833fc79d4cbc07934031035f60a2d8d0a542d4","LICENSE-APACHE":"000b4962e6b27176a0ff89cce4be555b16472cafb5671eb2804a8fdac6854793","LICENSE-BSD-3-Clause":"a6d3ebd1c2f37d4fd83d0676621f695fc0cc2d8c6e646cdbb831b46e0650c208","README.md":"3e585f0ceb915bf4734075d2f0a91b626ff2363079baebcf7592a8d51d2c7931","src/cmdline/mod.rs":"30f57b492618155be6129311d0182688e5d1ecd9a3b5fdc9b742cd0c0e1f85da","src/lib.rs":"67d3e4a9ed48495c00fe6698fc606693b15a006fb0599cb18b946ea3929cd0f6","src/loader/bootparam.rs":"054b5a196873965cb48b9e9fa99c2505f523f9c71ca8ca0fad3af02491811fe6","src/loader/elf.rs":"f4e4eb6ffcb114bbf3242a9c72ea7e99631487d63bbbfbcf641bea42b3aba2e1","src/loader/mod.rs":"c360a84b46f34dbafa71bfe8c6f9295925ab02c397abf368fe725a3bbbae4698","src/loader/struct_util.rs":"a98c2854ebd3a0c0ed11e01e474f2da15fb9200754129223710d62cc88ab253a","src/loader/test_elf.bin":"dda390f7546c7ba36bab412a93add96533806154824b77aafc8c153231f3f161","tests/conftest.py":"ee2baacd9da7ac04ffbfd580a7d4fe8a8b166a16e1eeed2d488f7b820abab433","tests/coverage":"69eaa47e0089d5a3e2844fe7ca823b67ff712e382f6c34b0300797a415b7f3e9","tests/test_coverage.py":"2f4bbb571bf52ad796f9f47a3aaace61ee92ab9788980496bb1652826f224150"},"package":null}
|
@ -6,7 +6,7 @@ edition = "2018"
|
|||||||
license = "Apache-2.0 AND BSD-3-Clause"
|
license = "Apache-2.0 AND BSD-3-Clause"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["elf"]
|
default = []
|
||||||
elf = []
|
elf = []
|
||||||
bzImage = []
|
bzImage = []
|
||||||
|
|
||||||
|
@ -182,7 +182,6 @@ impl KernelLoader for Elf {
|
|||||||
return Err(Error::InvalidProgramHeaderSize);
|
return Err(Error::InvalidProgramHeaderSize);
|
||||||
}
|
}
|
||||||
if (ehdr.e_phoff as usize) < mem::size_of::<elf::Elf64_Ehdr>() {
|
if (ehdr.e_phoff as usize) < mem::size_of::<elf::Elf64_Ehdr>() {
|
||||||
|
|
||||||
return Err(Error::InvalidProgramHeaderOffset);
|
return Err(Error::InvalidProgramHeaderOffset);
|
||||||
}
|
}
|
||||||
if (highmem_start_address.is_some())
|
if (highmem_start_address.is_some())
|
||||||
@ -383,7 +382,7 @@ mod test {
|
|||||||
#[cfg(feature = "bzImage")]
|
#[cfg(feature = "bzImage")]
|
||||||
fn make_bzImage() -> Vec<u8> {
|
fn make_bzImage() -> Vec<u8> {
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
v.extend_from_slice(include_bytes!("../../.buildkite/hooks/boot/vmlinuz-3.10.0-957.el7.x86_64"));
|
v.extend_from_slice(include_bytes!("./boot/vmlinuz-4.9.0-9-amd64"));
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -556,6 +555,7 @@ mod test {
|
|||||||
assert_eq!(val, '\0' as u8);
|
assert_eq!(val, '\0' as u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "elf")]
|
||||||
#[test]
|
#[test]
|
||||||
fn bad_magic() {
|
fn bad_magic() {
|
||||||
let gm = create_guest_mem();
|
let gm = create_guest_mem();
|
||||||
@ -568,6 +568,7 @@ mod test {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "elf")]
|
||||||
#[test]
|
#[test]
|
||||||
fn bad_endian() {
|
fn bad_endian() {
|
||||||
// Only little endian is supported
|
// Only little endian is supported
|
||||||
@ -581,6 +582,7 @@ mod test {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "elf")]
|
||||||
#[test]
|
#[test]
|
||||||
fn bad_phoff() {
|
fn bad_phoff() {
|
||||||
// program header has to be past the end of the elf header
|
// program header has to be past the end of the elf header
|
||||||
|
@ -1 +1 @@
|
|||||||
{"files":{"CHANGELOG.md":"b9f503da2d3c91b0a244f1dc853d975f971f782b209ea52cd4cd98705e6e2749","CODE_OF_CONDUCT.md":"42634d0f6d922f49857175af991802822f7f920487aefa2ee250a50d12251a66","Cargo.toml":"0234b6f827764ca093d897126b45505be0996e67860d61caeab696d092ffb781","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"6b236f8b62c82f189fabce0756e01a2c0ab1f32cb84cad9ff3c96b2ce5282bda","src/example_generated.rs":"e43eb59e90f317f38d436670a6067d2fd9eb35fb319fe716184e4a04e24ed1b2","src/lib.rs":"5751eb6fbb8cb97d8accd0846493168d9b5acff1f8d64435d4da8ad7dbf36b4d"},"package":"228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"}
|
{"files":{"CHANGELOG.md":"bdd5d8b41c8ef74d9529713650a1b17c5c412d44721d089c9462300d0d6fa404","CODE_OF_CONDUCT.md":"28d69bb291d5f0ba31e2bf1649e1ff08914d4dbf9363a48a61e667fe0136d2ae","Cargo.toml":"d689950710ad4e574b03ab2a5ccf459476dfcf77b2520bd53873f1185aa834e7","LICENSE-APACHE":"7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c","LICENSE-MIT":"705aaaaecefa087c187bd2eacdb01b8ac1c5ee95b1d5d04d8d7efe0363207df8","README.md":"223ca98599ea77f79293813a67116271676b2a4a7fd6879ef4ea2b7ca90ff587","build.rs":"35a5c69b27bba9b3b5fcf62ab8e37dc47565198d2ae594e34aaf0583e3beeafb","src/example_generated.rs":"4345138fd410405ce5a5c6ba1d256205541aaa7cdfd6f23413dfce432d4efd0c","src/lib.rs":"263a6308b66f9e51d3ef92a20ac6829ed14c8807a27f39a68f8c87379c73c051"},"package":"3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"}
|
@ -1,108 +1,134 @@
|
|||||||
# 1.0.3
|
# 1.1.0
|
||||||
|
|
||||||
- Improve zero value flag handling and documentation ([#157])
|
This is a re-release of `1.0.5`, which was yanked due to a bug in the RLS.
|
||||||
|
|
||||||
[#157]: https://github.com/rust-lang-nursery/bitflags/pull/157
|
# 1.0.5
|
||||||
|
|
||||||
# 1.0.2
|
- Use compiletest_rs flags supported by stable toolchain ([#171])
|
||||||
|
|
||||||
- 30% improvement in compile time of bitflags crate ([#156])
|
- Put the user provided attributes first ([#173])
|
||||||
|
|
||||||
- Documentation improvements ([#153])
|
- Make bitflags methods `const` on newer compilers ([#175])
|
||||||
|
|
||||||
- Implementation cleanup ([#149])
|
[#171]: https://github.com/rust-lang-nursery/bitflags/pull/171
|
||||||
|
[#173]: https://github.com/rust-lang-nursery/bitflags/pull/173
|
||||||
[#156]: https://github.com/rust-lang-nursery/bitflags/pull/156
|
[#175]: https://github.com/rust-lang-nursery/bitflags/pull/175
|
||||||
[#153]: https://github.com/rust-lang-nursery/bitflags/pull/153
|
|
||||||
[#149]: https://github.com/rust-lang-nursery/bitflags/pull/149
|
# 1.0.4
|
||||||
|
|
||||||
# 1.0.1
|
- Support Rust 2018 style macro imports ([#165])
|
||||||
- Add support for `pub(restricted)` specifier on the bitflags struct ([#135])
|
|
||||||
- Optimize performance of `all()` when called from a separate crate ([#136])
|
```rust
|
||||||
|
use bitflags::bitflags;
|
||||||
[#135]: https://github.com/rust-lang-nursery/bitflags/pull/135
|
```
|
||||||
[#136]: https://github.com/rust-lang-nursery/bitflags/pull/136
|
|
||||||
|
[#165]: https://github.com/rust-lang-nursery/bitflags/pull/165
|
||||||
# 1.0.0
|
|
||||||
- **[breaking change]** Macro now generates [associated constants](https://doc.rust-lang.org/reference/items.html#associated-constants) ([#24])
|
# 1.0.3
|
||||||
|
|
||||||
- **[breaking change]** Minimum supported version is Rust **1.20**, due to usage of associated constants
|
- Improve zero value flag handling and documentation ([#157])
|
||||||
|
|
||||||
- After being broken in 0.9, the `#[deprecated]` attribute is now supported again ([#112])
|
[#157]: https://github.com/rust-lang-nursery/bitflags/pull/157
|
||||||
|
|
||||||
- Other improvements to unit tests and documentation ([#106] and [#115])
|
# 1.0.2
|
||||||
|
|
||||||
[#24]: https://github.com/rust-lang-nursery/bitflags/pull/24
|
- 30% improvement in compile time of bitflags crate ([#156])
|
||||||
[#106]: https://github.com/rust-lang-nursery/bitflags/pull/106
|
|
||||||
[#112]: https://github.com/rust-lang-nursery/bitflags/pull/112
|
- Documentation improvements ([#153])
|
||||||
[#115]: https://github.com/rust-lang-nursery/bitflags/pull/115
|
|
||||||
|
- Implementation cleanup ([#149])
|
||||||
## How to update your code to use associated constants
|
|
||||||
Assuming the following structure definition:
|
[#156]: https://github.com/rust-lang-nursery/bitflags/pull/156
|
||||||
```rust
|
[#153]: https://github.com/rust-lang-nursery/bitflags/pull/153
|
||||||
bitflags! {
|
[#149]: https://github.com/rust-lang-nursery/bitflags/pull/149
|
||||||
struct Something: u8 {
|
|
||||||
const FOO = 0b01,
|
# 1.0.1
|
||||||
const BAR = 0b10
|
- Add support for `pub(restricted)` specifier on the bitflags struct ([#135])
|
||||||
}
|
- Optimize performance of `all()` when called from a separate crate ([#136])
|
||||||
}
|
|
||||||
```
|
[#135]: https://github.com/rust-lang-nursery/bitflags/pull/135
|
||||||
In 0.9 and older you could do:
|
[#136]: https://github.com/rust-lang-nursery/bitflags/pull/136
|
||||||
```rust
|
|
||||||
let x = FOO.bits | BAR.bits;
|
# 1.0.0
|
||||||
```
|
- **[breaking change]** Macro now generates [associated constants](https://doc.rust-lang.org/reference/items.html#associated-constants) ([#24])
|
||||||
Now you must use:
|
|
||||||
```rust
|
- **[breaking change]** Minimum supported version is Rust **1.20**, due to usage of associated constants
|
||||||
let x = Something::FOO.bits | Something::BAR.bits;
|
|
||||||
```
|
- After being broken in 0.9, the `#[deprecated]` attribute is now supported again ([#112])
|
||||||
|
|
||||||
# 0.9.1
|
- Other improvements to unit tests and documentation ([#106] and [#115])
|
||||||
- Fix the implementation of `Formatting` traits when other formatting traits were present in scope ([#105])
|
|
||||||
|
[#24]: https://github.com/rust-lang-nursery/bitflags/pull/24
|
||||||
[#105]: https://github.com/rust-lang-nursery/bitflags/pull/105
|
[#106]: https://github.com/rust-lang-nursery/bitflags/pull/106
|
||||||
|
[#112]: https://github.com/rust-lang-nursery/bitflags/pull/112
|
||||||
# 0.9.0
|
[#115]: https://github.com/rust-lang-nursery/bitflags/pull/115
|
||||||
- **[breaking change]** Use struct keyword instead of flags to define bitflag types ([#84])
|
|
||||||
|
## How to update your code to use associated constants
|
||||||
- **[breaking change]** Terminate const items with semicolons instead of commas ([#87])
|
Assuming the following structure definition:
|
||||||
|
```rust
|
||||||
- Implement the `Hex`, `Octal`, and `Binary` formatting traits ([#86])
|
bitflags! {
|
||||||
|
struct Something: u8 {
|
||||||
- Printing an empty flag value with the `Debug` trait now prints "(empty)" instead of nothing ([#85])
|
const FOO = 0b01,
|
||||||
|
const BAR = 0b10
|
||||||
- The `bitflags!` macro can now be used inside of a fn body, to define a type local to that function ([#74])
|
}
|
||||||
|
}
|
||||||
[#74]: https://github.com/rust-lang-nursery/bitflags/pull/74
|
```
|
||||||
[#84]: https://github.com/rust-lang-nursery/bitflags/pull/84
|
In 0.9 and older you could do:
|
||||||
[#85]: https://github.com/rust-lang-nursery/bitflags/pull/85
|
```rust
|
||||||
[#86]: https://github.com/rust-lang-nursery/bitflags/pull/86
|
let x = FOO.bits | BAR.bits;
|
||||||
[#87]: https://github.com/rust-lang-nursery/bitflags/pull/87
|
```
|
||||||
|
Now you must use:
|
||||||
# 0.8.2
|
```rust
|
||||||
- Update feature flag used when building bitflags as a dependency of the Rust toolchain
|
let x = Something::FOO.bits | Something::BAR.bits;
|
||||||
|
```
|
||||||
# 0.8.1
|
|
||||||
- Allow bitflags to be used as a dependency of the Rust toolchain
|
# 0.9.1
|
||||||
|
- Fix the implementation of `Formatting` traits when other formatting traits were present in scope ([#105])
|
||||||
# 0.8.0
|
|
||||||
- Add support for the experimental `i128` and `u128` integer types ([#57])
|
[#105]: https://github.com/rust-lang-nursery/bitflags/pull/105
|
||||||
- Add set method: `flags.set(SOME_FLAG, true)` or `flags.set(SOME_FLAG, false)` ([#55])
|
|
||||||
This may break code that defines its own set method
|
# 0.9.0
|
||||||
|
- **[breaking change]** Use struct keyword instead of flags to define bitflag types ([#84])
|
||||||
[#55]: https://github.com/rust-lang-nursery/bitflags/pull/55
|
|
||||||
[#57]: https://github.com/rust-lang-nursery/bitflags/pull/57
|
- **[breaking change]** Terminate const items with semicolons instead of commas ([#87])
|
||||||
|
|
||||||
# 0.7.1
|
- Implement the `Hex`, `Octal`, and `Binary` formatting traits ([#86])
|
||||||
*(yanked)*
|
|
||||||
|
- Printing an empty flag value with the `Debug` trait now prints "(empty)" instead of nothing ([#85])
|
||||||
# 0.7.0
|
|
||||||
- Implement the Extend trait ([#49])
|
- The `bitflags!` macro can now be used inside of a fn body, to define a type local to that function ([#74])
|
||||||
- Allow definitions inside the `bitflags!` macro to refer to items imported from other modules ([#51])
|
|
||||||
|
[#74]: https://github.com/rust-lang-nursery/bitflags/pull/74
|
||||||
[#49]: https://github.com/rust-lang-nursery/bitflags/pull/49
|
[#84]: https://github.com/rust-lang-nursery/bitflags/pull/84
|
||||||
[#51]: https://github.com/rust-lang-nursery/bitflags/pull/51
|
[#85]: https://github.com/rust-lang-nursery/bitflags/pull/85
|
||||||
|
[#86]: https://github.com/rust-lang-nursery/bitflags/pull/86
|
||||||
# 0.6.0
|
[#87]: https://github.com/rust-lang-nursery/bitflags/pull/87
|
||||||
- The `no_std` feature was removed as it is now the default
|
|
||||||
- The `assignment_operators` feature was remove as it is now enabled by default
|
# 0.8.2
|
||||||
- Some clippy suggestions have been applied
|
- Update feature flag used when building bitflags as a dependency of the Rust toolchain
|
||||||
|
|
||||||
|
# 0.8.1
|
||||||
|
- Allow bitflags to be used as a dependency of the Rust toolchain
|
||||||
|
|
||||||
|
# 0.8.0
|
||||||
|
- Add support for the experimental `i128` and `u128` integer types ([#57])
|
||||||
|
- Add set method: `flags.set(SOME_FLAG, true)` or `flags.set(SOME_FLAG, false)` ([#55])
|
||||||
|
This may break code that defines its own set method
|
||||||
|
|
||||||
|
[#55]: https://github.com/rust-lang-nursery/bitflags/pull/55
|
||||||
|
[#57]: https://github.com/rust-lang-nursery/bitflags/pull/57
|
||||||
|
|
||||||
|
# 0.7.1
|
||||||
|
*(yanked)*
|
||||||
|
|
||||||
|
# 0.7.0
|
||||||
|
- Implement the Extend trait ([#49])
|
||||||
|
- Allow definitions inside the `bitflags!` macro to refer to items imported from other modules ([#51])
|
||||||
|
|
||||||
|
[#49]: https://github.com/rust-lang-nursery/bitflags/pull/49
|
||||||
|
[#51]: https://github.com/rust-lang-nursery/bitflags/pull/51
|
||||||
|
|
||||||
|
# 0.6.0
|
||||||
|
- The `no_std` feature was removed as it is now the default
|
||||||
|
- The `assignment_operators` feature was remove as it is now enabled by default
|
||||||
|
- Some clippy suggestions have been applied
|
||||||
|
@ -1,73 +1,73 @@
|
|||||||
# Contributor Covenant Code of Conduct
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
## Our Pledge
|
## Our Pledge
|
||||||
|
|
||||||
In the interest of fostering an open and welcoming environment, we as
|
In the interest of fostering an open and welcoming environment, we as
|
||||||
contributors and maintainers pledge to making participation in our project and
|
contributors and maintainers pledge to making participation in our project and
|
||||||
our community a harassment-free experience for everyone, regardless of age, body
|
our community a harassment-free experience for everyone, regardless of age, body
|
||||||
size, disability, ethnicity, gender identity and expression, level of experience,
|
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||||
education, socio-economic status, nationality, personal appearance, race,
|
education, socio-economic status, nationality, personal appearance, race,
|
||||||
religion, or sexual identity and orientation.
|
religion, or sexual identity and orientation.
|
||||||
|
|
||||||
## Our Standards
|
## Our Standards
|
||||||
|
|
||||||
Examples of behavior that contributes to creating a positive environment
|
Examples of behavior that contributes to creating a positive environment
|
||||||
include:
|
include:
|
||||||
|
|
||||||
* Using welcoming and inclusive language
|
* Using welcoming and inclusive language
|
||||||
* Being respectful of differing viewpoints and experiences
|
* Being respectful of differing viewpoints and experiences
|
||||||
* Gracefully accepting constructive criticism
|
* Gracefully accepting constructive criticism
|
||||||
* Focusing on what is best for the community
|
* Focusing on what is best for the community
|
||||||
* Showing empathy towards other community members
|
* Showing empathy towards other community members
|
||||||
|
|
||||||
Examples of unacceptable behavior by participants include:
|
Examples of unacceptable behavior by participants include:
|
||||||
|
|
||||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||||
advances
|
advances
|
||||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||||
* Public or private harassment
|
* Public or private harassment
|
||||||
* Publishing others' private information, such as a physical or electronic
|
* Publishing others' private information, such as a physical or electronic
|
||||||
address, without explicit permission
|
address, without explicit permission
|
||||||
* Other conduct which could reasonably be considered inappropriate in a
|
* Other conduct which could reasonably be considered inappropriate in a
|
||||||
professional setting
|
professional setting
|
||||||
|
|
||||||
## Our Responsibilities
|
## Our Responsibilities
|
||||||
|
|
||||||
Project maintainers are responsible for clarifying the standards of acceptable
|
Project maintainers are responsible for clarifying the standards of acceptable
|
||||||
behavior and are expected to take appropriate and fair corrective action in
|
behavior and are expected to take appropriate and fair corrective action in
|
||||||
response to any instances of unacceptable behavior.
|
response to any instances of unacceptable behavior.
|
||||||
|
|
||||||
Project maintainers have the right and responsibility to remove, edit, or
|
Project maintainers have the right and responsibility to remove, edit, or
|
||||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||||
permanently any contributor for other behaviors that they deem inappropriate,
|
permanently any contributor for other behaviors that they deem inappropriate,
|
||||||
threatening, offensive, or harmful.
|
threatening, offensive, or harmful.
|
||||||
|
|
||||||
## Scope
|
## Scope
|
||||||
|
|
||||||
This Code of Conduct applies both within project spaces and in public spaces
|
This Code of Conduct applies both within project spaces and in public spaces
|
||||||
when an individual is representing the project or its community. Examples of
|
when an individual is representing the project or its community. Examples of
|
||||||
representing a project or community include using an official project e-mail
|
representing a project or community include using an official project e-mail
|
||||||
address, posting via an official social media account, or acting as an appointed
|
address, posting via an official social media account, or acting as an appointed
|
||||||
representative at an online or offline event. Representation of a project may be
|
representative at an online or offline event. Representation of a project may be
|
||||||
further defined and clarified by project maintainers.
|
further defined and clarified by project maintainers.
|
||||||
|
|
||||||
## Enforcement
|
## Enforcement
|
||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
reported by contacting the project team at coc@senaite.org. All
|
reported by contacting the project team at coc@senaite.org. All
|
||||||
complaints will be reviewed and investigated and will result in a response that
|
complaints will be reviewed and investigated and will result in a response that
|
||||||
is deemed necessary and appropriate to the circumstances. The project team is
|
is deemed necessary and appropriate to the circumstances. The project team is
|
||||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||||
Further details of specific enforcement policies may be posted separately.
|
Further details of specific enforcement policies may be posted separately.
|
||||||
|
|
||||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||||
faith may face temporary or permanent repercussions as determined by other
|
faith may face temporary or permanent repercussions as determined by other
|
||||||
members of the project's leadership.
|
members of the project's leadership.
|
||||||
|
|
||||||
## Attribution
|
## Attribution
|
||||||
|
|
||||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||||
|
|
||||||
[homepage]: https://www.contributor-covenant.org
|
[homepage]: https://www.contributor-covenant.org
|
@ -3,7 +3,7 @@
|
|||||||
# When uploading crates to the registry Cargo will automatically
|
# When uploading crates to the registry Cargo will automatically
|
||||||
# "normalize" Cargo.toml files for maximal compatibility
|
# "normalize" Cargo.toml files for maximal compatibility
|
||||||
# with all versions of Cargo and also rewrite `path` dependencies
|
# with all versions of Cargo and also rewrite `path` dependencies
|
||||||
# to registry (e.g. crates.io) dependencies
|
# to registry (e.g., crates.io) dependencies
|
||||||
#
|
#
|
||||||
# If you believe there's an error in this file please file an
|
# If you believe there's an error in this file please file an
|
||||||
# issue against the rust-lang/cargo repository. If you're
|
# issue against the rust-lang/cargo repository. If you're
|
||||||
@ -12,8 +12,9 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.0.4"
|
version = "1.1.0"
|
||||||
authors = ["The Rust Project Developers"]
|
authors = ["The Rust Project Developers"]
|
||||||
|
build = "build.rs"
|
||||||
exclude = [".travis.yml", "appveyor.yml", "bors.toml"]
|
exclude = [".travis.yml", "appveyor.yml", "bors.toml"]
|
||||||
description = "A macro to generate structures which behave like bitflags.\n"
|
description = "A macro to generate structures which behave like bitflags.\n"
|
||||||
homepage = "https://github.com/bitflags/bitflags"
|
homepage = "https://github.com/bitflags/bitflags"
|
||||||
|
@ -1,201 +1,201 @@
|
|||||||
Apache License
|
Apache License
|
||||||
Version 2.0, January 2004
|
Version 2.0, January 2004
|
||||||
http://www.apache.org/licenses/
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
1. Definitions.
|
1. Definitions.
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
the copyright owner that is granting the License.
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
other entities that control, are controlled by, or are under common
|
other entities that control, are controlled by, or are under common
|
||||||
control with that entity. For the purposes of this definition,
|
control with that entity. For the purposes of this definition,
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
direction or management of such entity, whether by contract or
|
direction or management of such entity, whether by contract or
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
exercising permissions granted by this License.
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
including but not limited to software source code, documentation
|
including but not limited to software source code, documentation
|
||||||
source, and configuration files.
|
source, and configuration files.
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
"Object" form shall mean any form resulting from mechanical
|
||||||
transformation or translation of a Source form, including but
|
transformation or translation of a Source form, including but
|
||||||
not limited to compiled object code, generated documentation,
|
not limited to compiled object code, generated documentation,
|
||||||
and conversions to other media types.
|
and conversions to other media types.
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
Object form, made available under the License, as indicated by a
|
Object form, made available under the License, as indicated by a
|
||||||
copyright notice that is included in or attached to the work
|
copyright notice that is included in or attached to the work
|
||||||
(an example is provided in the Appendix below).
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
form, that is based on (or derived from) the Work and for which the
|
form, that is based on (or derived from) the Work and for which the
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
of this License, Derivative Works shall not include works that remain
|
of this License, Derivative Works shall not include works that remain
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
the Work and Derivative Works thereof.
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
"Contribution" shall mean any work of authorship, including
|
||||||
the original version of the Work and any modifications or additions
|
the original version of the Work and any modifications or additions
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
means any form of electronic, verbal, or written communication sent
|
means any form of electronic, verbal, or written communication sent
|
||||||
to the Licensor or its representatives, including but not limited to
|
to the Licensor or its representatives, including but not limited to
|
||||||
communication on electronic mailing lists, source code control systems,
|
communication on electronic mailing lists, source code control systems,
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
excluding communication that is conspicuously marked or otherwise
|
excluding communication that is conspicuously marked or otherwise
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
subsequently incorporated within the Work.
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
Work and such Derivative Works in Source or Object form.
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
(except as stated in this section) patent license to make, have made,
|
(except as stated in this section) patent license to make, have made,
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
where such license applies only to those patent claims licensable
|
where such license applies only to those patent claims licensable
|
||||||
by such Contributor that are necessarily infringed by their
|
by such Contributor that are necessarily infringed by their
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
institute patent litigation against any entity (including a
|
institute patent litigation against any entity (including a
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
or contributory patent infringement, then any patent licenses
|
or contributory patent infringement, then any patent licenses
|
||||||
granted to You under this License for that Work shall terminate
|
granted to You under this License for that Work shall terminate
|
||||||
as of the date such litigation is filed.
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
modifications, and in Source or Object form, provided that You
|
modifications, and in Source or Object form, provided that You
|
||||||
meet the following conditions:
|
meet the following conditions:
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
(a) You must give any other recipients of the Work or
|
||||||
Derivative Works a copy of this License; and
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
(b) You must cause any modified files to carry prominent notices
|
||||||
stating that You changed the files; and
|
stating that You changed the files; and
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
that You distribute, all copyright, patent, trademark, and
|
that You distribute, all copyright, patent, trademark, and
|
||||||
attribution notices from the Source form of the Work,
|
attribution notices from the Source form of the Work,
|
||||||
excluding those notices that do not pertain to any part of
|
excluding those notices that do not pertain to any part of
|
||||||
the Derivative Works; and
|
the Derivative Works; and
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
distribution, then any Derivative Works that You distribute must
|
distribution, then any Derivative Works that You distribute must
|
||||||
include a readable copy of the attribution notices contained
|
include a readable copy of the attribution notices contained
|
||||||
within such NOTICE file, excluding those notices that do not
|
within such NOTICE file, excluding those notices that do not
|
||||||
pertain to any part of the Derivative Works, in at least one
|
pertain to any part of the Derivative Works, in at least one
|
||||||
of the following places: within a NOTICE text file distributed
|
of the following places: within a NOTICE text file distributed
|
||||||
as part of the Derivative Works; within the Source form or
|
as part of the Derivative Works; within the Source form or
|
||||||
documentation, if provided along with the Derivative Works; or,
|
documentation, if provided along with the Derivative Works; or,
|
||||||
within a display generated by the Derivative Works, if and
|
within a display generated by the Derivative Works, if and
|
||||||
wherever such third-party notices normally appear. The contents
|
wherever such third-party notices normally appear. The contents
|
||||||
of the NOTICE file are for informational purposes only and
|
of the NOTICE file are for informational purposes only and
|
||||||
do not modify the License. You may add Your own attribution
|
do not modify the License. You may add Your own attribution
|
||||||
notices within Derivative Works that You distribute, alongside
|
notices within Derivative Works that You distribute, alongside
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
that such additional attribution notices cannot be construed
|
that such additional attribution notices cannot be construed
|
||||||
as modifying the License.
|
as modifying the License.
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
You may add Your own copyright statement to Your modifications and
|
||||||
may provide additional or different license terms and conditions
|
may provide additional or different license terms and conditions
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
the conditions stated in this License.
|
the conditions stated in this License.
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
this License, without any additional terms or conditions.
|
this License, without any additional terms or conditions.
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
the terms of any separate license agreement you may have executed
|
the terms of any separate license agreement you may have executed
|
||||||
with Licensor regarding such Contributions.
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
except as required for reasonable and customary use in describing the
|
except as required for reasonable and customary use in describing the
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
implied, including, without limitation, any warranties or conditions
|
implied, including, without limitation, any warranties or conditions
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
appropriateness of using or redistributing the Work and assume any
|
appropriateness of using or redistributing the Work and assume any
|
||||||
risks associated with Your exercise of permissions under this License.
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
unless required by applicable law (such as deliberate and grossly
|
unless required by applicable law (such as deliberate and grossly
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
liable to You for damages, including any direct, indirect, special,
|
liable to You for damages, including any direct, indirect, special,
|
||||||
incidental, or consequential damages of any character arising as a
|
incidental, or consequential damages of any character arising as a
|
||||||
result of this License or out of the use or inability to use the
|
result of this License or out of the use or inability to use the
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
other commercial damages or losses), even if such Contributor
|
other commercial damages or losses), even if such Contributor
|
||||||
has been advised of the possibility of such damages.
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
or other liability obligations and/or rights consistent with this
|
or other liability obligations and/or rights consistent with this
|
||||||
License. However, in accepting such obligations, You may act only
|
License. However, in accepting such obligations, You may act only
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
defend, and hold each Contributor harmless for any liability
|
defend, and hold each Contributor harmless for any liability
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
of your accepting any such warranty or additional liability.
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
To apply the Apache License to your work, attach the following
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
replaced with your own identifying information. (Don't include
|
replaced with your own identifying information. (Don't include
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
comment syntax for the file format. We also recommend that a
|
comment syntax for the file format. We also recommend that a
|
||||||
file or class name and description of purpose be included on the
|
file or class name and description of purpose be included on the
|
||||||
same "printed page" as the copyright notice for easier
|
same "printed page" as the copyright notice for easier
|
||||||
identification within third-party archives.
|
identification within third-party archives.
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
You may obtain a copy of the License at
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
Unless required by applicable law or agreed to in writing, software
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
Copyright (c) 2014 The Rust Project Developers
|
Copyright (c) 2014 The Rust Project Developers
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any
|
Permission is hereby granted, free of charge, to any
|
||||||
person obtaining a copy of this software and associated
|
person obtaining a copy of this software and associated
|
||||||
documentation files (the "Software"), to deal in the
|
documentation files (the "Software"), to deal in the
|
||||||
Software without restriction, including without
|
Software without restriction, including without
|
||||||
limitation the rights to use, copy, modify, merge,
|
limitation the rights to use, copy, modify, merge,
|
||||||
publish, distribute, sublicense, and/or sell copies of
|
publish, distribute, sublicense, and/or sell copies of
|
||||||
the Software, and to permit persons to whom the Software
|
the Software, and to permit persons to whom the Software
|
||||||
is furnished to do so, subject to the following
|
is furnished to do so, subject to the following
|
||||||
conditions:
|
conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice
|
The above copyright notice and this permission notice
|
||||||
shall be included in all copies or substantial portions
|
shall be included in all copies or substantial portions
|
||||||
of the Software.
|
of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
DEALINGS IN THE SOFTWARE.
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
@ -1,34 +1,34 @@
|
|||||||
bitflags
|
bitflags
|
||||||
========
|
========
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.com/bitflags/bitflags.svg?branch=master)](https://travis-ci.com/bitflags/bitflags)
|
[![Build Status](https://travis-ci.com/bitflags/bitflags.svg?branch=master)](https://travis-ci.com/bitflags/bitflags)
|
||||||
[![Join the chat at https://gitter.im/bitflags/Lobby](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/bitflags/Lobby?utm_source=badge&utm_medium=badge&utm_content=badge)
|
[![Join the chat at https://gitter.im/bitflags/Lobby](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/bitflags/Lobby?utm_source=badge&utm_medium=badge&utm_content=badge)
|
||||||
[![Latest version](https://img.shields.io/crates/v/bitflags.svg)](https://crates.io/crates/bitflags)
|
[![Latest version](https://img.shields.io/crates/v/bitflags.svg)](https://crates.io/crates/bitflags)
|
||||||
[![Documentation](https://docs.rs/bitflags/badge.svg)](https://docs.rs/bitflags)
|
[![Documentation](https://docs.rs/bitflags/badge.svg)](https://docs.rs/bitflags)
|
||||||
![Minimum rustc version](https://img.shields.io/badge/rustc-1.20+-yellow.svg)
|
![Minimum rustc version](https://img.shields.io/badge/rustc-1.20+-yellow.svg)
|
||||||
![License](https://img.shields.io/crates/l/bitflags.svg)
|
![License](https://img.shields.io/crates/l/bitflags.svg)
|
||||||
|
|
||||||
A Rust macro to generate structures which behave like a set of bitflags
|
A Rust macro to generate structures which behave like a set of bitflags
|
||||||
|
|
||||||
- [Documentation](https://docs.rs/bitflags)
|
- [Documentation](https://docs.rs/bitflags)
|
||||||
- [Release notes](https://github.com/bitflags/bitflags/releases)
|
- [Release notes](https://github.com/bitflags/bitflags/releases)
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Add this to your `Cargo.toml`:
|
Add this to your `Cargo.toml`:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bitflags = "1.0"
|
bitflags = "1.0"
|
||||||
```
|
```
|
||||||
|
|
||||||
and this to your crate root:
|
and this to your crate root:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate bitflags;
|
extern crate bitflags;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Rust Version Support
|
## Rust Version Support
|
||||||
|
|
||||||
The minimum supported Rust version is 1.20 due to use of associated constants.
|
The minimum supported Rust version is 1.20 due to use of associated constants.
|
||||||
|
44
vendor/registry-40351f815f426200/bitflags/build.rs
vendored
Normal file
44
vendor/registry-40351f815f426200/bitflags/build.rs
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
use std::env;
|
||||||
|
use std::process::Command;
|
||||||
|
use std::str::{self, FromStr};
|
||||||
|
|
||||||
|
fn main(){
|
||||||
|
let minor = match rustc_minor_version() {
|
||||||
|
Some(minor) => minor,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
// const fn stabilized in Rust 1.31:
|
||||||
|
if minor >= 31 {
|
||||||
|
println!("cargo:rustc-cfg=bitflags_const_fn");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rustc_minor_version() -> Option<u32> {
|
||||||
|
let rustc = match env::var_os("RUSTC") {
|
||||||
|
Some(rustc) => rustc,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let output = match Command::new(rustc).arg("--version").output() {
|
||||||
|
Ok(output) => output,
|
||||||
|
Err(_) => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let version = match str::from_utf8(&output.stdout) {
|
||||||
|
Ok(version) => version,
|
||||||
|
Err(_) => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut pieces = version.split('.');
|
||||||
|
if pieces.next() != Some("rustc 1") {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let next = match pieces.next() {
|
||||||
|
Some(next) => next,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
u32::from_str(next).ok()
|
||||||
|
}
|
@ -1,14 +1,14 @@
|
|||||||
//! This module shows an example of code generated by the macro. **IT MUST NOT BE USED OUTSIDE THIS
|
//! This module shows an example of code generated by the macro. **IT MUST NOT BE USED OUTSIDE THIS
|
||||||
//! CRATE**.
|
//! CRATE**.
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
/// This is the same `Flags` struct defined in the [crate level example](../index.html#example).
|
/// This is the same `Flags` struct defined in the [crate level example](../index.html#example).
|
||||||
/// Note that this struct is just for documentation purposes only, it must not be used outside
|
/// Note that this struct is just for documentation purposes only, it must not be used outside
|
||||||
/// this crate.
|
/// this crate.
|
||||||
pub struct Flags: u32 {
|
pub struct Flags: u32 {
|
||||||
const A = 0b00000001;
|
const A = 0b00000001;
|
||||||
const B = 0b00000010;
|
const B = 0b00000010;
|
||||||
const C = 0b00000100;
|
const C = 0b00000100;
|
||||||
const ABC = Self::A.bits | Self::B.bits | Self::C.bits;
|
const ABC = Self::A.bits | Self::B.bits | Self::C.bits;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2582
vendor/registry-40351f815f426200/bitflags/src/lib.rs
vendored
2582
vendor/registry-40351f815f426200/bitflags/src/lib.rs
vendored
File diff suppressed because it is too large
Load Diff
@ -15,11 +15,14 @@ log = "*"
|
|||||||
net_util = { path = "../net_util" }
|
net_util = { path = "../net_util" }
|
||||||
pci = {path = "../pci"}
|
pci = {path = "../pci"}
|
||||||
qcow = { path = "../qcow" }
|
qcow = { path = "../qcow" }
|
||||||
linux-loader = { git = "https://github.com/bjzhjing/linux-loader" }
|
|
||||||
vm-virtio = { path = "../vm-virtio" }
|
vm-virtio = { path = "../vm-virtio" }
|
||||||
vm-allocator = { path = "../vm-allocator" }
|
vm-allocator = { path = "../vm-allocator" }
|
||||||
vmm-sys-util = { git = "https://github.com/rust-vmm/vmm-sys-util" }
|
vmm-sys-util = { git = "https://github.com/rust-vmm/vmm-sys-util" }
|
||||||
|
|
||||||
|
[dependencies.linux-loader]
|
||||||
|
git = "https://github.com/bjzhjing/linux-loader"
|
||||||
|
features = ["elf"]
|
||||||
|
|
||||||
[dependencies.vm-memory]
|
[dependencies.vm-memory]
|
||||||
git = "https://github.com/rust-vmm/vm-memory"
|
git = "https://github.com/rust-vmm/vm-memory"
|
||||||
features = ["backend-mmap"]
|
features = ["backend-mmap"]
|
||||||
|
Loading…
Reference in New Issue
Block a user