diff --git a/Cargo.lock b/Cargo.lock index 294fc2566..a407c1567 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,7 +43,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -86,7 +86,7 @@ name = "cloudabi" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] @@ -105,7 +105,7 @@ name = "epoll" version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" 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)", ] @@ -136,7 +136,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "linux-loader" version = "0.1.0" -source = "git+https://github.com/bjzhjing/linux-loader#55c985a16d63dceccbd30952f0e93a73b25a8191" +source = "git+https://github.com/bjzhjing/linux-loader#9fa483ce4a7d6a1250be82fa551060ecdbdec4aa" dependencies = [ "vm-memory 0.1.0 (git+https://github.com/rust-vmm/vm-memory)", ] @@ -439,7 +439,7 @@ dependencies = [ [[package]] name = "vm-memory" 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 = [ "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -495,7 +495,7 @@ dependencies = [ [[package]] name = "vmm-sys-util" 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 = [ "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 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 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 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" diff --git a/vendor/git-3e7c44ea7d5fd800/vm-memory/.buildkite/pipeline.linux.yml b/vendor/git-3e7c44ea7d5fd800/vm-memory/.buildkite/pipeline.linux.yml index f39aa1a54..e19a6ab5b 100644 --- a/vendor/git-3e7c44ea7d5fd800/vm-memory/.buildkite/pipeline.linux.yml +++ b/vendor/git-3e7c44ea7d5fd800/vm-memory/.buildkite/pipeline.linux.yml @@ -9,7 +9,7 @@ steps: os: linux plugins: - docker#v3.0.1: - image: "fandree/rust-vmm-dev" + image: "rustvmm/dev:v2" always-pull: true - label: "build-gnu-x86-mmap" @@ -22,7 +22,7 @@ steps: os: linux plugins: - docker#v3.0.1: - image: "fandree/rust-vmm-dev" + image: "rustvmm/dev:v2" always-pull: true - label: "build-gnu-arm-mmap" @@ -35,7 +35,7 @@ steps: os: linux plugins: - docker#v3.0.1: - image: "fandree/rust-vmm-dev" + image: "rustvmm/dev:v2" always-pull: true - label: "build-musl-arm-mmap" @@ -48,7 +48,7 @@ steps: os: linux plugins: - docker#v3.0.1: - image: "fandree/rust-vmm-dev" + image: "rustvmm/dev:v2" always-pull: true - label: "style" @@ -60,7 +60,7 @@ steps: os: linux plugins: - docker#v3.0.1: - image: "fandree/rust-vmm-dev" + image: "rustvmm/dev:v2" always-pull: true - label: "unittests-gnu-x86" @@ -73,7 +73,7 @@ steps: os: linux plugins: - docker#v3.0.1: - image: "fandree/rust-vmm-dev" + image: "rustvmm/dev:v2" always-pull: true - label: "unittests-musl-x86" @@ -86,7 +86,7 @@ steps: os: linux plugins: - docker#v3.0.1: - image: "fandree/rust-vmm-dev" + image: "rustvmm/dev:v2" always-pull: true - label: "unittests-gnu-arm" @@ -99,7 +99,7 @@ steps: os: linux plugins: - docker#v3.0.1: - image: "fandree/rust-vmm-dev" + image: "rustvmm/dev:v2" always-pull: true - label: "unittests-musl-arm" @@ -112,12 +112,12 @@ steps: os: linux plugins: - docker#v3.0.1: - image: "fandree/rust-vmm-dev" + image: "rustvmm/dev:v2" always-pull: true - label: "clippy-x86" commands: - - cargo clippy --all + - cargo clippy --all -- -D warnings retry: automatic: false agents: @@ -125,7 +125,20 @@ steps: os: linux plugins: - 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 - label: "check-warnings-x86" @@ -138,7 +151,7 @@ steps: os: linux plugins: - docker#v3.0.1: - image: "fandree/rust-vmm-dev" + image: "rustvmm/dev:v2" always-pull: true - label: "check-warnings-arm" @@ -151,5 +164,5 @@ steps: os: linux plugins: - docker#v3.0.1: - image: "fandree/rust-vmm-dev" + image: "rustvmm/dev:v2" always-pull: true diff --git a/vendor/git-3e7c44ea7d5fd800/vm-memory/.cargo-checksum.json b/vendor/git-3e7c44ea7d5fd800/vm-memory/.cargo-checksum.json index 8cd1bfbcf..c18ed9793 100644 --- a/vendor/git-3e7c44ea7d5fd800/vm-memory/.cargo-checksum.json +++ b/vendor/git-3e7c44ea7d5fd800/vm-memory/.cargo-checksum.json @@ -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} \ No newline at end of file +{"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} \ No newline at end of file diff --git a/vendor/git-643dc7ede01ca600/vmm-sys-util/.buildkite/pipeline.yml b/vendor/git-643dc7ede01ca600/vmm-sys-util/.buildkite/pipeline.yml new file mode 100644 index 000000000..b04c47901 --- /dev/null +++ b/vendor/git-643dc7ede01ca600/vmm-sys-util/.buildkite/pipeline.yml @@ -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 diff --git a/vendor/git-643dc7ede01ca600/vmm-sys-util/.cargo-checksum.json b/vendor/git-643dc7ede01ca600/vmm-sys-util/.cargo-checksum.json new file mode 100644 index 000000000..26f912292 --- /dev/null +++ b/vendor/git-643dc7ede01ca600/vmm-sys-util/.cargo-checksum.json @@ -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} \ No newline at end of file diff --git a/vendor/git-643dc7ede01ca600/vmm-sys-util/.cargo/config b/vendor/git-643dc7ede01ca600/vmm-sys-util/.cargo/config new file mode 100644 index 000000000..0c55a7c4b --- /dev/null +++ b/vendor/git-643dc7ede01ca600/vmm-sys-util/.cargo/config @@ -0,0 +1,2 @@ +[target.aarch64-unknown-linux-musl] +rustflags = [ "-C", "target-feature=+crt-static", "-C", "link-arg=-lgcc"] diff --git a/vendor/git-643dc7ede01ca600/vmm-sys-util/Cargo.toml b/vendor/git-643dc7ede01ca600/vmm-sys-util/Cargo.toml new file mode 100644 index 000000000..bb697b6c3 --- /dev/null +++ b/vendor/git-643dc7ede01ca600/vmm-sys-util/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "vmm-sys-util" +version = "0.1.0" +authors = ["Jing Liu "] +license = "Apache-2.0" + +[dependencies] +libc = ">=0.2.39" + diff --git a/vendor/git-643dc7ede01ca600/vmm-sys-util/LICENSE-APACHE b/vendor/git-643dc7ede01ca600/vmm-sys-util/LICENSE-APACHE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/vendor/git-643dc7ede01ca600/vmm-sys-util/LICENSE-APACHE @@ -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. diff --git a/vendor/git-643dc7ede01ca600/vmm-sys-util/LICENSE-BSD-3-Clause b/vendor/git-643dc7ede01ca600/vmm-sys-util/LICENSE-BSD-3-Clause new file mode 100644 index 000000000..8bafca303 --- /dev/null +++ b/vendor/git-643dc7ede01ca600/vmm-sys-util/LICENSE-BSD-3-Clause @@ -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. diff --git a/vendor/git-643dc7ede01ca600/vmm-sys-util/README.md b/vendor/git-643dc7ede01ca600/vmm-sys-util/README.md new file mode 100644 index 000000000..383aa42db --- /dev/null +++ b/vendor/git-643dc7ede01ca600/vmm-sys-util/README.md @@ -0,0 +1,2 @@ +# vmm-sys-util +This crate is a collection of modules that provides helpers and utilities. diff --git a/vendor/git-643dc7ede01ca600/vmm-sys-util/src/errno.rs b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/errno.rs new file mode 100644 index 000000000..89bbbb6b1 --- /dev/null +++ b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/errno.rs @@ -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 = result::Result; + +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 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() -> Result { + 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::().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()); + } +} diff --git a/vendor/git-643dc7ede01ca600/vmm-sys-util/src/eventfd.rs b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/eventfd.rs new file mode 100644 index 000000000..ff0542735 --- /dev/null +++ b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/eventfd.rs @@ -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 { + // 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::(), + ) + }; + 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 { + 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::(), + ) + }; + 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 { + // 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); + } +} diff --git a/vendor/git-643dc7ede01ca600/vmm-sys-util/src/file_traits.rs b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/file_traits.rs new file mode 100644 index 000000000..a2fa77b87 --- /dev/null +++ b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/file_traits.rs @@ -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) + } +} diff --git a/vendor/git-643dc7ede01ca600/vmm-sys-util/src/ioctl.rs b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/ioctl.rs new file mode 100644 index 000000000..0adc3b1d4 --- /dev/null +++ b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/ioctl.rs @@ -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(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(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(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(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(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(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)); + } +} diff --git a/vendor/git-643dc7ede01ca600/vmm-sys-util/src/lib.rs b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/lib.rs new file mode 100644 index 000000000..883e4a53d --- /dev/null +++ b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/lib.rs @@ -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(()) + } +} diff --git a/vendor/git-643dc7ede01ca600/vmm-sys-util/src/poll.rs b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/poll.rs new file mode 100644 index 000000000..4eb49a429 --- /dev/null +++ b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/poll.rs @@ -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, // 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, +{ + 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, + T: PollToken, +{ + type Item = PollEvent<'a, T>; + fn next(&mut self) -> Option { + 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 { + PollEventsOwned { + count: self.count, + events: RefCell::new(*self.events), + tokens: PhantomData, + } + } + + /// Iterates over each event. + pub fn iter(&self) -> PollEventIter, T> { + PollEventIter { + mask: 0xffff_ffff, + iter: self.events[..self.count].iter(), + tokens: PhantomData, + } + } + + /// Iterates over each readable event. + pub fn iter_readable(&self) -> PollEventIter, 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, 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 { + count: usize, + events: RefCell<[epoll_event; POLL_CONTEXT_MAX_EVENTS]>, + tokens: PhantomData, // Needed to satisfy usage of T +} + +impl PollEventsOwned { + /// Takes a reference to the events so that they can be iterated via methods in `PollEvents`. + pub fn as_ref(&self) -> PollEvents { + 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 { + epoll_ctx: File, + // Needed to satisfy usage of T + tokens: PhantomData<[T]>, +} + +impl EpollContext { + /// Creates a new `EpollContext`. + pub fn new() -> Result> { + // 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> { + 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> { + 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 AsRawFd for EpollContext { + fn as_raw_fd(&self) -> RawFd { + self.epoll_ctx.as_raw_fd() + } +} + +impl IntoRawFd for EpollContext { + 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 = PollContext::new()?; +/// ctx.add(&evt1, 1)?; +/// ctx.add(&evt2, 2)?; +/// +/// let pollevents: PollEvents = ctx.wait()?; +/// let tokens: Vec = pollevents.iter_readable().map(|e| e.token()).collect(); +/// assert_eq!(&tokens[..], &[2]); +/// # Ok(()) +/// # } +/// ``` +pub struct PollContext { + epoll_ctx: EpollContext, + + // 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, + max_hangups: Cell, +} + +impl PollContext { + /// Creates a new `PollContext`. + pub fn new() -> Result> { + 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> { + 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> { + 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 AsRawFd for PollContext { + fn as_raw_fd(&self) -> RawFd { + self.epoll_ctx.as_raw_fd() + } +} + +impl IntoRawFd for PollContext { + 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 = 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 = 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 = 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 = PollContext::new().unwrap(); + let dur = Duration::from_millis(10); + let start_inst = Instant::now(); + ctx.wait_timeout(dur).unwrap(); + assert!(start_inst.elapsed() >= dur); + } + +} diff --git a/vendor/git-643dc7ede01ca600/vmm-sys-util/src/seek_hole.rs b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/seek_hole.rs new file mode 100644 index 000000000..12ac2e9bb --- /dev/null +++ b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/seek_hole.rs @@ -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>; + + /// 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>; +} + +#[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> { + // 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> { + lseek(self, offset as i64, SEEK_HOLE) + } + + fn seek_data(&mut self, offset: u64) -> Result> { + 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); + } +} diff --git a/vendor/git-643dc7ede01ca600/vmm-sys-util/src/signal.rs b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/signal.rs new file mode 100644 index 000000000..4961d958c --- /dev/null +++ b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/signal.rs @@ -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 = result::Result; +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 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 { + 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 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> { + 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 Killable for JoinHandle { + 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::(), mem::size_of::()); + 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. + } +} diff --git a/vendor/git-643dc7ede01ca600/vmm-sys-util/src/syslog.rs b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/syslog.rs new file mode 100644 index 000000000..d09b56a88 --- /dev/null +++ b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/syslog.rs @@ -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 { + 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 { + 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 { + // 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, + file: Option, + hostname: Option, + proc_name: Option, +} + +impl State { + fn new() -> Result { + 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 = 0 as *const _; + +fn new_mutex_ptr(inner: T) -> *const StdMutex { + 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, 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>(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>(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) { + 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) { + 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")); + } +} diff --git a/vendor/git-643dc7ede01ca600/vmm-sys-util/src/tempdir.rs b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/tempdir.rs new file mode 100644 index 000000000..7256998e8 --- /dev/null +++ b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/tempdir.rs @@ -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, +} + +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>(prefix: P) -> Result { + 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()); + } +} diff --git a/vendor/git-643dc7ede01ca600/vmm-sys-util/src/terminal.rs b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/terminal.rs new file mode 100644 index 000000000..2d6177d1d --- /dev/null +++ b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/terminal.rs @@ -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(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 { + // 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 { + // 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()); + } +} diff --git a/vendor/git-643dc7ede01ca600/vmm-sys-util/src/timerfd.rs b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/timerfd.rs new file mode 100644 index 000000000..4e2903e52 --- /dev/null +++ b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/timerfd.rs @@ -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 { + // 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) -> 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 { + 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 { + // 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); + } + +} diff --git a/vendor/git-643dc7ede01ca600/vmm-sys-util/src/write_zeroes.rs b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/write_zeroes.rs new file mode 100644 index 000000000..98195d8f3 --- /dev/null +++ b/vendor/git-643dc7ede01ca600/vmm-sys-util/src/write_zeroes.rs @@ -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; +} + +impl WriteZeroes for T { + fn write_zeroes(&mut self, length: usize) -> io::Result { + // 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); + } + } +} diff --git a/vendor/git-bda1448fb2afcb00/linux-loader/.buildkite/hooks/post-checkout b/vendor/git-bda1448fb2afcb00/linux-loader/.buildkite/hooks/post-checkout index 8b1bf2e2c..5a628ee97 100644 --- a/vendor/git-bda1448fb2afcb00/linux-loader/.buildkite/hooks/post-checkout +++ b/vendor/git-bda1448fb2afcb00/linux-loader/.buildkite/hooks/post-checkout @@ -1,5 +1,6 @@ #!/bin/bash -wget http://mirror.centos.org/centos/7/os/x86_64/Packages/kernel-3.10.0-957.el7.x86_64.rpm -rpm2cpio kernel-3.10.0-957.el7.x86_64.rpm | cpio -idmv ./boot/vmlinuz-3.10.0-957.el7.x86_64 +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 +dpkg-deb -x $BUILDKITE_BUILD_CHECKOUT_PATH/linux-loader/src/loader/linux-image-4.9.0-9-amd64_4.9.168-1_amd64.deb + diff --git a/vendor/git-bda1448fb2afcb00/linux-loader/.cargo-checksum.json b/vendor/git-bda1448fb2afcb00/linux-loader/.cargo-checksum.json index d7eb78fa7..631bfb9d4 100644 --- a/vendor/git-bda1448fb2afcb00/linux-loader/.cargo-checksum.json +++ b/vendor/git-bda1448fb2afcb00/linux-loader/.cargo-checksum.json @@ -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} \ No newline at end of file +{"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} \ No newline at end of file diff --git a/vendor/git-bda1448fb2afcb00/linux-loader/Cargo.toml b/vendor/git-bda1448fb2afcb00/linux-loader/Cargo.toml index d180f24e4..368659e80 100644 --- a/vendor/git-bda1448fb2afcb00/linux-loader/Cargo.toml +++ b/vendor/git-bda1448fb2afcb00/linux-loader/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" license = "Apache-2.0 AND BSD-3-Clause" [features] -default = ["elf"] +default = [] elf = [] bzImage = [] diff --git a/vendor/git-bda1448fb2afcb00/linux-loader/src/loader/mod.rs b/vendor/git-bda1448fb2afcb00/linux-loader/src/loader/mod.rs index 7c9d5e87e..a4a30ba4b 100644 --- a/vendor/git-bda1448fb2afcb00/linux-loader/src/loader/mod.rs +++ b/vendor/git-bda1448fb2afcb00/linux-loader/src/loader/mod.rs @@ -182,7 +182,6 @@ impl KernelLoader for Elf { return Err(Error::InvalidProgramHeaderSize); } if (ehdr.e_phoff as usize) < mem::size_of::() { - return Err(Error::InvalidProgramHeaderOffset); } if (highmem_start_address.is_some()) @@ -383,7 +382,7 @@ mod test { #[cfg(feature = "bzImage")] fn make_bzImage() -> Vec { 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 } @@ -556,6 +555,7 @@ mod test { assert_eq!(val, '\0' as u8); } + #[cfg(feature = "elf")] #[test] fn bad_magic() { let gm = create_guest_mem(); @@ -568,6 +568,7 @@ mod test { ); } + #[cfg(feature = "elf")] #[test] fn bad_endian() { // Only little endian is supported @@ -581,6 +582,7 @@ mod test { ); } + #[cfg(feature = "elf")] #[test] fn bad_phoff() { // program header has to be past the end of the elf header diff --git a/vendor/registry-40351f815f426200/bitflags/.cargo-checksum.json b/vendor/registry-40351f815f426200/bitflags/.cargo-checksum.json index 0338787d2..65776d56d 100644 --- a/vendor/registry-40351f815f426200/bitflags/.cargo-checksum.json +++ b/vendor/registry-40351f815f426200/bitflags/.cargo-checksum.json @@ -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"} \ No newline at end of file +{"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"} \ No newline at end of file diff --git a/vendor/registry-40351f815f426200/bitflags/CHANGELOG.md b/vendor/registry-40351f815f426200/bitflags/CHANGELOG.md index 1f5b4252c..1fbb95a81 100644 --- a/vendor/registry-40351f815f426200/bitflags/CHANGELOG.md +++ b/vendor/registry-40351f815f426200/bitflags/CHANGELOG.md @@ -1,108 +1,134 @@ -# 1.0.3 - -- Improve zero value flag handling and documentation ([#157]) - -[#157]: https://github.com/rust-lang-nursery/bitflags/pull/157 - -# 1.0.2 - -- 30% improvement in compile time of bitflags crate ([#156]) - -- Documentation improvements ([#153]) - -- Implementation cleanup ([#149]) - -[#156]: https://github.com/rust-lang-nursery/bitflags/pull/156 -[#153]: https://github.com/rust-lang-nursery/bitflags/pull/153 -[#149]: https://github.com/rust-lang-nursery/bitflags/pull/149 - -# 1.0.1 -- 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 -[#136]: https://github.com/rust-lang-nursery/bitflags/pull/136 - -# 1.0.0 -- **[breaking change]** Macro now generates [associated constants](https://doc.rust-lang.org/reference/items.html#associated-constants) ([#24]) - -- **[breaking change]** Minimum supported version is Rust **1.20**, due to usage of associated constants - -- After being broken in 0.9, the `#[deprecated]` attribute is now supported again ([#112]) - -- Other improvements to unit tests and documentation ([#106] and [#115]) - -[#24]: https://github.com/rust-lang-nursery/bitflags/pull/24 -[#106]: https://github.com/rust-lang-nursery/bitflags/pull/106 -[#112]: https://github.com/rust-lang-nursery/bitflags/pull/112 -[#115]: https://github.com/rust-lang-nursery/bitflags/pull/115 - -## How to update your code to use associated constants -Assuming the following structure definition: -```rust -bitflags! { - struct Something: u8 { - const FOO = 0b01, - const BAR = 0b10 - } -} -``` -In 0.9 and older you could do: -```rust -let x = FOO.bits | BAR.bits; -``` -Now you must use: -```rust -let x = Something::FOO.bits | Something::BAR.bits; -``` - -# 0.9.1 -- Fix the implementation of `Formatting` traits when other formatting traits were present in scope ([#105]) - -[#105]: https://github.com/rust-lang-nursery/bitflags/pull/105 - -# 0.9.0 -- **[breaking change]** Use struct keyword instead of flags to define bitflag types ([#84]) - -- **[breaking change]** Terminate const items with semicolons instead of commas ([#87]) - -- Implement the `Hex`, `Octal`, and `Binary` formatting traits ([#86]) - -- Printing an empty flag value with the `Debug` trait now prints "(empty)" instead of nothing ([#85]) - -- 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 -[#85]: https://github.com/rust-lang-nursery/bitflags/pull/85 -[#86]: https://github.com/rust-lang-nursery/bitflags/pull/86 -[#87]: https://github.com/rust-lang-nursery/bitflags/pull/87 - -# 0.8.2 -- 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.1.0 + +This is a re-release of `1.0.5`, which was yanked due to a bug in the RLS. + +# 1.0.5 + +- Use compiletest_rs flags supported by stable toolchain ([#171]) + +- Put the user provided attributes first ([#173]) + +- Make bitflags methods `const` on newer compilers ([#175]) + +[#171]: https://github.com/rust-lang-nursery/bitflags/pull/171 +[#173]: https://github.com/rust-lang-nursery/bitflags/pull/173 +[#175]: https://github.com/rust-lang-nursery/bitflags/pull/175 + +# 1.0.4 + +- Support Rust 2018 style macro imports ([#165]) + + ```rust + use bitflags::bitflags; + ``` + +[#165]: https://github.com/rust-lang-nursery/bitflags/pull/165 + +# 1.0.3 + +- Improve zero value flag handling and documentation ([#157]) + +[#157]: https://github.com/rust-lang-nursery/bitflags/pull/157 + +# 1.0.2 + +- 30% improvement in compile time of bitflags crate ([#156]) + +- Documentation improvements ([#153]) + +- Implementation cleanup ([#149]) + +[#156]: https://github.com/rust-lang-nursery/bitflags/pull/156 +[#153]: https://github.com/rust-lang-nursery/bitflags/pull/153 +[#149]: https://github.com/rust-lang-nursery/bitflags/pull/149 + +# 1.0.1 +- 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 +[#136]: https://github.com/rust-lang-nursery/bitflags/pull/136 + +# 1.0.0 +- **[breaking change]** Macro now generates [associated constants](https://doc.rust-lang.org/reference/items.html#associated-constants) ([#24]) + +- **[breaking change]** Minimum supported version is Rust **1.20**, due to usage of associated constants + +- After being broken in 0.9, the `#[deprecated]` attribute is now supported again ([#112]) + +- Other improvements to unit tests and documentation ([#106] and [#115]) + +[#24]: https://github.com/rust-lang-nursery/bitflags/pull/24 +[#106]: https://github.com/rust-lang-nursery/bitflags/pull/106 +[#112]: https://github.com/rust-lang-nursery/bitflags/pull/112 +[#115]: https://github.com/rust-lang-nursery/bitflags/pull/115 + +## How to update your code to use associated constants +Assuming the following structure definition: +```rust +bitflags! { + struct Something: u8 { + const FOO = 0b01, + const BAR = 0b10 + } +} +``` +In 0.9 and older you could do: +```rust +let x = FOO.bits | BAR.bits; +``` +Now you must use: +```rust +let x = Something::FOO.bits | Something::BAR.bits; +``` + +# 0.9.1 +- Fix the implementation of `Formatting` traits when other formatting traits were present in scope ([#105]) + +[#105]: https://github.com/rust-lang-nursery/bitflags/pull/105 + +# 0.9.0 +- **[breaking change]** Use struct keyword instead of flags to define bitflag types ([#84]) + +- **[breaking change]** Terminate const items with semicolons instead of commas ([#87]) + +- Implement the `Hex`, `Octal`, and `Binary` formatting traits ([#86]) + +- Printing an empty flag value with the `Debug` trait now prints "(empty)" instead of nothing ([#85]) + +- 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 +[#85]: https://github.com/rust-lang-nursery/bitflags/pull/85 +[#86]: https://github.com/rust-lang-nursery/bitflags/pull/86 +[#87]: https://github.com/rust-lang-nursery/bitflags/pull/87 + +# 0.8.2 +- 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 diff --git a/vendor/registry-40351f815f426200/bitflags/CODE_OF_CONDUCT.md b/vendor/registry-40351f815f426200/bitflags/CODE_OF_CONDUCT.md index f7add90ae..ae001fdc8 100644 --- a/vendor/registry-40351f815f426200/bitflags/CODE_OF_CONDUCT.md +++ b/vendor/registry-40351f815f426200/bitflags/CODE_OF_CONDUCT.md @@ -1,73 +1,73 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, gender identity and expression, level of experience, -education, socio-economic status, nationality, personal appearance, race, -religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -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 -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 -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at coc@senaite.org. All -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 -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -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 -members of the project's leadership. - -## Attribution - -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 - +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +education, socio-economic status, nationality, personal appearance, race, +religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +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 +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 +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at coc@senaite.org. All +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 +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +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 +members of the project's leadership. + +## Attribution + +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 + [homepage]: https://www.contributor-covenant.org \ No newline at end of file diff --git a/vendor/registry-40351f815f426200/bitflags/Cargo.toml b/vendor/registry-40351f815f426200/bitflags/Cargo.toml index 956e9e976..c3391297d 100644 --- a/vendor/registry-40351f815f426200/bitflags/Cargo.toml +++ b/vendor/registry-40351f815f426200/bitflags/Cargo.toml @@ -3,7 +3,7 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies +# to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're @@ -12,8 +12,9 @@ [package] name = "bitflags" -version = "1.0.4" +version = "1.1.0" authors = ["The Rust Project Developers"] +build = "build.rs" exclude = [".travis.yml", "appveyor.yml", "bors.toml"] description = "A macro to generate structures which behave like bitflags.\n" homepage = "https://github.com/bitflags/bitflags" diff --git a/vendor/registry-40351f815f426200/bitflags/LICENSE-APACHE b/vendor/registry-40351f815f426200/bitflags/LICENSE-APACHE index 16fe87b06..f47c94114 100644 --- a/vendor/registry-40351f815f426200/bitflags/LICENSE-APACHE +++ b/vendor/registry-40351f815f426200/bitflags/LICENSE-APACHE @@ -1,201 +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. + 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. diff --git a/vendor/registry-40351f815f426200/bitflags/LICENSE-MIT b/vendor/registry-40351f815f426200/bitflags/LICENSE-MIT index 39d4bdb5a..c0428e2d3 100644 --- a/vendor/registry-40351f815f426200/bitflags/LICENSE-MIT +++ b/vendor/registry-40351f815f426200/bitflags/LICENSE-MIT @@ -1,25 +1,25 @@ -Copyright (c) 2014 The Rust Project Developers - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/vendor/registry-40351f815f426200/bitflags/README.md b/vendor/registry-40351f815f426200/bitflags/README.md index df12934c3..59c849bfe 100644 --- a/vendor/registry-40351f815f426200/bitflags/README.md +++ b/vendor/registry-40351f815f426200/bitflags/README.md @@ -1,34 +1,34 @@ -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) -[![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) -![Minimum rustc version](https://img.shields.io/badge/rustc-1.20+-yellow.svg) -![License](https://img.shields.io/crates/l/bitflags.svg) - -A Rust macro to generate structures which behave like a set of bitflags - -- [Documentation](https://docs.rs/bitflags) -- [Release notes](https://github.com/bitflags/bitflags/releases) - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -bitflags = "1.0" -``` - -and this to your crate root: - -```rust -#[macro_use] -extern crate bitflags; -``` - -## Rust Version Support - -The minimum supported Rust version is 1.20 due to use of associated constants. +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) +[![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) +![Minimum rustc version](https://img.shields.io/badge/rustc-1.20+-yellow.svg) +![License](https://img.shields.io/crates/l/bitflags.svg) + +A Rust macro to generate structures which behave like a set of bitflags + +- [Documentation](https://docs.rs/bitflags) +- [Release notes](https://github.com/bitflags/bitflags/releases) + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +bitflags = "1.0" +``` + +and this to your crate root: + +```rust +#[macro_use] +extern crate bitflags; +``` + +## Rust Version Support + +The minimum supported Rust version is 1.20 due to use of associated constants. diff --git a/vendor/registry-40351f815f426200/bitflags/build.rs b/vendor/registry-40351f815f426200/bitflags/build.rs new file mode 100644 index 000000000..168c03055 --- /dev/null +++ b/vendor/registry-40351f815f426200/bitflags/build.rs @@ -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 { + 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() +} \ No newline at end of file diff --git a/vendor/registry-40351f815f426200/bitflags/src/example_generated.rs b/vendor/registry-40351f815f426200/bitflags/src/example_generated.rs index cf188d99c..a860d2dcf 100644 --- a/vendor/registry-40351f815f426200/bitflags/src/example_generated.rs +++ b/vendor/registry-40351f815f426200/bitflags/src/example_generated.rs @@ -1,14 +1,14 @@ -//! This module shows an example of code generated by the macro. **IT MUST NOT BE USED OUTSIDE THIS -//! CRATE**. - -bitflags! { - /// 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 - /// this crate. - pub struct Flags: u32 { - const A = 0b00000001; - const B = 0b00000010; - const C = 0b00000100; - const ABC = Self::A.bits | Self::B.bits | Self::C.bits; - } -} +//! This module shows an example of code generated by the macro. **IT MUST NOT BE USED OUTSIDE THIS +//! CRATE**. + +bitflags! { + /// 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 + /// this crate. + pub struct Flags: u32 { + const A = 0b00000001; + const B = 0b00000010; + const C = 0b00000100; + const ABC = Self::A.bits | Self::B.bits | Self::C.bits; + } +} diff --git a/vendor/registry-40351f815f426200/bitflags/src/lib.rs b/vendor/registry-40351f815f426200/bitflags/src/lib.rs index 9e1bcfd6c..44a6f80cc 100644 --- a/vendor/registry-40351f815f426200/bitflags/src/lib.rs +++ b/vendor/registry-40351f815f426200/bitflags/src/lib.rs @@ -1,1229 +1,1353 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A typesafe bitmask flag generator useful for sets of C-style bitmask flags. -//! It can be used for creating typesafe wrappers around C APIs. -//! -//! The `bitflags!` macro generates a `struct` that manages a set of flags. The -//! flags should only be defined for integer types, otherwise unexpected type -//! errors may occur at compile time. -//! -//! # Example -//! -//! ``` -//! #[macro_use] -//! extern crate bitflags; -//! -//! bitflags! { -//! struct Flags: u32 { -//! const A = 0b00000001; -//! const B = 0b00000010; -//! const C = 0b00000100; -//! const ABC = Self::A.bits | Self::B.bits | Self::C.bits; -//! } -//! } -//! -//! fn main() { -//! let e1 = Flags::A | Flags::C; -//! let e2 = Flags::B | Flags::C; -//! assert_eq!((e1 | e2), Flags::ABC); // union -//! assert_eq!((e1 & e2), Flags::C); // intersection -//! assert_eq!((e1 - e2), Flags::A); // set difference -//! assert_eq!(!e2, Flags::A); // set complement -//! } -//! ``` -//! -//! See [`example_generated::Flags`](./example_generated/struct.Flags.html) for documentation of code -//! generated by the above `bitflags!` expansion. -//! -//! The generated `struct`s can also be extended with type and trait -//! implementations: -//! -//! ``` -//! #[macro_use] -//! extern crate bitflags; -//! -//! use std::fmt; -//! -//! bitflags! { -//! struct Flags: u32 { -//! const A = 0b00000001; -//! const B = 0b00000010; -//! } -//! } -//! -//! impl Flags { -//! pub fn clear(&mut self) { -//! self.bits = 0; // The `bits` field can be accessed from within the -//! // same module where the `bitflags!` macro was invoked. -//! } -//! } -//! -//! impl fmt::Display for Flags { -//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { -//! write!(f, "hi!") -//! } -//! } -//! -//! fn main() { -//! let mut flags = Flags::A | Flags::B; -//! flags.clear(); -//! assert!(flags.is_empty()); -//! assert_eq!(format!("{}", flags), "hi!"); -//! assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); -//! assert_eq!(format!("{:?}", Flags::B), "B"); -//! } -//! ``` -//! -//! # Visibility -//! -//! The generated struct and its associated flag constants are not exported -//! out of the current module by default. A definition can be exported out of -//! the current module by adding `pub` before `flags`: -//! -//! ``` -//! #[macro_use] -//! extern crate bitflags; -//! -//! mod example { -//! bitflags! { -//! pub struct Flags1: u32 { -//! const A = 0b00000001; -//! } -//! } -//! bitflags! { -//! # pub -//! struct Flags2: u32 { -//! const B = 0b00000010; -//! } -//! } -//! } -//! -//! fn main() { -//! let flag1 = example::Flags1::A; -//! let flag2 = example::Flags2::B; // error: const `B` is private -//! } -//! ``` -//! -//! # Attributes -//! -//! Attributes can be attached to the generated `struct` by placing them -//! before the `flags` keyword. -//! -//! # Trait implementations -//! -//! The `Copy`, `Clone`, `PartialEq`, `Eq`, `PartialOrd`, `Ord` and `Hash` -//! traits automatically derived for the `struct` using the `derive` attribute. -//! Additional traits can be derived by providing an explicit `derive` -//! attribute on `flags`. -//! -//! The `Extend` and `FromIterator` traits are implemented for the `struct`, -//! too: `Extend` adds the union of the instances of the `struct` iterated over, -//! while `FromIterator` calculates the union. -//! -//! The `Binary`, `Debug`, `LowerExp`, `Octal` and `UpperExp` trait is also -//! implemented by displaying the bits value of the internal struct. -//! -//! ## Operators -//! -//! The following operator traits are implemented for the generated `struct`: -//! -//! - `BitOr` and `BitOrAssign`: union -//! - `BitAnd` and `BitAndAssign`: intersection -//! - `BitXor` and `BitXorAssign`: toggle -//! - `Sub` and `SubAssign`: set difference -//! - `Not`: set complement -//! -//! # Methods -//! -//! The following methods are defined for the generated `struct`: -//! -//! - `empty`: an empty set of flags -//! - `all`: the set of all flags -//! - `bits`: the raw value of the flags currently stored -//! - `from_bits`: convert from underlying bit representation, unless that -//! representation contains bits that do not correspond to a flag -//! - `from_bits_truncate`: convert from underlying bit representation, dropping -//! any bits that do not correspond to flags -//! - `is_empty`: `true` if no flags are currently stored -//! - `is_all`: `true` if all flags are currently set -//! - `intersects`: `true` if there are flags common to both `self` and `other` -//! - `contains`: `true` all of the flags in `other` are contained within `self` -//! - `insert`: inserts the specified flags in-place -//! - `remove`: removes the specified flags in-place -//! - `toggle`: the specified flags will be inserted if not present, and removed -//! if they are. -//! - `set`: inserts or removes the specified flags depending on the passed value -//! -//! ## Default -//! -//! The `Default` trait is not automatically implemented for the generated struct. -//! -//! If your default value is equal to `0` (which is the same value as calling `empty()` -//! on the generated struct), you can simply derive `Default`: -//! -//! ``` -//! #[macro_use] -//! extern crate bitflags; -//! -//! bitflags! { -//! // Results in default value with bits: 0 -//! #[derive(Default)] -//! struct Flags: u32 { -//! const A = 0b00000001; -//! const B = 0b00000010; -//! const C = 0b00000100; -//! } -//! } -//! -//! fn main() { -//! let derived_default: Flags = Default::default(); -//! assert_eq!(derived_default.bits(), 0); -//! } -//! ``` -//! -//! If your default value is not equal to `0` you need to implement `Default` yourself: -//! -//! ``` -//! #[macro_use] -//! extern crate bitflags; -//! -//! bitflags! { -//! struct Flags: u32 { -//! const A = 0b00000001; -//! const B = 0b00000010; -//! const C = 0b00000100; -//! } -//! } -//! -//! // explicit `Default` implementation -//! impl Default for Flags { -//! fn default() -> Flags { -//! Flags::A | Flags::C -//! } -//! } -//! -//! fn main() { -//! let implemented_default: Flags = Default::default(); -//! assert_eq!(implemented_default, (Flags::A | Flags::C)); -//! } -//! ``` -//! -//! # Zero Flags -//! -//! Flags with a value equal to zero will have some strange behavior that one should be aware of. -//! -//! ``` -//! #[macro_use] -//! extern crate bitflags; -//! -//! bitflags! { -//! struct Flags: u32 { -//! const NONE = 0b00000000; -//! const SOME = 0b00000001; -//! } -//! } -//! -//! fn main() { -//! let empty = Flags::empty(); -//! let none = Flags::NONE; -//! let some = Flags::SOME; -//! -//! // Zero flags are treated as always present -//! assert!(empty.contains(Flags::NONE)); -//! assert!(none.contains(Flags::NONE)); -//! assert!(some.contains(Flags::NONE)); -//! -//! // Zero flags will be ignored when testing for emptiness -//! assert!(none.is_empty()); -//! } -//! ``` - -#![no_std] -#![doc(html_root_url = "https://docs.rs/bitflags/1.0.4")] - -#[cfg(test)] -#[macro_use] -extern crate std; - -// Re-export libcore using an alias so that the macros can work without -// requiring `extern crate core` downstream. -#[doc(hidden)] -pub extern crate core as _core; - -/// The macro used to generate the flag structure. -/// -/// See the [crate level docs](../bitflags/index.html) for complete documentation. -/// -/// # Example -/// -/// ``` -/// #[macro_use] -/// extern crate bitflags; -/// -/// bitflags! { -/// struct Flags: u32 { -/// const A = 0b00000001; -/// const B = 0b00000010; -/// const C = 0b00000100; -/// const ABC = Self::A.bits | Self::B.bits | Self::C.bits; -/// } -/// } -/// -/// fn main() { -/// let e1 = Flags::A | Flags::C; -/// let e2 = Flags::B | Flags::C; -/// assert_eq!((e1 | e2), Flags::ABC); // union -/// assert_eq!((e1 & e2), Flags::C); // intersection -/// assert_eq!((e1 - e2), Flags::A); // set difference -/// assert_eq!(!e2, Flags::A); // set complement -/// } -/// ``` -/// -/// The generated `struct`s can also be extended with type and trait -/// implementations: -/// -/// ``` -/// #[macro_use] -/// extern crate bitflags; -/// -/// use std::fmt; -/// -/// bitflags! { -/// struct Flags: u32 { -/// const A = 0b00000001; -/// const B = 0b00000010; -/// } -/// } -/// -/// impl Flags { -/// pub fn clear(&mut self) { -/// self.bits = 0; // The `bits` field can be accessed from within the -/// // same module where the `bitflags!` macro was invoked. -/// } -/// } -/// -/// impl fmt::Display for Flags { -/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { -/// write!(f, "hi!") -/// } -/// } -/// -/// fn main() { -/// let mut flags = Flags::A | Flags::B; -/// flags.clear(); -/// assert!(flags.is_empty()); -/// assert_eq!(format!("{}", flags), "hi!"); -/// assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); -/// assert_eq!(format!("{:?}", Flags::B), "B"); -/// } -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! bitflags { - ( - $(#[$outer:meta])* - pub struct $BitFlags:ident: $T:ty { - $( - $(#[$inner:ident $($args:tt)*])* - const $Flag:ident = $value:expr; - )+ - } - ) => { - __bitflags! { - $(#[$outer])* - (pub) $BitFlags: $T { - $( - $(#[$inner $($args)*])* - $Flag = $value; - )+ - } - } - }; - ( - $(#[$outer:meta])* - struct $BitFlags:ident: $T:ty { - $( - $(#[$inner:ident $($args:tt)*])* - const $Flag:ident = $value:expr; - )+ - } - ) => { - __bitflags! { - $(#[$outer])* - () $BitFlags: $T { - $( - $(#[$inner $($args)*])* - $Flag = $value; - )+ - } - } - }; - ( - $(#[$outer:meta])* - pub ($($vis:tt)+) struct $BitFlags:ident: $T:ty { - $( - $(#[$inner:ident $($args:tt)*])* - const $Flag:ident = $value:expr; - )+ - } - ) => { - __bitflags! { - $(#[$outer])* - (pub ($($vis)+)) $BitFlags: $T { - $( - $(#[$inner $($args)*])* - $Flag = $value; - )+ - } - } - }; -} - -#[macro_export(local_inner_macros)] -#[doc(hidden)] -macro_rules! __bitflags { - ( - $(#[$outer:meta])* - ($($vis:tt)*) $BitFlags:ident: $T:ty { - $( - $(#[$inner:ident $($args:tt)*])* - $Flag:ident = $value:expr; - )+ - } - ) => { - #[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)] - $(#[$outer])* - $($vis)* struct $BitFlags { - bits: $T, - } - - __impl_bitflags! { - $BitFlags: $T { - $( - $(#[$inner $($args)*])* - $Flag = $value; - )+ - } - } - }; -} - -#[macro_export(local_inner_macros)] -#[doc(hidden)] -macro_rules! __impl_bitflags { - ( - $BitFlags:ident: $T:ty { - $( - $(#[$attr:ident $($args:tt)*])* - $Flag:ident = $value:expr; - )+ - } - ) => { - impl $crate::_core::fmt::Debug for $BitFlags { - fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { - // This convoluted approach is to handle #[cfg]-based flag - // omission correctly. For example it needs to support: - // - // #[cfg(unix)] const A: Flag = /* ... */; - // #[cfg(windows)] const B: Flag = /* ... */; - - // Unconditionally define a check for every flag, even disabled - // ones. - #[allow(non_snake_case)] - trait __BitFlags { - $( - #[inline] - fn $Flag(&self) -> bool { false } - )+ - } - - // Conditionally override the check for just those flags that - // are not #[cfg]ed away. - impl __BitFlags for $BitFlags { - $( - __impl_bitflags! { - #[allow(deprecated)] - #[inline] - $(? #[$attr $($args)*])* - fn $Flag(&self) -> bool { - if Self::$Flag.bits == 0 && self.bits != 0 { - false - } else { - self.bits & Self::$Flag.bits == Self::$Flag.bits - } - } - } - )+ - } - - let mut first = true; - $( - if <$BitFlags as __BitFlags>::$Flag(self) { - if !first { - f.write_str(" | ")?; - } - first = false; - f.write_str(__bitflags_stringify!($Flag))?; - } - )+ - if first { - f.write_str("(empty)")?; - } - Ok(()) - } - } - impl $crate::_core::fmt::Binary for $BitFlags { - fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { - $crate::_core::fmt::Binary::fmt(&self.bits, f) - } - } - impl $crate::_core::fmt::Octal for $BitFlags { - fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { - $crate::_core::fmt::Octal::fmt(&self.bits, f) - } - } - impl $crate::_core::fmt::LowerHex for $BitFlags { - fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { - $crate::_core::fmt::LowerHex::fmt(&self.bits, f) - } - } - impl $crate::_core::fmt::UpperHex for $BitFlags { - fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { - $crate::_core::fmt::UpperHex::fmt(&self.bits, f) - } - } - - #[allow(dead_code)] - impl $BitFlags { - $( - $(#[$attr $($args)*])* - pub const $Flag: $BitFlags = $BitFlags { bits: $value }; - )+ - - /// Returns an empty set of flags. - #[inline] - pub fn empty() -> $BitFlags { - $BitFlags { bits: 0 } - } - - /// Returns the set containing all flags. - #[inline] - pub fn all() -> $BitFlags { - // See `Debug::fmt` for why this approach is taken. - #[allow(non_snake_case)] - trait __BitFlags { - $( - #[inline] - fn $Flag() -> $T { 0 } - )+ - } - impl __BitFlags for $BitFlags { - $( - __impl_bitflags! { - #[allow(deprecated)] - #[inline] - $(? #[$attr $($args)*])* - fn $Flag() -> $T { Self::$Flag.bits } - } - )+ - } - $BitFlags { bits: $(<$BitFlags as __BitFlags>::$Flag())|+ } - } - - /// Returns the raw value of the flags currently stored. - #[inline] - pub fn bits(&self) -> $T { - self.bits - } - - /// Convert from underlying bit representation, unless that - /// representation contains bits that do not correspond to a flag. - #[inline] - pub fn from_bits(bits: $T) -> $crate::_core::option::Option<$BitFlags> { - if (bits & !$BitFlags::all().bits()) == 0 { - $crate::_core::option::Option::Some($BitFlags { bits }) - } else { - $crate::_core::option::Option::None - } - } - - /// Convert from underlying bit representation, dropping any bits - /// that do not correspond to flags. - #[inline] - pub fn from_bits_truncate(bits: $T) -> $BitFlags { - $BitFlags { bits } & $BitFlags::all() - } - - /// Returns `true` if no flags are currently stored. - #[inline] - pub fn is_empty(&self) -> bool { - *self == $BitFlags::empty() - } - - /// Returns `true` if all flags are currently set. - #[inline] - pub fn is_all(&self) -> bool { - *self == $BitFlags::all() - } - - /// Returns `true` if there are flags common to both `self` and `other`. - #[inline] - pub fn intersects(&self, other: $BitFlags) -> bool { - !(*self & other).is_empty() - } - - /// Returns `true` all of the flags in `other` are contained within `self`. - #[inline] - pub fn contains(&self, other: $BitFlags) -> bool { - (*self & other) == other - } - - /// Inserts the specified flags in-place. - #[inline] - pub fn insert(&mut self, other: $BitFlags) { - self.bits |= other.bits; - } - - /// Removes the specified flags in-place. - #[inline] - pub fn remove(&mut self, other: $BitFlags) { - self.bits &= !other.bits; - } - - /// Toggles the specified flags in-place. - #[inline] - pub fn toggle(&mut self, other: $BitFlags) { - self.bits ^= other.bits; - } - - /// Inserts or removes the specified flags depending on the passed value. - #[inline] - pub fn set(&mut self, other: $BitFlags, value: bool) { - if value { - self.insert(other); - } else { - self.remove(other); - } - } - } - - impl $crate::_core::ops::BitOr for $BitFlags { - type Output = $BitFlags; - - /// Returns the union of the two sets of flags. - #[inline] - fn bitor(self, other: $BitFlags) -> $BitFlags { - $BitFlags { bits: self.bits | other.bits } - } - } - - impl $crate::_core::ops::BitOrAssign for $BitFlags { - - /// Adds the set of flags. - #[inline] - fn bitor_assign(&mut self, other: $BitFlags) { - self.bits |= other.bits; - } - } - - impl $crate::_core::ops::BitXor for $BitFlags { - type Output = $BitFlags; - - /// Returns the left flags, but with all the right flags toggled. - #[inline] - fn bitxor(self, other: $BitFlags) -> $BitFlags { - $BitFlags { bits: self.bits ^ other.bits } - } - } - - impl $crate::_core::ops::BitXorAssign for $BitFlags { - - /// Toggles the set of flags. - #[inline] - fn bitxor_assign(&mut self, other: $BitFlags) { - self.bits ^= other.bits; - } - } - - impl $crate::_core::ops::BitAnd for $BitFlags { - type Output = $BitFlags; - - /// Returns the intersection between the two sets of flags. - #[inline] - fn bitand(self, other: $BitFlags) -> $BitFlags { - $BitFlags { bits: self.bits & other.bits } - } - } - - impl $crate::_core::ops::BitAndAssign for $BitFlags { - - /// Disables all flags disabled in the set. - #[inline] - fn bitand_assign(&mut self, other: $BitFlags) { - self.bits &= other.bits; - } - } - - impl $crate::_core::ops::Sub for $BitFlags { - type Output = $BitFlags; - - /// Returns the set difference of the two sets of flags. - #[inline] - fn sub(self, other: $BitFlags) -> $BitFlags { - $BitFlags { bits: self.bits & !other.bits } - } - } - - impl $crate::_core::ops::SubAssign for $BitFlags { - - /// Disables all flags enabled in the set. - #[inline] - fn sub_assign(&mut self, other: $BitFlags) { - self.bits &= !other.bits; - } - } - - impl $crate::_core::ops::Not for $BitFlags { - type Output = $BitFlags; - - /// Returns the complement of this set of flags. - #[inline] - fn not(self) -> $BitFlags { - $BitFlags { bits: !self.bits } & $BitFlags::all() - } - } - - impl $crate::_core::iter::Extend<$BitFlags> for $BitFlags { - fn extend>(&mut self, iterator: T) { - for item in iterator { - self.insert(item) - } - } - } - - impl $crate::_core::iter::FromIterator<$BitFlags> for $BitFlags { - fn from_iter>(iterator: T) -> $BitFlags { - let mut result = Self::empty(); - result.extend(iterator); - result - } - } - }; - - // Every attribute that the user writes on a const is applied to the - // corresponding const that we generate, but within the implementation of - // Debug and all() we want to ignore everything but #[cfg] attributes. In - // particular, including a #[deprecated] attribute on those items would fail - // to compile. - // https://github.com/bitflags/bitflags/issues/109 - // - // Input: - // - // ? #[cfg(feature = "advanced")] - // ? #[deprecated(note = "Use somthing else.")] - // ? #[doc = r"High quality documentation."] - // fn f() -> i32 { /* ... */ } - // - // Output: - // - // #[cfg(feature = "advanced")] - // fn f() -> i32 { /* ... */ } - ( - $(#[$filtered:meta])* - ? #[cfg $($cfgargs:tt)*] - $(? #[$rest:ident $($restargs:tt)*])* - fn $($item:tt)* - ) => { - __impl_bitflags! { - $(#[$filtered])* - #[cfg $($cfgargs)*] - $(? #[$rest $($restargs)*])* - fn $($item)* - } - }; - ( - $(#[$filtered:meta])* - // $next != `cfg` - ? #[$next:ident $($nextargs:tt)*] - $(? #[$rest:ident $($restargs:tt)*])* - fn $($item:tt)* - ) => { - __impl_bitflags! { - $(#[$filtered])* - // $next filtered out - $(? #[$rest $($restargs)*])* - fn $($item)* - } - }; - ( - $(#[$filtered:meta])* - fn $($item:tt)* - ) => { - $(#[$filtered])* - fn $($item)* - }; -} - -// Same as std::stringify but callable from __impl_bitflags, which needs to use -// local_inner_macros so can only directly call macros from this crate. -#[macro_export] -#[doc(hidden)] -macro_rules! __bitflags_stringify { - ($s:ident) => { - stringify!($s) - }; -} - -#[cfg(feature = "example_generated")] -pub mod example_generated; - -#[cfg(test)] -mod tests { - use std::collections::hash_map::DefaultHasher; - use std::hash::{Hash, Hasher}; - - bitflags! { - #[doc = "> The first principle is that you must not fool yourself — and"] - #[doc = "> you are the easiest person to fool."] - #[doc = "> "] - #[doc = "> - Richard Feynman"] - struct Flags: u32 { - const A = 0b00000001; - #[doc = " macros are way better at generating code than trans is"] - const B = 0b00000010; - const C = 0b00000100; - #[doc = "* cmr bed"] - #[doc = "* strcat table"] - #[doc = " wait what?"] - const ABC = Self::A.bits | Self::B.bits | Self::C.bits; - } - } - - bitflags! { - struct _CfgFlags: u32 { - #[cfg(windows)] - const _CFG_A = 0b01; - #[cfg(unix)] - const _CFG_B = 0b01; - #[cfg(windows)] - const _CFG_C = _CFG_A.bits | 0b10; - } - } - - bitflags! { - struct AnotherSetOfFlags: i8 { - const ANOTHER_FLAG = -1_i8; - } - } - - bitflags! { - struct LongFlags: u32 { - const LONG_A = 0b1111111111111111; - } - } - - #[test] - fn test_bits() { - assert_eq!(Flags::empty().bits(), 0b00000000); - assert_eq!(Flags::A.bits(), 0b00000001); - assert_eq!(Flags::ABC.bits(), 0b00000111); - - assert_eq!(AnotherSetOfFlags::empty().bits(), 0b00); - assert_eq!(AnotherSetOfFlags::ANOTHER_FLAG.bits(), !0_i8); - } - - #[test] - fn test_from_bits() { - assert_eq!(Flags::from_bits(0), Some(Flags::empty())); - assert_eq!(Flags::from_bits(0b1), Some(Flags::A)); - assert_eq!(Flags::from_bits(0b10), Some(Flags::B)); - assert_eq!(Flags::from_bits(0b11), Some(Flags::A | Flags::B)); - assert_eq!(Flags::from_bits(0b1000), None); - - assert_eq!( - AnotherSetOfFlags::from_bits(!0_i8), - Some(AnotherSetOfFlags::ANOTHER_FLAG) - ); - } - - #[test] - fn test_from_bits_truncate() { - assert_eq!(Flags::from_bits_truncate(0), Flags::empty()); - assert_eq!(Flags::from_bits_truncate(0b1), Flags::A); - assert_eq!(Flags::from_bits_truncate(0b10), Flags::B); - assert_eq!(Flags::from_bits_truncate(0b11), (Flags::A | Flags::B)); - assert_eq!(Flags::from_bits_truncate(0b1000), Flags::empty()); - assert_eq!(Flags::from_bits_truncate(0b1001), Flags::A); - - assert_eq!( - AnotherSetOfFlags::from_bits_truncate(0_i8), - AnotherSetOfFlags::empty() - ); - } - - #[test] - fn test_is_empty() { - assert!(Flags::empty().is_empty()); - assert!(!Flags::A.is_empty()); - assert!(!Flags::ABC.is_empty()); - - assert!(!AnotherSetOfFlags::ANOTHER_FLAG.is_empty()); - } - - #[test] - fn test_is_all() { - assert!(Flags::all().is_all()); - assert!(!Flags::A.is_all()); - assert!(Flags::ABC.is_all()); - - assert!(AnotherSetOfFlags::ANOTHER_FLAG.is_all()); - } - - #[test] - fn test_two_empties_do_not_intersect() { - let e1 = Flags::empty(); - let e2 = Flags::empty(); - assert!(!e1.intersects(e2)); - - assert!(AnotherSetOfFlags::ANOTHER_FLAG.intersects(AnotherSetOfFlags::ANOTHER_FLAG)); - } - - #[test] - fn test_empty_does_not_intersect_with_full() { - let e1 = Flags::empty(); - let e2 = Flags::ABC; - assert!(!e1.intersects(e2)); - } - - #[test] - fn test_disjoint_intersects() { - let e1 = Flags::A; - let e2 = Flags::B; - assert!(!e1.intersects(e2)); - } - - #[test] - fn test_overlapping_intersects() { - let e1 = Flags::A; - let e2 = Flags::A | Flags::B; - assert!(e1.intersects(e2)); - } - - #[test] - fn test_contains() { - let e1 = Flags::A; - let e2 = Flags::A | Flags::B; - assert!(!e1.contains(e2)); - assert!(e2.contains(e1)); - assert!(Flags::ABC.contains(e2)); - - assert!(AnotherSetOfFlags::ANOTHER_FLAG.contains(AnotherSetOfFlags::ANOTHER_FLAG)); - } - - #[test] - fn test_insert() { - let mut e1 = Flags::A; - let e2 = Flags::A | Flags::B; - e1.insert(e2); - assert_eq!(e1, e2); - - let mut e3 = AnotherSetOfFlags::empty(); - e3.insert(AnotherSetOfFlags::ANOTHER_FLAG); - assert_eq!(e3, AnotherSetOfFlags::ANOTHER_FLAG); - } - - #[test] - fn test_remove() { - let mut e1 = Flags::A | Flags::B; - let e2 = Flags::A | Flags::C; - e1.remove(e2); - assert_eq!(e1, Flags::B); - - let mut e3 = AnotherSetOfFlags::ANOTHER_FLAG; - e3.remove(AnotherSetOfFlags::ANOTHER_FLAG); - assert_eq!(e3, AnotherSetOfFlags::empty()); - } - - #[test] - fn test_operators() { - let e1 = Flags::A | Flags::C; - let e2 = Flags::B | Flags::C; - assert_eq!((e1 | e2), Flags::ABC); // union - assert_eq!((e1 & e2), Flags::C); // intersection - assert_eq!((e1 - e2), Flags::A); // set difference - assert_eq!(!e2, Flags::A); // set complement - assert_eq!(e1 ^ e2, Flags::A | Flags::B); // toggle - let mut e3 = e1; - e3.toggle(e2); - assert_eq!(e3, Flags::A | Flags::B); - - let mut m4 = AnotherSetOfFlags::empty(); - m4.toggle(AnotherSetOfFlags::empty()); - assert_eq!(m4, AnotherSetOfFlags::empty()); - } - - #[test] - fn test_set() { - let mut e1 = Flags::A | Flags::C; - e1.set(Flags::B, true); - e1.set(Flags::C, false); - - assert_eq!(e1, Flags::A | Flags::B); - } - - #[test] - fn test_assignment_operators() { - let mut m1 = Flags::empty(); - let e1 = Flags::A | Flags::C; - // union - m1 |= Flags::A; - assert_eq!(m1, Flags::A); - // intersection - m1 &= e1; - assert_eq!(m1, Flags::A); - // set difference - m1 -= m1; - assert_eq!(m1, Flags::empty()); - // toggle - m1 ^= e1; - assert_eq!(m1, e1); - } - - #[test] - fn test_extend() { - let mut flags; - - flags = Flags::empty(); - flags.extend([].iter().cloned()); - assert_eq!(flags, Flags::empty()); - - flags = Flags::empty(); - flags.extend([Flags::A, Flags::B].iter().cloned()); - assert_eq!(flags, Flags::A | Flags::B); - - flags = Flags::A; - flags.extend([Flags::A, Flags::B].iter().cloned()); - assert_eq!(flags, Flags::A | Flags::B); - - flags = Flags::B; - flags.extend([Flags::A, Flags::ABC].iter().cloned()); - assert_eq!(flags, Flags::ABC); - } - - #[test] - fn test_from_iterator() { - assert_eq!([].iter().cloned().collect::(), Flags::empty()); - assert_eq!( - [Flags::A, Flags::B].iter().cloned().collect::(), - Flags::A | Flags::B - ); - assert_eq!( - [Flags::A, Flags::ABC].iter().cloned().collect::(), - Flags::ABC - ); - } - - #[test] - fn test_lt() { - let mut a = Flags::empty(); - let mut b = Flags::empty(); - - assert!(!(a < b) && !(b < a)); - b = Flags::B; - assert!(a < b); - a = Flags::C; - assert!(!(a < b) && b < a); - b = Flags::C | Flags::B; - assert!(a < b); - } - - #[test] - fn test_ord() { - let mut a = Flags::empty(); - let mut b = Flags::empty(); - - assert!(a <= b && a >= b); - a = Flags::A; - assert!(a > b && a >= b); - assert!(b < a && b <= a); - b = Flags::B; - assert!(b > a && b >= a); - assert!(a < b && a <= b); - } - - fn hash(t: &T) -> u64 { - let mut s = DefaultHasher::new(); - t.hash(&mut s); - s.finish() - } - - #[test] - fn test_hash() { - let mut x = Flags::empty(); - let mut y = Flags::empty(); - assert_eq!(hash(&x), hash(&y)); - x = Flags::all(); - y = Flags::ABC; - assert_eq!(hash(&x), hash(&y)); - } - - #[test] - fn test_debug() { - assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); - assert_eq!(format!("{:?}", Flags::empty()), "(empty)"); - assert_eq!(format!("{:?}", Flags::ABC), "A | B | C | ABC"); - } - - #[test] - fn test_binary() { - assert_eq!(format!("{:b}", Flags::ABC), "111"); - assert_eq!(format!("{:#b}", Flags::ABC), "0b111"); - } - - #[test] - fn test_octal() { - assert_eq!(format!("{:o}", LongFlags::LONG_A), "177777"); - assert_eq!(format!("{:#o}", LongFlags::LONG_A), "0o177777"); - } - - #[test] - fn test_lowerhex() { - assert_eq!(format!("{:x}", LongFlags::LONG_A), "ffff"); - assert_eq!(format!("{:#x}", LongFlags::LONG_A), "0xffff"); - } - - #[test] - fn test_upperhex() { - assert_eq!(format!("{:X}", LongFlags::LONG_A), "FFFF"); - assert_eq!(format!("{:#X}", LongFlags::LONG_A), "0xFFFF"); - } - - mod submodule { - bitflags! { - pub struct PublicFlags: i8 { - const X = 0; - } - } - bitflags! { - struct PrivateFlags: i8 { - const Y = 0; - } - } - - #[test] - fn test_private() { - let _ = PrivateFlags::Y; - } - } - - #[test] - fn test_public() { - let _ = submodule::PublicFlags::X; - } - - mod t1 { - mod foo { - pub type Bar = i32; - } - - bitflags! { - /// baz - struct Flags: foo::Bar { - const A = 0b00000001; - #[cfg(foo)] - const B = 0b00000010; - #[cfg(foo)] - const C = 0b00000010; - } - } - } - - #[test] - fn test_in_function() { - bitflags! { - struct Flags: u8 { - const A = 1; - #[cfg(any())] // false - const B = 2; - } - } - assert_eq!(Flags::all(), Flags::A); - assert_eq!(format!("{:?}", Flags::A), "A"); - } - - #[test] - fn test_deprecated() { - bitflags! { - pub struct TestFlags: u32 { - #[deprecated(note = "Use something else.")] - const ONE = 1; - } - } - } - - #[test] - fn test_pub_crate() { - mod module { - bitflags! { - pub (crate) struct Test: u8 { - const FOO = 1; - } - } - } - - assert_eq!(module::Test::FOO.bits(), 1); - } - - #[test] - fn test_pub_in_module() { - mod module { - mod submodule { - bitflags! { - // `pub (in super)` means only the module `module` will - // be able to access this. - pub (in super) struct Test: u8 { - const FOO = 1; - } - } - } - - mod test { - // Note: due to `pub (in super)`, - // this cannot be accessed directly by the testing code. - pub(super) fn value() -> u8 { - super::submodule::Test::FOO.bits() - } - } - - pub fn value() -> u8 { - test::value() - } - } - - assert_eq!(module::value(), 1) - } - - #[test] - fn test_zero_value_flags() { - bitflags! { - struct Flags: u32 { - const NONE = 0b0; - const SOME = 0b1; - } - } - - assert!(Flags::empty().contains(Flags::NONE)); - assert!(Flags::SOME.contains(Flags::NONE)); - assert!(Flags::NONE.is_empty()); - - assert_eq!(format!("{:?}", Flags::empty()), "NONE"); - assert_eq!(format!("{:?}", Flags::SOME), "SOME"); - } -} +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A typesafe bitmask flag generator useful for sets of C-style bitmask flags. +//! It can be used for creating typesafe wrappers around C APIs. +//! +//! The `bitflags!` macro generates a `struct` that manages a set of flags. The +//! flags should only be defined for integer types, otherwise unexpected type +//! errors may occur at compile time. +//! +//! # Example +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! bitflags! { +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! const C = 0b00000100; +//! const ABC = Self::A.bits | Self::B.bits | Self::C.bits; +//! } +//! } +//! +//! fn main() { +//! let e1 = Flags::A | Flags::C; +//! let e2 = Flags::B | Flags::C; +//! assert_eq!((e1 | e2), Flags::ABC); // union +//! assert_eq!((e1 & e2), Flags::C); // intersection +//! assert_eq!((e1 - e2), Flags::A); // set difference +//! assert_eq!(!e2, Flags::A); // set complement +//! } +//! ``` +//! +//! See [`example_generated::Flags`](./example_generated/struct.Flags.html) for documentation of code +//! generated by the above `bitflags!` expansion. +//! +//! The generated `struct`s can also be extended with type and trait +//! implementations: +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! use std::fmt; +//! +//! bitflags! { +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! } +//! } +//! +//! impl Flags { +//! pub fn clear(&mut self) { +//! self.bits = 0; // The `bits` field can be accessed from within the +//! // same module where the `bitflags!` macro was invoked. +//! } +//! } +//! +//! impl fmt::Display for Flags { +//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +//! write!(f, "hi!") +//! } +//! } +//! +//! fn main() { +//! let mut flags = Flags::A | Flags::B; +//! flags.clear(); +//! assert!(flags.is_empty()); +//! assert_eq!(format!("{}", flags), "hi!"); +//! assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); +//! assert_eq!(format!("{:?}", Flags::B), "B"); +//! } +//! ``` +//! +//! # Visibility +//! +//! The generated struct and its associated flag constants are not exported +//! out of the current module by default. A definition can be exported out of +//! the current module by adding `pub` before `flags`: +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! mod example { +//! bitflags! { +//! pub struct Flags1: u32 { +//! const A = 0b00000001; +//! } +//! } +//! bitflags! { +//! # pub +//! struct Flags2: u32 { +//! const B = 0b00000010; +//! } +//! } +//! } +//! +//! fn main() { +//! let flag1 = example::Flags1::A; +//! let flag2 = example::Flags2::B; // error: const `B` is private +//! } +//! ``` +//! +//! # Attributes +//! +//! Attributes can be attached to the generated `struct` by placing them +//! before the `flags` keyword. +//! +//! # Trait implementations +//! +//! The `Copy`, `Clone`, `PartialEq`, `Eq`, `PartialOrd`, `Ord` and `Hash` +//! traits automatically derived for the `struct` using the `derive` attribute. +//! Additional traits can be derived by providing an explicit `derive` +//! attribute on `flags`. +//! +//! The `Extend` and `FromIterator` traits are implemented for the `struct`, +//! too: `Extend` adds the union of the instances of the `struct` iterated over, +//! while `FromIterator` calculates the union. +//! +//! The `Binary`, `Debug`, `LowerExp`, `Octal` and `UpperExp` trait is also +//! implemented by displaying the bits value of the internal struct. +//! +//! ## Operators +//! +//! The following operator traits are implemented for the generated `struct`: +//! +//! - `BitOr` and `BitOrAssign`: union +//! - `BitAnd` and `BitAndAssign`: intersection +//! - `BitXor` and `BitXorAssign`: toggle +//! - `Sub` and `SubAssign`: set difference +//! - `Not`: set complement +//! +//! # Methods +//! +//! The following methods are defined for the generated `struct`: +//! +//! - `empty`: an empty set of flags +//! - `all`: the set of all flags +//! - `bits`: the raw value of the flags currently stored +//! - `from_bits`: convert from underlying bit representation, unless that +//! representation contains bits that do not correspond to a flag +//! - `from_bits_truncate`: convert from underlying bit representation, dropping +//! any bits that do not correspond to flags +//! - `is_empty`: `true` if no flags are currently stored +//! - `is_all`: `true` if all flags are currently set +//! - `intersects`: `true` if there are flags common to both `self` and `other` +//! - `contains`: `true` all of the flags in `other` are contained within `self` +//! - `insert`: inserts the specified flags in-place +//! - `remove`: removes the specified flags in-place +//! - `toggle`: the specified flags will be inserted if not present, and removed +//! if they are. +//! - `set`: inserts or removes the specified flags depending on the passed value +//! +//! ## Default +//! +//! The `Default` trait is not automatically implemented for the generated struct. +//! +//! If your default value is equal to `0` (which is the same value as calling `empty()` +//! on the generated struct), you can simply derive `Default`: +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! bitflags! { +//! // Results in default value with bits: 0 +//! #[derive(Default)] +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! const C = 0b00000100; +//! } +//! } +//! +//! fn main() { +//! let derived_default: Flags = Default::default(); +//! assert_eq!(derived_default.bits(), 0); +//! } +//! ``` +//! +//! If your default value is not equal to `0` you need to implement `Default` yourself: +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! bitflags! { +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! const C = 0b00000100; +//! } +//! } +//! +//! // explicit `Default` implementation +//! impl Default for Flags { +//! fn default() -> Flags { +//! Flags::A | Flags::C +//! } +//! } +//! +//! fn main() { +//! let implemented_default: Flags = Default::default(); +//! assert_eq!(implemented_default, (Flags::A | Flags::C)); +//! } +//! ``` +//! +//! # Zero Flags +//! +//! Flags with a value equal to zero will have some strange behavior that one should be aware of. +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! bitflags! { +//! struct Flags: u32 { +//! const NONE = 0b00000000; +//! const SOME = 0b00000001; +//! } +//! } +//! +//! fn main() { +//! let empty = Flags::empty(); +//! let none = Flags::NONE; +//! let some = Flags::SOME; +//! +//! // Zero flags are treated as always present +//! assert!(empty.contains(Flags::NONE)); +//! assert!(none.contains(Flags::NONE)); +//! assert!(some.contains(Flags::NONE)); +//! +//! // Zero flags will be ignored when testing for emptiness +//! assert!(none.is_empty()); +//! } +//! ``` + +#![no_std] +#![doc(html_root_url = "https://docs.rs/bitflags/1.1.0")] + +#[cfg(test)] +#[macro_use] +extern crate std; + +// Re-export libcore using an alias so that the macros can work without +// requiring `extern crate core` downstream. +#[doc(hidden)] +pub extern crate core as _core; + +/// The macro used to generate the flag structure. +/// +/// See the [crate level docs](../bitflags/index.html) for complete documentation. +/// +/// # Example +/// +/// ``` +/// #[macro_use] +/// extern crate bitflags; +/// +/// bitflags! { +/// struct Flags: u32 { +/// const A = 0b00000001; +/// const B = 0b00000010; +/// const C = 0b00000100; +/// const ABC = Self::A.bits | Self::B.bits | Self::C.bits; +/// } +/// } +/// +/// fn main() { +/// let e1 = Flags::A | Flags::C; +/// let e2 = Flags::B | Flags::C; +/// assert_eq!((e1 | e2), Flags::ABC); // union +/// assert_eq!((e1 & e2), Flags::C); // intersection +/// assert_eq!((e1 - e2), Flags::A); // set difference +/// assert_eq!(!e2, Flags::A); // set complement +/// } +/// ``` +/// +/// The generated `struct`s can also be extended with type and trait +/// implementations: +/// +/// ``` +/// #[macro_use] +/// extern crate bitflags; +/// +/// use std::fmt; +/// +/// bitflags! { +/// struct Flags: u32 { +/// const A = 0b00000001; +/// const B = 0b00000010; +/// } +/// } +/// +/// impl Flags { +/// pub fn clear(&mut self) { +/// self.bits = 0; // The `bits` field can be accessed from within the +/// // same module where the `bitflags!` macro was invoked. +/// } +/// } +/// +/// impl fmt::Display for Flags { +/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// write!(f, "hi!") +/// } +/// } +/// +/// fn main() { +/// let mut flags = Flags::A | Flags::B; +/// flags.clear(); +/// assert!(flags.is_empty()); +/// assert_eq!(format!("{}", flags), "hi!"); +/// assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); +/// assert_eq!(format!("{:?}", Flags::B), "B"); +/// } +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! bitflags { + ( + $(#[$outer:meta])* + pub struct $BitFlags:ident: $T:ty { + $( + $(#[$inner:ident $($args:tt)*])* + const $Flag:ident = $value:expr; + )+ + } + ) => { + __bitflags! { + $(#[$outer])* + (pub) $BitFlags: $T { + $( + $(#[$inner $($args)*])* + $Flag = $value; + )+ + } + } + }; + ( + $(#[$outer:meta])* + struct $BitFlags:ident: $T:ty { + $( + $(#[$inner:ident $($args:tt)*])* + const $Flag:ident = $value:expr; + )+ + } + ) => { + __bitflags! { + $(#[$outer])* + () $BitFlags: $T { + $( + $(#[$inner $($args)*])* + $Flag = $value; + )+ + } + } + }; + ( + $(#[$outer:meta])* + pub ($($vis:tt)+) struct $BitFlags:ident: $T:ty { + $( + $(#[$inner:ident $($args:tt)*])* + const $Flag:ident = $value:expr; + )+ + } + ) => { + __bitflags! { + $(#[$outer])* + (pub ($($vis)+)) $BitFlags: $T { + $( + $(#[$inner $($args)*])* + $Flag = $value; + )+ + } + } + }; +} + +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __bitflags { + ( + $(#[$outer:meta])* + ($($vis:tt)*) $BitFlags:ident: $T:ty { + $( + $(#[$inner:ident $($args:tt)*])* + $Flag:ident = $value:expr; + )+ + } + ) => { + $(#[$outer])* + #[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)] + $($vis)* struct $BitFlags { + bits: $T, + } + + __impl_bitflags! { + $BitFlags: $T { + $( + $(#[$inner $($args)*])* + $Flag = $value; + )+ + } + } + }; +} + +#[macro_export(local_inner_macros)] +#[doc(hidden)] +#[cfg(bitflags_const_fn)] +macro_rules! __fn_bitflags { + ( + $(# $attr_args:tt)* + const fn $($item:tt)* + ) => { + $(# $attr_args)* + const fn $($item)* + }; + ( + $(# $attr_args:tt)* + pub const fn $($item:tt)* + ) => { + $(# $attr_args)* + pub const fn $($item)* + }; +} + +#[macro_export(local_inner_macros)] +#[doc(hidden)] +#[cfg(not(bitflags_const_fn))] +macro_rules! __fn_bitflags { + ( + $(# $attr_args:tt)* + const fn $($item:tt)* + ) => { + $(# $attr_args)* + fn $($item)* + }; + ( + $(# $attr_args:tt)* + pub const fn $($item:tt)* + ) => { + $(# $attr_args)* + pub fn $($item)* + }; +} + +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __impl_bitflags { + ( + $BitFlags:ident: $T:ty { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident = $value:expr; + )+ + } + ) => { + impl $crate::_core::fmt::Debug for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + // This convoluted approach is to handle #[cfg]-based flag + // omission correctly. For example it needs to support: + // + // #[cfg(unix)] const A: Flag = /* ... */; + // #[cfg(windows)] const B: Flag = /* ... */; + + // Unconditionally define a check for every flag, even disabled + // ones. + #[allow(non_snake_case)] + trait __BitFlags { + $( + #[inline] + fn $Flag(&self) -> bool { false } + )+ + } + + // Conditionally override the check for just those flags that + // are not #[cfg]ed away. + impl __BitFlags for $BitFlags { + $( + __impl_bitflags! { + #[allow(deprecated)] + #[inline] + $(? #[$attr $($args)*])* + fn $Flag(&self) -> bool { + if Self::$Flag.bits == 0 && self.bits != 0 { + false + } else { + self.bits & Self::$Flag.bits == Self::$Flag.bits + } + } + } + )+ + } + + let mut first = true; + $( + if <$BitFlags as __BitFlags>::$Flag(self) { + if !first { + f.write_str(" | ")?; + } + first = false; + f.write_str(__bitflags_stringify!($Flag))?; + } + )+ + if first { + f.write_str("(empty)")?; + } + Ok(()) + } + } + impl $crate::_core::fmt::Binary for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + $crate::_core::fmt::Binary::fmt(&self.bits, f) + } + } + impl $crate::_core::fmt::Octal for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + $crate::_core::fmt::Octal::fmt(&self.bits, f) + } + } + impl $crate::_core::fmt::LowerHex for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + $crate::_core::fmt::LowerHex::fmt(&self.bits, f) + } + } + impl $crate::_core::fmt::UpperHex for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + $crate::_core::fmt::UpperHex::fmt(&self.bits, f) + } + } + + #[allow(dead_code)] + impl $BitFlags { + $( + $(#[$attr $($args)*])* + pub const $Flag: $BitFlags = $BitFlags { bits: $value }; + )+ + + __fn_bitflags! { + /// Returns an empty set of flags + #[inline] + pub const fn empty() -> $BitFlags { + $BitFlags { bits: 0 } + } + } + + __fn_bitflags! { + /// Returns the set containing all flags. + #[inline] + pub const fn all() -> $BitFlags { + // See `Debug::fmt` for why this approach is taken. + #[allow(non_snake_case)] + trait __BitFlags { + $( + #[inline] + const $Flag: $T = 0; + )+ + } + impl __BitFlags for $BitFlags { + $( + __impl_bitflags! { + #[allow(deprecated)] + #[inline] + $(? #[$attr $($args)*])* + const $Flag: $T = Self::$Flag.bits; + } + )+ + } + $BitFlags { bits: $(<$BitFlags as __BitFlags>::$Flag)|+ } + } + } + + __fn_bitflags! { + /// Returns the raw value of the flags currently stored. + #[inline] + pub const fn bits(&self) -> $T { + self.bits + } + } + + /// Convert from underlying bit representation, unless that + /// representation contains bits that do not correspond to a flag. + #[inline] + pub fn from_bits(bits: $T) -> $crate::_core::option::Option<$BitFlags> { + if (bits & !$BitFlags::all().bits()) == 0 { + $crate::_core::option::Option::Some($BitFlags { bits }) + } else { + $crate::_core::option::Option::None + } + } + + __fn_bitflags! { + /// Convert from underlying bit representation, dropping any bits + /// that do not correspond to flags. + #[inline] + pub const fn from_bits_truncate(bits: $T) -> $BitFlags { + $BitFlags { bits: bits & $BitFlags::all().bits } + } + } + + __fn_bitflags! { + /// Returns `true` if no flags are currently stored. + #[inline] + pub const fn is_empty(&self) -> bool { + self.bits() == $BitFlags::empty().bits() + } + } + + __fn_bitflags! { + /// Returns `true` if all flags are currently set. + #[inline] + pub const fn is_all(&self) -> bool { + self.bits == $BitFlags::all().bits + } + } + + __fn_bitflags! { + /// Returns `true` if there are flags common to both `self` and `other`. + #[inline] + pub const fn intersects(&self, other: $BitFlags) -> bool { + !$BitFlags{ bits: self.bits & other.bits}.is_empty() + } + } + + __fn_bitflags! { + /// Returns `true` all of the flags in `other` are contained within `self`. + #[inline] + pub const fn contains(&self, other: $BitFlags) -> bool { + (self.bits & other.bits) == other.bits + } + } + + /// Inserts the specified flags in-place. + #[inline] + pub fn insert(&mut self, other: $BitFlags) { + self.bits |= other.bits; + } + + /// Removes the specified flags in-place. + #[inline] + pub fn remove(&mut self, other: $BitFlags) { + self.bits &= !other.bits; + } + + /// Toggles the specified flags in-place. + #[inline] + pub fn toggle(&mut self, other: $BitFlags) { + self.bits ^= other.bits; + } + + /// Inserts or removes the specified flags depending on the passed value. + #[inline] + pub fn set(&mut self, other: $BitFlags, value: bool) { + if value { + self.insert(other); + } else { + self.remove(other); + } + } + } + + impl $crate::_core::ops::BitOr for $BitFlags { + type Output = $BitFlags; + + /// Returns the union of the two sets of flags. + #[inline] + fn bitor(self, other: $BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits | other.bits } + } + } + + impl $crate::_core::ops::BitOrAssign for $BitFlags { + + /// Adds the set of flags. + #[inline] + fn bitor_assign(&mut self, other: $BitFlags) { + self.bits |= other.bits; + } + } + + impl $crate::_core::ops::BitXor for $BitFlags { + type Output = $BitFlags; + + /// Returns the left flags, but with all the right flags toggled. + #[inline] + fn bitxor(self, other: $BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits ^ other.bits } + } + } + + impl $crate::_core::ops::BitXorAssign for $BitFlags { + + /// Toggles the set of flags. + #[inline] + fn bitxor_assign(&mut self, other: $BitFlags) { + self.bits ^= other.bits; + } + } + + impl $crate::_core::ops::BitAnd for $BitFlags { + type Output = $BitFlags; + + /// Returns the intersection between the two sets of flags. + #[inline] + fn bitand(self, other: $BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits & other.bits } + } + } + + impl $crate::_core::ops::BitAndAssign for $BitFlags { + + /// Disables all flags disabled in the set. + #[inline] + fn bitand_assign(&mut self, other: $BitFlags) { + self.bits &= other.bits; + } + } + + impl $crate::_core::ops::Sub for $BitFlags { + type Output = $BitFlags; + + /// Returns the set difference of the two sets of flags. + #[inline] + fn sub(self, other: $BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits & !other.bits } + } + } + + impl $crate::_core::ops::SubAssign for $BitFlags { + + /// Disables all flags enabled in the set. + #[inline] + fn sub_assign(&mut self, other: $BitFlags) { + self.bits &= !other.bits; + } + } + + impl $crate::_core::ops::Not for $BitFlags { + type Output = $BitFlags; + + /// Returns the complement of this set of flags. + #[inline] + fn not(self) -> $BitFlags { + $BitFlags { bits: !self.bits } & $BitFlags::all() + } + } + + impl $crate::_core::iter::Extend<$BitFlags> for $BitFlags { + fn extend>(&mut self, iterator: T) { + for item in iterator { + self.insert(item) + } + } + } + + impl $crate::_core::iter::FromIterator<$BitFlags> for $BitFlags { + fn from_iter>(iterator: T) -> $BitFlags { + let mut result = Self::empty(); + result.extend(iterator); + result + } + } + }; + + // Every attribute that the user writes on a const is applied to the + // corresponding const that we generate, but within the implementation of + // Debug and all() we want to ignore everything but #[cfg] attributes. In + // particular, including a #[deprecated] attribute on those items would fail + // to compile. + // https://github.com/bitflags/bitflags/issues/109 + // + // Input: + // + // ? #[cfg(feature = "advanced")] + // ? #[deprecated(note = "Use somthing else.")] + // ? #[doc = r"High quality documentation."] + // fn f() -> i32 { /* ... */ } + // + // Output: + // + // #[cfg(feature = "advanced")] + // fn f() -> i32 { /* ... */ } + ( + $(#[$filtered:meta])* + ? #[cfg $($cfgargs:tt)*] + $(? #[$rest:ident $($restargs:tt)*])* + fn $($item:tt)* + ) => { + __impl_bitflags! { + $(#[$filtered])* + #[cfg $($cfgargs)*] + $(? #[$rest $($restargs)*])* + fn $($item)* + } + }; + ( + $(#[$filtered:meta])* + // $next != `cfg` + ? #[$next:ident $($nextargs:tt)*] + $(? #[$rest:ident $($restargs:tt)*])* + fn $($item:tt)* + ) => { + __impl_bitflags! { + $(#[$filtered])* + // $next filtered out + $(? #[$rest $($restargs)*])* + fn $($item)* + } + }; + ( + $(#[$filtered:meta])* + fn $($item:tt)* + ) => { + $(#[$filtered])* + fn $($item)* + }; + + // Every attribute that the user writes on a const is applied to the + // corresponding const that we generate, but within the implementation of + // Debug and all() we want to ignore everything but #[cfg] attributes. In + // particular, including a #[deprecated] attribute on those items would fail + // to compile. + // https://github.com/bitflags/bitflags/issues/109 + // + // const version + // + // Input: + // + // ? #[cfg(feature = "advanced")] + // ? #[deprecated(note = "Use somthing else.")] + // ? #[doc = r"High quality documentation."] + // const f: i32 { /* ... */ } + // + // Output: + // + // #[cfg(feature = "advanced")] + // const f: i32 { /* ... */ } + ( + $(#[$filtered:meta])* + ? #[cfg $($cfgargs:tt)*] + $(? #[$rest:ident $($restargs:tt)*])* + const $($item:tt)* + ) => { + __impl_bitflags! { + $(#[$filtered])* + #[cfg $($cfgargs)*] + $(? #[$rest $($restargs)*])* + const $($item)* + } + }; + ( + $(#[$filtered:meta])* + // $next != `cfg` + ? #[$next:ident $($nextargs:tt)*] + $(? #[$rest:ident $($restargs:tt)*])* + const $($item:tt)* + ) => { + __impl_bitflags! { + $(#[$filtered])* + // $next filtered out + $(? #[$rest $($restargs)*])* + const $($item)* + } + }; + ( + $(#[$filtered:meta])* + const $($item:tt)* + ) => { + $(#[$filtered])* + const $($item)* + }; +} + +// Same as std::stringify but callable from __impl_bitflags, which needs to use +// local_inner_macros so can only directly call macros from this crate. +#[macro_export] +#[doc(hidden)] +macro_rules! __bitflags_stringify { + ($s:ident) => { + stringify!($s) + }; +} + +#[cfg(feature = "example_generated")] +pub mod example_generated; + +#[cfg(test)] +mod tests { + use std::collections::hash_map::DefaultHasher; + use std::hash::{Hash, Hasher}; + + bitflags! { + #[doc = "> The first principle is that you must not fool yourself — and"] + #[doc = "> you are the easiest person to fool."] + #[doc = "> "] + #[doc = "> - Richard Feynman"] + struct Flags: u32 { + const A = 0b00000001; + #[doc = " macros are way better at generating code than trans is"] + const B = 0b00000010; + const C = 0b00000100; + #[doc = "* cmr bed"] + #[doc = "* strcat table"] + #[doc = " wait what?"] + const ABC = Self::A.bits | Self::B.bits | Self::C.bits; + } + } + + bitflags! { + struct _CfgFlags: u32 { + #[cfg(windows)] + const _CFG_A = 0b01; + #[cfg(unix)] + const _CFG_B = 0b01; + #[cfg(windows)] + const _CFG_C = _CFG_A.bits | 0b10; + } + } + + bitflags! { + struct AnotherSetOfFlags: i8 { + const ANOTHER_FLAG = -1_i8; + } + } + + bitflags! { + struct LongFlags: u32 { + const LONG_A = 0b1111111111111111; + } + } + + #[test] + fn test_bits() { + assert_eq!(Flags::empty().bits(), 0b00000000); + assert_eq!(Flags::A.bits(), 0b00000001); + assert_eq!(Flags::ABC.bits(), 0b00000111); + + assert_eq!(AnotherSetOfFlags::empty().bits(), 0b00); + assert_eq!(AnotherSetOfFlags::ANOTHER_FLAG.bits(), !0_i8); + } + + #[test] + fn test_from_bits() { + assert_eq!(Flags::from_bits(0), Some(Flags::empty())); + assert_eq!(Flags::from_bits(0b1), Some(Flags::A)); + assert_eq!(Flags::from_bits(0b10), Some(Flags::B)); + assert_eq!(Flags::from_bits(0b11), Some(Flags::A | Flags::B)); + assert_eq!(Flags::from_bits(0b1000), None); + + assert_eq!( + AnotherSetOfFlags::from_bits(!0_i8), + Some(AnotherSetOfFlags::ANOTHER_FLAG) + ); + } + + #[test] + fn test_from_bits_truncate() { + assert_eq!(Flags::from_bits_truncate(0), Flags::empty()); + assert_eq!(Flags::from_bits_truncate(0b1), Flags::A); + assert_eq!(Flags::from_bits_truncate(0b10), Flags::B); + assert_eq!(Flags::from_bits_truncate(0b11), (Flags::A | Flags::B)); + assert_eq!(Flags::from_bits_truncate(0b1000), Flags::empty()); + assert_eq!(Flags::from_bits_truncate(0b1001), Flags::A); + + assert_eq!( + AnotherSetOfFlags::from_bits_truncate(0_i8), + AnotherSetOfFlags::empty() + ); + } + + #[test] + fn test_is_empty() { + assert!(Flags::empty().is_empty()); + assert!(!Flags::A.is_empty()); + assert!(!Flags::ABC.is_empty()); + + assert!(!AnotherSetOfFlags::ANOTHER_FLAG.is_empty()); + } + + #[test] + fn test_is_all() { + assert!(Flags::all().is_all()); + assert!(!Flags::A.is_all()); + assert!(Flags::ABC.is_all()); + + assert!(AnotherSetOfFlags::ANOTHER_FLAG.is_all()); + } + + #[test] + fn test_two_empties_do_not_intersect() { + let e1 = Flags::empty(); + let e2 = Flags::empty(); + assert!(!e1.intersects(e2)); + + assert!(AnotherSetOfFlags::ANOTHER_FLAG.intersects(AnotherSetOfFlags::ANOTHER_FLAG)); + } + + #[test] + fn test_empty_does_not_intersect_with_full() { + let e1 = Flags::empty(); + let e2 = Flags::ABC; + assert!(!e1.intersects(e2)); + } + + #[test] + fn test_disjoint_intersects() { + let e1 = Flags::A; + let e2 = Flags::B; + assert!(!e1.intersects(e2)); + } + + #[test] + fn test_overlapping_intersects() { + let e1 = Flags::A; + let e2 = Flags::A | Flags::B; + assert!(e1.intersects(e2)); + } + + #[test] + fn test_contains() { + let e1 = Flags::A; + let e2 = Flags::A | Flags::B; + assert!(!e1.contains(e2)); + assert!(e2.contains(e1)); + assert!(Flags::ABC.contains(e2)); + + assert!(AnotherSetOfFlags::ANOTHER_FLAG.contains(AnotherSetOfFlags::ANOTHER_FLAG)); + } + + #[test] + fn test_insert() { + let mut e1 = Flags::A; + let e2 = Flags::A | Flags::B; + e1.insert(e2); + assert_eq!(e1, e2); + + let mut e3 = AnotherSetOfFlags::empty(); + e3.insert(AnotherSetOfFlags::ANOTHER_FLAG); + assert_eq!(e3, AnotherSetOfFlags::ANOTHER_FLAG); + } + + #[test] + fn test_remove() { + let mut e1 = Flags::A | Flags::B; + let e2 = Flags::A | Flags::C; + e1.remove(e2); + assert_eq!(e1, Flags::B); + + let mut e3 = AnotherSetOfFlags::ANOTHER_FLAG; + e3.remove(AnotherSetOfFlags::ANOTHER_FLAG); + assert_eq!(e3, AnotherSetOfFlags::empty()); + } + + #[test] + fn test_operators() { + let e1 = Flags::A | Flags::C; + let e2 = Flags::B | Flags::C; + assert_eq!((e1 | e2), Flags::ABC); // union + assert_eq!((e1 & e2), Flags::C); // intersection + assert_eq!((e1 - e2), Flags::A); // set difference + assert_eq!(!e2, Flags::A); // set complement + assert_eq!(e1 ^ e2, Flags::A | Flags::B); // toggle + let mut e3 = e1; + e3.toggle(e2); + assert_eq!(e3, Flags::A | Flags::B); + + let mut m4 = AnotherSetOfFlags::empty(); + m4.toggle(AnotherSetOfFlags::empty()); + assert_eq!(m4, AnotherSetOfFlags::empty()); + } + + #[test] + fn test_set() { + let mut e1 = Flags::A | Flags::C; + e1.set(Flags::B, true); + e1.set(Flags::C, false); + + assert_eq!(e1, Flags::A | Flags::B); + } + + #[test] + fn test_assignment_operators() { + let mut m1 = Flags::empty(); + let e1 = Flags::A | Flags::C; + // union + m1 |= Flags::A; + assert_eq!(m1, Flags::A); + // intersection + m1 &= e1; + assert_eq!(m1, Flags::A); + // set difference + m1 -= m1; + assert_eq!(m1, Flags::empty()); + // toggle + m1 ^= e1; + assert_eq!(m1, e1); + } + + + #[cfg(bitflags_const_fn)] + #[test] + fn test_const_fn() { + const M1: Flags = Flags::empty(); + + const M2: Flags = Flags::A; + assert_eq!(M2, Flags::A); + + const M3: Flags = Flags::C; + assert_eq!(M3, Flags::C); + } + + #[test] + fn test_extend() { + let mut flags; + + flags = Flags::empty(); + flags.extend([].iter().cloned()); + assert_eq!(flags, Flags::empty()); + + flags = Flags::empty(); + flags.extend([Flags::A, Flags::B].iter().cloned()); + assert_eq!(flags, Flags::A | Flags::B); + + flags = Flags::A; + flags.extend([Flags::A, Flags::B].iter().cloned()); + assert_eq!(flags, Flags::A | Flags::B); + + flags = Flags::B; + flags.extend([Flags::A, Flags::ABC].iter().cloned()); + assert_eq!(flags, Flags::ABC); + } + + #[test] + fn test_from_iterator() { + assert_eq!([].iter().cloned().collect::(), Flags::empty()); + assert_eq!( + [Flags::A, Flags::B].iter().cloned().collect::(), + Flags::A | Flags::B + ); + assert_eq!( + [Flags::A, Flags::ABC].iter().cloned().collect::(), + Flags::ABC + ); + } + + #[test] + fn test_lt() { + let mut a = Flags::empty(); + let mut b = Flags::empty(); + + assert!(!(a < b) && !(b < a)); + b = Flags::B; + assert!(a < b); + a = Flags::C; + assert!(!(a < b) && b < a); + b = Flags::C | Flags::B; + assert!(a < b); + } + + #[test] + fn test_ord() { + let mut a = Flags::empty(); + let mut b = Flags::empty(); + + assert!(a <= b && a >= b); + a = Flags::A; + assert!(a > b && a >= b); + assert!(b < a && b <= a); + b = Flags::B; + assert!(b > a && b >= a); + assert!(a < b && a <= b); + } + + fn hash(t: &T) -> u64 { + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() + } + + #[test] + fn test_hash() { + let mut x = Flags::empty(); + let mut y = Flags::empty(); + assert_eq!(hash(&x), hash(&y)); + x = Flags::all(); + y = Flags::ABC; + assert_eq!(hash(&x), hash(&y)); + } + + #[test] + fn test_debug() { + assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); + assert_eq!(format!("{:?}", Flags::empty()), "(empty)"); + assert_eq!(format!("{:?}", Flags::ABC), "A | B | C | ABC"); + } + + #[test] + fn test_binary() { + assert_eq!(format!("{:b}", Flags::ABC), "111"); + assert_eq!(format!("{:#b}", Flags::ABC), "0b111"); + } + + #[test] + fn test_octal() { + assert_eq!(format!("{:o}", LongFlags::LONG_A), "177777"); + assert_eq!(format!("{:#o}", LongFlags::LONG_A), "0o177777"); + } + + #[test] + fn test_lowerhex() { + assert_eq!(format!("{:x}", LongFlags::LONG_A), "ffff"); + assert_eq!(format!("{:#x}", LongFlags::LONG_A), "0xffff"); + } + + #[test] + fn test_upperhex() { + assert_eq!(format!("{:X}", LongFlags::LONG_A), "FFFF"); + assert_eq!(format!("{:#X}", LongFlags::LONG_A), "0xFFFF"); + } + + mod submodule { + bitflags! { + pub struct PublicFlags: i8 { + const X = 0; + } + } + bitflags! { + struct PrivateFlags: i8 { + const Y = 0; + } + } + + #[test] + fn test_private() { + let _ = PrivateFlags::Y; + } + } + + #[test] + fn test_public() { + let _ = submodule::PublicFlags::X; + } + + mod t1 { + mod foo { + pub type Bar = i32; + } + + bitflags! { + /// baz + struct Flags: foo::Bar { + const A = 0b00000001; + #[cfg(foo)] + const B = 0b00000010; + #[cfg(foo)] + const C = 0b00000010; + } + } + } + + #[test] + fn test_in_function() { + bitflags! { + struct Flags: u8 { + const A = 1; + #[cfg(any())] // false + const B = 2; + } + } + assert_eq!(Flags::all(), Flags::A); + assert_eq!(format!("{:?}", Flags::A), "A"); + } + + #[test] + fn test_deprecated() { + bitflags! { + pub struct TestFlags: u32 { + #[deprecated(note = "Use something else.")] + const ONE = 1; + } + } + } + + #[test] + fn test_pub_crate() { + mod module { + bitflags! { + pub (crate) struct Test: u8 { + const FOO = 1; + } + } + } + + assert_eq!(module::Test::FOO.bits(), 1); + } + + #[test] + fn test_pub_in_module() { + mod module { + mod submodule { + bitflags! { + // `pub (in super)` means only the module `module` will + // be able to access this. + pub (in super) struct Test: u8 { + const FOO = 1; + } + } + } + + mod test { + // Note: due to `pub (in super)`, + // this cannot be accessed directly by the testing code. + pub(super) fn value() -> u8 { + super::submodule::Test::FOO.bits() + } + } + + pub fn value() -> u8 { + test::value() + } + } + + assert_eq!(module::value(), 1) + } + + #[test] + fn test_zero_value_flags() { + bitflags! { + struct Flags: u32 { + const NONE = 0b0; + const SOME = 0b1; + } + } + + assert!(Flags::empty().contains(Flags::NONE)); + assert!(Flags::SOME.contains(Flags::NONE)); + assert!(Flags::NONE.is_empty()); + + assert_eq!(format!("{:?}", Flags::empty()), "NONE"); + assert_eq!(format!("{:?}", Flags::SOME), "SOME"); + } +} diff --git a/vmm/Cargo.toml b/vmm/Cargo.toml index 803344634..3206bc328 100755 --- a/vmm/Cargo.toml +++ b/vmm/Cargo.toml @@ -15,11 +15,14 @@ log = "*" net_util = { path = "../net_util" } pci = {path = "../pci"} qcow = { path = "../qcow" } -linux-loader = { git = "https://github.com/bjzhjing/linux-loader" } vm-virtio = { path = "../vm-virtio" } vm-allocator = { path = "../vm-allocator" } 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] git = "https://github.com/rust-vmm/vm-memory" features = ["backend-mmap"]