commit
f8e425b378
4
.gitignore
vendored
4
.gitignore
vendored
@ -1 +1,3 @@
|
||||
/target
|
||||
syntax: glob
|
||||
|
||||
/target/
|
||||
|
219
Cargo.lock
generated
219
Cargo.lock
generated
@ -84,9 +84,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.8.0"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
|
||||
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
@ -103,17 +103,11 @@ version = "3.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.13"
|
||||
version = "1.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda"
|
||||
checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
@ -261,9 +255,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.11"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
|
||||
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
@ -298,15 +292,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.13.0"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
@ -315,7 +309,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -336,14 +330,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
|
||||
checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasi",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -389,9 +383,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.7.1"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
|
||||
checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
@ -405,9 +399,9 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.14"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
||||
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
@ -439,9 +433,9 @@ checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.25"
|
||||
version = "0.4.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
|
||||
checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
|
||||
|
||||
[[package]]
|
||||
name = "md-5"
|
||||
@ -521,9 +515,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.3"
|
||||
version = "1.21.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
|
||||
checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc"
|
||||
|
||||
[[package]]
|
||||
name = "os_display"
|
||||
@ -600,11 +594,11 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.20"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
|
||||
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
||||
dependencies = [
|
||||
"zerocopy 0.7.35",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -619,9 +613,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.93"
|
||||
version = "1.0.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
|
||||
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@ -650,13 +644,19 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.38"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
|
||||
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "5.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
@ -673,8 +673,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
|
||||
dependencies = [
|
||||
"rand_chacha",
|
||||
"rand_core 0.9.0",
|
||||
"zerocopy 0.8.17",
|
||||
"rand_core 0.9.3",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -684,7 +684,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.9.0",
|
||||
"rand_core 0.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -695,14 +695,19 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.0"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff"
|
||||
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"zerocopy 0.8.17",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rangemap"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684"
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.10.0"
|
||||
@ -777,33 +782,33 @@ dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.15",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.0.0"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17f8dcd64f141950290e45c99f7710ede1b600297c91818bb30b3667c0f45dc0"
|
||||
checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.9.3",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.19"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
|
||||
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.19"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
|
||||
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
@ -874,15 +879,21 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.98"
|
||||
version = "2.0.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
|
||||
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syscall-numbers"
|
||||
version = "4.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e88dcf8be2fd556b3cebd02689c424dced834317c7e38328eadfcfcab00b785"
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.33.1"
|
||||
@ -906,17 +917,17 @@ dependencies = [
|
||||
"fastrand",
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"rustix 1.0.0",
|
||||
"windows-sys 0.52.0",
|
||||
"rustix 1.0.3",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "terminal_size"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9"
|
||||
checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed"
|
||||
dependencies = [
|
||||
"rustix 0.38.44",
|
||||
"rustix 1.0.3",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
@ -933,10 +944,30 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.37"
|
||||
name = "thiserror"
|
||||
version = "2.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21"
|
||||
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d9c75b47bdff86fa3334a3db91356b8d7d86a9b839dab7d0bdc5c3d3a077618"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa",
|
||||
@ -951,15 +982,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.2"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
||||
checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.19"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de"
|
||||
checksum = "29aa485584182073ed57fd5004aa09c371f021325014694e432313345865fd04"
|
||||
dependencies = [
|
||||
"num-conv",
|
||||
"time-core",
|
||||
@ -973,9 +1004,9 @@ checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.16"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-linebreak"
|
||||
@ -1023,6 +1054,7 @@ dependencies = [
|
||||
"tempfile",
|
||||
"textwrap",
|
||||
"uu_blockdev",
|
||||
"uu_chcpu",
|
||||
"uu_ctrlaltdel",
|
||||
"uu_dmesg",
|
||||
"uu_fsfreeze",
|
||||
@ -1051,6 +1083,18 @@ dependencies = [
|
||||
"uucore",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uu_chcpu"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"libc",
|
||||
"rangemap",
|
||||
"syscall-numbers",
|
||||
"thiserror",
|
||||
"uucore",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uu_ctrlaltdel"
|
||||
version = "0.0.1"
|
||||
@ -1223,9 +1267,9 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.13.3+wasi-0.2.2"
|
||||
version = "0.14.2+wasi-0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
|
||||
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
|
||||
dependencies = [
|
||||
"wit-bindgen-rt",
|
||||
]
|
||||
@ -1374,9 +1418,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3"
|
||||
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
@ -1537,9 +1581,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.33.0"
|
||||
version = "0.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
|
||||
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
@ -1551,7 +1595,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rustix 1.0.0",
|
||||
"rustix 1.0.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1562,39 +1606,18 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
version = "0.8.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"zerocopy-derive 0.7.35",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa91407dacce3a68c56de03abe2760159582b846c6a4acd2f456618087f12713"
|
||||
dependencies = [
|
||||
"zerocopy-derive 0.8.17",
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.35"
|
||||
version = "0.8.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06718a168365cad3d5ff0bb133aad346959a2074bd4a85c121255a11304a8626"
|
||||
checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -27,6 +27,7 @@ uudoc = []
|
||||
|
||||
feat_common_core = [
|
||||
"blockdev",
|
||||
"chcpu",
|
||||
"ctrlaltdel",
|
||||
"dmesg",
|
||||
"fsfreeze",
|
||||
@ -60,8 +61,11 @@ serde_json = { version = "1.0.122", features = ["preserve_order"] }
|
||||
sysinfo = "0.33"
|
||||
tempfile = "3.9.0"
|
||||
textwrap = { version = "0.16.0", features = ["terminal_size"] }
|
||||
thiserror = "2.0"
|
||||
uucore = "0.0.30"
|
||||
xattr = "1.3.1"
|
||||
rangemap = "1.5.1"
|
||||
syscall-numbers = "4.0.2"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace = true }
|
||||
@ -76,6 +80,7 @@ uucore = { workspace = true }
|
||||
|
||||
#
|
||||
blockdev = { optional = true, version = "0.0.1", package = "uu_blockdev", path = "src/uu/blockdev" }
|
||||
chcpu = { optional = true, version = "0.0.1", package = "uu_chcpu", path = "src/uu/chcpu" }
|
||||
ctrlaltdel = { optional = true, version = "0.0.1", package = "uu_ctrlaltdel", path = "src/uu/ctrlaltdel" }
|
||||
dmesg = { optional = true, version = "0.0.1", package = "uu_dmesg", path = "src/uu/dmesg" }
|
||||
fsfreeze = { optional = true, version = "0.0.1", package = "uu_fsfreeze", path = "src/uu/fsfreeze" }
|
||||
|
19
src/uu/chcpu/Cargo.toml
Normal file
19
src/uu/chcpu/Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "uu_chcpu"
|
||||
version = "0.0.1"
|
||||
edition = "2024"
|
||||
|
||||
[lib]
|
||||
path = "src/chcpu.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "chcpu"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
rangemap = { workspace = true }
|
||||
syscall-numbers = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
uucore = { workspace = true }
|
11
src/uu/chcpu/chcpu.md
Normal file
11
src/uu/chcpu/chcpu.md
Normal file
@ -0,0 +1,11 @@
|
||||
# chcpu
|
||||
|
||||
```
|
||||
chcpu {-e|--enable|-d|--disable|-c|--configure|-g|--deconfigure} cpu-list
|
||||
chcpu {-p|--dispatch} mode
|
||||
chcpu {-r|--rescan}
|
||||
chcpu {-V|--version}
|
||||
chcpu {-h|--help}
|
||||
```
|
||||
|
||||
configure CPUs in a multi-processor system.
|
338
src/uu/chcpu/src/chcpu.rs
Normal file
338
src/uu/chcpu/src/chcpu.rs
Normal file
@ -0,0 +1,338 @@
|
||||
// This file is part of the uutils util-linux package.
|
||||
//
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
// Remove this if the tool is ported to Non-UNIX platforms.
|
||||
#![cfg_attr(not(unix), allow(dead_code))]
|
||||
|
||||
mod errors;
|
||||
#[cfg(unix)]
|
||||
mod sysfs;
|
||||
|
||||
use std::str::FromStr;
|
||||
use std::{fmt, str};
|
||||
|
||||
use clap::builder::{EnumValueParser, PossibleValue};
|
||||
use clap::{Arg, ArgAction, ArgGroup, Command, ValueEnum, crate_version};
|
||||
use rangemap::RangeInclusiveSet;
|
||||
use uucore::{error::UResult, format_usage, help_about, help_usage};
|
||||
|
||||
use crate::errors::ChCpuError;
|
||||
|
||||
mod options {
|
||||
pub static ENABLE: &str = "enable";
|
||||
pub static DISABLE: &str = "disable";
|
||||
pub static CONFIGURE: &str = "configure";
|
||||
pub static DECONFIGURE: &str = "deconfigure";
|
||||
pub static CPU_LIST: &str = "cpu-list";
|
||||
pub static DISPATCH: &str = "dispatch";
|
||||
pub static MODE: &str = "mode";
|
||||
pub static RESCAN: &str = "rescan";
|
||||
}
|
||||
|
||||
const ABOUT: &str = help_about!("chcpu.md");
|
||||
const USAGE: &str = help_usage!("chcpu.md");
|
||||
|
||||
#[uucore::main]
|
||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
let args = uu_app().try_get_matches_from_mut(args)?;
|
||||
|
||||
if args.contains_id(options::ENABLE) {
|
||||
let cpu_list = args
|
||||
.get_one::<CpuList>(options::ENABLE)
|
||||
.expect("cpu-list is required");
|
||||
|
||||
enable_cpu(cpu_list, true)?;
|
||||
} else if args.contains_id(options::DISABLE) {
|
||||
let cpu_list = args
|
||||
.get_one::<CpuList>(options::DISABLE)
|
||||
.expect("cpu-list is required");
|
||||
|
||||
enable_cpu(cpu_list, false)?;
|
||||
} else if args.contains_id(options::CONFIGURE) {
|
||||
let cpu_list = args
|
||||
.get_one::<CpuList>(options::CONFIGURE)
|
||||
.expect("cpu-list is required");
|
||||
|
||||
configure_cpu(cpu_list, true)?;
|
||||
} else if args.contains_id(options::DECONFIGURE) {
|
||||
let cpu_list = args
|
||||
.get_one::<CpuList>(options::DECONFIGURE)
|
||||
.expect("cpu-list is required");
|
||||
|
||||
configure_cpu(cpu_list, false)?;
|
||||
} else if args.contains_id(options::DISPATCH) {
|
||||
let dispatch_mode = args
|
||||
.get_one::<DispatchMode>(options::DISPATCH)
|
||||
.expect("mode is required");
|
||||
|
||||
set_dispatch_mode(*dispatch_mode)?;
|
||||
} else if args.get_flag(options::RESCAN) {
|
||||
rescan_cpus()?;
|
||||
} else {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl ValueEnum for DispatchMode {
|
||||
fn value_variants<'a>() -> &'a [Self] {
|
||||
&[Self::Horizontal, Self::Vertical]
|
||||
}
|
||||
|
||||
fn to_possible_value<'a>(&self) -> Option<PossibleValue> {
|
||||
Some(match self {
|
||||
Self::Horizontal => {
|
||||
PossibleValue::new("horizontal").help("workload spread across all available CPUs")
|
||||
}
|
||||
Self::Vertical => {
|
||||
PossibleValue::new("vertical").help("workload concentrated on few CPUs")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn uu_app() -> Command {
|
||||
Command::new(uucore::util_name())
|
||||
.version(crate_version!())
|
||||
.about(ABOUT)
|
||||
.override_usage(format_usage(USAGE))
|
||||
.infer_long_args(true)
|
||||
.arg_required_else_help(true)
|
||||
.arg(
|
||||
Arg::new(options::ENABLE)
|
||||
.short('e')
|
||||
.long(options::ENABLE)
|
||||
.value_name(options::CPU_LIST)
|
||||
.value_parser(CpuList::from_str)
|
||||
.action(ArgAction::Set)
|
||||
.help("enable CPUs"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::DISABLE)
|
||||
.short('d')
|
||||
.long(options::DISABLE)
|
||||
.value_name(options::CPU_LIST)
|
||||
.value_parser(CpuList::from_str)
|
||||
.action(ArgAction::Set)
|
||||
.help("disable CPUs"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::CONFIGURE)
|
||||
.short('c')
|
||||
.long(options::CONFIGURE)
|
||||
.value_name(options::CPU_LIST)
|
||||
.value_parser(CpuList::from_str)
|
||||
.action(ArgAction::Set)
|
||||
.help("configure CPUs"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::DECONFIGURE)
|
||||
.short('g')
|
||||
.long(options::DECONFIGURE)
|
||||
.value_name(options::CPU_LIST)
|
||||
.value_parser(CpuList::from_str)
|
||||
.action(ArgAction::Set)
|
||||
.help("deconfigure CPUs"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::DISPATCH)
|
||||
.short('p')
|
||||
.long(options::DISPATCH)
|
||||
.value_name(options::MODE)
|
||||
.value_parser(EnumValueParser::<DispatchMode>::new())
|
||||
.action(ArgAction::Set)
|
||||
.help("set dispatching mode"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::RESCAN)
|
||||
.short('r')
|
||||
.long(options::RESCAN)
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("trigger rescan of CPUs"),
|
||||
)
|
||||
.group(
|
||||
ArgGroup::new("control-group")
|
||||
.args([
|
||||
options::ENABLE,
|
||||
options::DISABLE,
|
||||
options::CONFIGURE,
|
||||
options::DECONFIGURE,
|
||||
])
|
||||
.multiple(false)
|
||||
.conflicts_with_all(["dispatch-group", "rescan-group"]),
|
||||
)
|
||||
.group(
|
||||
ArgGroup::new("dispatch-group")
|
||||
.args([options::DISPATCH])
|
||||
.multiple(false)
|
||||
.conflicts_with_all(["control-group", "rescan-group"]),
|
||||
)
|
||||
.group(
|
||||
ArgGroup::new("rescan-group")
|
||||
.args([options::RESCAN])
|
||||
.multiple(false)
|
||||
.conflicts_with_all(["control-group", "dispatch-group"]),
|
||||
)
|
||||
.after_help(
|
||||
"<cpu-list> is one or more elements separated by commas. \
|
||||
Each element is either a positive integer (e.g., 3), \
|
||||
or an inclusive range of positive integers (e.g., 0-5). \
|
||||
For example, 0,2,7,10-13 refers to CPUs whose addresses are: 0, 2, 7, 10, 11, 12, and 13.",
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[repr(u8)]
|
||||
enum DispatchMode {
|
||||
Horizontal = 0,
|
||||
Vertical = 1,
|
||||
}
|
||||
|
||||
impl fmt::Display for DispatchMode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Horizontal => write!(f, "horizontal"),
|
||||
Self::Vertical => write!(f, "vertical"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub(crate) struct CpuList(RangeInclusiveSet<usize>);
|
||||
|
||||
impl CpuList {
|
||||
fn run(&self, f: &mut dyn FnMut(usize) -> Result<(), ChCpuError>) -> Result<(), ChCpuError> {
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
let iter = self.0.iter().flat_map(RangeInclusive::to_owned).map(f);
|
||||
|
||||
let (success_occurred, first_error) =
|
||||
iter.fold((false, None), |(success_occurred, first_error), result| {
|
||||
if let Err(err) = result {
|
||||
eprintln!("{err}");
|
||||
(success_occurred, first_error.or(Some(err)))
|
||||
} else {
|
||||
(true, first_error)
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(err) = first_error {
|
||||
if success_occurred {
|
||||
uucore::error::set_exit_code(64); // Partial success.
|
||||
Ok(())
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&[u8]> for CpuList {
|
||||
type Error = ChCpuError;
|
||||
|
||||
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
|
||||
let set: RangeInclusiveSet<usize> = bytes
|
||||
.split(|&b| b == b',')
|
||||
.map(|element| {
|
||||
// Parsing: ...,element,...
|
||||
let mut iter = element.splitn(2, |&b| b == b'-').map(<[u8]>::trim_ascii);
|
||||
let first = iter.next();
|
||||
(first, iter.next())
|
||||
})
|
||||
.map(|(first, last)| {
|
||||
let first = first.ok_or(ChCpuError::EmptyCpuList)?;
|
||||
let first: usize = str::from_utf8(first)
|
||||
.map_err(|_r| ChCpuError::CpuSpecNotPositiveInteger)?
|
||||
.parse()
|
||||
.map_err(|_r| ChCpuError::CpuSpecNotPositiveInteger)?;
|
||||
|
||||
if let Some(last) = last {
|
||||
// Parsing: ...,first-last,...
|
||||
let last = str::from_utf8(last)
|
||||
.map_err(|_r| ChCpuError::CpuSpecNotPositiveInteger)?
|
||||
.parse()
|
||||
.map_err(|_r| ChCpuError::CpuSpecNotPositiveInteger)?;
|
||||
|
||||
if first <= last {
|
||||
Ok(first..=last)
|
||||
} else {
|
||||
Err(ChCpuError::CpuSpecFirstAfterLast)
|
||||
}
|
||||
} else {
|
||||
Ok(first..=first) // Parsing: ...,first,...
|
||||
}
|
||||
})
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
if set.is_empty() {
|
||||
Err(ChCpuError::EmptyCpuList)
|
||||
} else {
|
||||
Ok(Self(set))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for CpuList {
|
||||
type Err = ChCpuError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Self::try_from(s.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn enable_cpu(cpu_list: &CpuList, enable: bool) -> Result<(), ChCpuError> {
|
||||
let sysfs_cpu = sysfs::SysFSCpu::open()?;
|
||||
|
||||
let mut enabled_cpu_list = sysfs_cpu.enabled_cpu_list().ok();
|
||||
|
||||
cpu_list.run(&mut move |cpu_index| {
|
||||
sysfs_cpu.enable_cpu(enabled_cpu_list.as_mut(), cpu_index, enable)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
fn enable_cpu(_cpu_list: &CpuList, _enable: bool) -> Result<(), ChCpuError> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn configure_cpu(cpu_list: &CpuList, configure: bool) -> Result<(), ChCpuError> {
|
||||
let sysfs_cpu = sysfs::SysFSCpu::open()?;
|
||||
|
||||
let enabled_cpu_list = sysfs_cpu.enabled_cpu_list().ok();
|
||||
|
||||
cpu_list.run(&mut move |cpu_index| {
|
||||
sysfs_cpu.configure_cpu(enabled_cpu_list.as_ref(), cpu_index, configure)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
fn configure_cpu(_cpu_list: &CpuList, _configure: bool) -> Result<(), ChCpuError> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn set_dispatch_mode(dispatch_mode: DispatchMode) -> Result<(), ChCpuError> {
|
||||
sysfs::SysFSCpu::open()?.set_dispatch_mode(dispatch_mode)
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
fn set_dispatch_mode(_dispatch_mode: DispatchMode) -> Result<(), ChCpuError> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn rescan_cpus() -> Result<(), ChCpuError> {
|
||||
sysfs::SysFSCpu::open()?.rescan_cpus()
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
fn rescan_cpus() -> Result<(), ChCpuError> {
|
||||
unimplemented!()
|
||||
}
|
92
src/uu/chcpu/src/errors.rs
Normal file
92
src/uu/chcpu/src/errors.rs
Normal file
@ -0,0 +1,92 @@
|
||||
// This file is part of the uutils hostname package.
|
||||
//
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum ChCpuError {
|
||||
#[error("CPU {0} is enabled")]
|
||||
CpuIsEnabled(usize),
|
||||
|
||||
#[error("CPU {0} is not configurable")]
|
||||
CpuNotConfigurable(usize),
|
||||
|
||||
#[error("CPU {0} is not hot pluggable")]
|
||||
CpuNotHotPluggable(usize),
|
||||
|
||||
#[error("this system does not support rescanning of CPUs")]
|
||||
CpuRescanUnsupported,
|
||||
|
||||
#[error("first element of CPU list range is greater than its last element")]
|
||||
CpuSpecFirstAfterLast,
|
||||
|
||||
#[error("CPU list element is not a positive number")]
|
||||
CpuSpecNotPositiveInteger,
|
||||
|
||||
#[error("CPU list is empty")]
|
||||
EmptyCpuList,
|
||||
|
||||
#[error("CPU {0} does not exist")]
|
||||
InvalidCpuIndex(usize),
|
||||
|
||||
#[error("{0}: {1}")]
|
||||
IO0(String, std::io::Error),
|
||||
|
||||
#[error("{0} '{path}': {2}", path = .1.display())]
|
||||
IO1(String, PathBuf, std::io::Error),
|
||||
|
||||
#[error("only one CPU is enabled")]
|
||||
OneCpuIsEnabled,
|
||||
|
||||
#[error("data is not an integer '{0}'")]
|
||||
NotInteger(String),
|
||||
|
||||
#[error("this system does not support setting the dispatching mode of CPUs")]
|
||||
SetCpuDispatchUnsupported,
|
||||
}
|
||||
|
||||
impl ChCpuError {
|
||||
pub(crate) fn io0(message: impl Into<String>, error: std::io::Error) -> Self {
|
||||
Self::IO0(message.into(), error)
|
||||
}
|
||||
|
||||
pub(crate) fn io1(
|
||||
message: impl Into<String>,
|
||||
path: impl Into<PathBuf>,
|
||||
error: std::io::Error,
|
||||
) -> Self {
|
||||
Self::IO1(message.into(), path.into(), error)
|
||||
}
|
||||
|
||||
pub(crate) fn with_io_message(self, message: impl Into<String>) -> Self {
|
||||
match self {
|
||||
Self::IO0(_, err) => Self::IO0(message.into(), err),
|
||||
|
||||
Self::IO1(_, path, err) => Self::IO1(message.into(), path, err),
|
||||
|
||||
Self::CpuIsEnabled(_)
|
||||
| Self::CpuNotConfigurable(_)
|
||||
| Self::CpuNotHotPluggable(_)
|
||||
| Self::CpuRescanUnsupported
|
||||
| Self::CpuSpecFirstAfterLast
|
||||
| Self::CpuSpecNotPositiveInteger
|
||||
| Self::EmptyCpuList
|
||||
| Self::InvalidCpuIndex(_)
|
||||
| Self::OneCpuIsEnabled
|
||||
| Self::NotInteger(_)
|
||||
| Self::SetCpuDispatchUnsupported => self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl uucore::error::UError for ChCpuError {
|
||||
fn code(&self) -> i32 {
|
||||
1
|
||||
}
|
||||
|
||||
fn usage(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
1
src/uu/chcpu/src/main.rs
Normal file
1
src/uu/chcpu/src/main.rs
Normal file
@ -0,0 +1 @@
|
||||
uucore::bin!(uu_chcpu);
|
270
src/uu/chcpu/src/sysfs.rs
Normal file
270
src/uu/chcpu/src/sysfs.rs
Normal file
@ -0,0 +1,270 @@
|
||||
// This file is part of the uutils hostname package.
|
||||
//
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
use std::ffi::{CString, c_int};
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{BufRead, BufReader, Read, Write, stdout};
|
||||
use std::os::fd::{AsRawFd, FromRawFd};
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::os::unix::fs::OpenOptionsExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
use std::{fmt, str};
|
||||
|
||||
use crate::errors::ChCpuError;
|
||||
use crate::{CpuList, DispatchMode};
|
||||
|
||||
pub(crate) const PATH_SYS_CPU: &str = "/sys/devices/system/cpu";
|
||||
|
||||
pub(crate) struct SysFSCpu(File);
|
||||
|
||||
impl SysFSCpu {
|
||||
pub(crate) fn open() -> Result<Self, ChCpuError> {
|
||||
OpenOptions::new()
|
||||
.read(true)
|
||||
.custom_flags(libc::O_CLOEXEC)
|
||||
.open(PATH_SYS_CPU)
|
||||
.map(Self)
|
||||
.map_err(|err| ChCpuError::io1("failed to open", PATH_SYS_CPU, err))
|
||||
}
|
||||
|
||||
fn inner_path(name: impl AsRef<Path>) -> PathBuf {
|
||||
Path::new(PATH_SYS_CPU).join(name)
|
||||
}
|
||||
|
||||
pub(crate) fn ensure_accessible(
|
||||
&self,
|
||||
name: impl AsRef<Path>,
|
||||
access: c_int,
|
||||
) -> Result<(), ChCpuError> {
|
||||
use std::io::Error;
|
||||
|
||||
let name = name.as_ref();
|
||||
let c_name = c_string_from_path(name)?;
|
||||
|
||||
if unsafe { libc::faccessat(self.0.as_raw_fd(), c_name.as_ptr(), access, 0) } == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
let path = Self::inner_path(name);
|
||||
let err = Error::last_os_error();
|
||||
Err(ChCpuError::io1("file/directory is inaccessible", path, err))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn open_inner(
|
||||
&self,
|
||||
name: impl AsRef<Path>,
|
||||
flags: c_int,
|
||||
) -> Result<File, ChCpuError> {
|
||||
use std::io::Error;
|
||||
|
||||
let name = name.as_ref();
|
||||
let c_name = c_string_from_path(name)?;
|
||||
|
||||
unsafe {
|
||||
let fd = libc::openat(self.0.as_raw_fd(), c_name.as_ptr(), flags);
|
||||
if fd >= 0 {
|
||||
return Ok(File::from_raw_fd(fd));
|
||||
}
|
||||
}
|
||||
|
||||
let path = Self::inner_path(name);
|
||||
let err = Error::last_os_error();
|
||||
Err(ChCpuError::io1("failed to open", path, err))
|
||||
}
|
||||
|
||||
pub(crate) fn read_value<T>(&self, name: impl AsRef<Path>) -> Result<T, ChCpuError>
|
||||
where
|
||||
T: FromStr,
|
||||
{
|
||||
let name = name.as_ref();
|
||||
let mut line = String::default();
|
||||
|
||||
self.open_inner(name, libc::O_RDONLY | libc::O_CLOEXEC)
|
||||
.map(BufReader::new)?
|
||||
.read_line(&mut line)
|
||||
.map_err(|err| ChCpuError::io1("failed to read file", Self::inner_path(name), err))?;
|
||||
|
||||
line.trim()
|
||||
.parse()
|
||||
.map_err(|_r| ChCpuError::NotInteger(line.trim().into()))
|
||||
}
|
||||
|
||||
pub(crate) fn write_value(
|
||||
&self,
|
||||
name: impl AsRef<Path>,
|
||||
value: impl fmt::Display,
|
||||
) -> Result<(), ChCpuError> {
|
||||
let name = name.as_ref();
|
||||
|
||||
self.open_inner(name, libc::O_WRONLY | libc::O_CLOEXEC)?
|
||||
.write_all(format!("{value}").as_bytes())
|
||||
.map_err(|err| ChCpuError::io1("failed to write file", Self::inner_path(name), err))
|
||||
}
|
||||
|
||||
pub(crate) fn enabled_cpu_list(&self) -> Result<CpuList, ChCpuError> {
|
||||
let mut buffer = Vec::default();
|
||||
|
||||
self.open_inner("online", libc::O_RDONLY | libc::O_CLOEXEC)?
|
||||
.read_to_end(&mut buffer)
|
||||
.map_err(|err| {
|
||||
ChCpuError::io1("failed to read file", Self::inner_path("online"), err)
|
||||
})?;
|
||||
|
||||
CpuList::try_from(buffer.as_slice())
|
||||
}
|
||||
|
||||
pub(crate) fn cpu_dir_path(&self, cpu_index: usize) -> Result<PathBuf, ChCpuError> {
|
||||
let dir_name = PathBuf::from(format!("cpu{cpu_index}"));
|
||||
|
||||
self.ensure_accessible(&dir_name, libc::F_OK)
|
||||
.map(|()| dir_name)
|
||||
.map_err(|_r| ChCpuError::InvalidCpuIndex(cpu_index))
|
||||
}
|
||||
|
||||
pub(crate) fn enable_cpu(
|
||||
&self,
|
||||
enabled_cpu_list: Option<&mut CpuList>,
|
||||
cpu_index: usize,
|
||||
enable: bool,
|
||||
) -> Result<(), ChCpuError> {
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
let dir_name = self.cpu_dir_path(cpu_index)?;
|
||||
|
||||
let online_path = dir_name.join("online");
|
||||
self.ensure_accessible(&online_path, libc::F_OK)
|
||||
.map_err(|_r| ChCpuError::CpuNotHotPluggable(cpu_index))?;
|
||||
|
||||
let online = self
|
||||
.read_value::<i32>(&online_path)
|
||||
.map(|value| value != 0)?;
|
||||
|
||||
let new_state = if enable { "enabled" } else { "disabled" };
|
||||
|
||||
if enable == online {
|
||||
let mut stdout = stdout().lock();
|
||||
return writeln!(&mut stdout, "CPU {cpu_index} is already {new_state}")
|
||||
.map_err(|err| ChCpuError::io0("write standard output", err));
|
||||
}
|
||||
|
||||
if let Some(enabled_cpu_list) = &enabled_cpu_list {
|
||||
let iter = enabled_cpu_list
|
||||
.0
|
||||
.iter()
|
||||
.flat_map(RangeInclusive::to_owned)
|
||||
.take(2);
|
||||
|
||||
if !enable && iter.count() <= 1 {
|
||||
return Err(ChCpuError::OneCpuIsEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
let configured = self.read_value::<i32>(dir_name.join("configure"));
|
||||
|
||||
if let Err(err) = self.write_value(&online_path, u8::from(enable)) {
|
||||
let operation = if enable { "enable" } else { "disable" };
|
||||
|
||||
let reason = if enable && configured.is_ok_and(|value| value == 0) {
|
||||
" (CPU is deconfigured)"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
||||
return Err(err.with_io_message(format!("CPU {cpu_index} {operation} failed{reason}")));
|
||||
}
|
||||
|
||||
if let Some(enabled_cpu_list) = enabled_cpu_list {
|
||||
if enable {
|
||||
enabled_cpu_list.0.insert(cpu_index..=cpu_index);
|
||||
} else {
|
||||
enabled_cpu_list.0.remove(cpu_index..=cpu_index);
|
||||
}
|
||||
}
|
||||
|
||||
let mut stdout = stdout().lock();
|
||||
writeln!(&mut stdout, "CPU {cpu_index} {new_state}",)
|
||||
.map_err(|err| ChCpuError::io0("write standard output", err))
|
||||
}
|
||||
|
||||
pub(crate) fn configure_cpu(
|
||||
&self,
|
||||
enabled_cpu_list: Option<&CpuList>,
|
||||
cpu_index: usize,
|
||||
configure: bool,
|
||||
) -> Result<(), ChCpuError> {
|
||||
let dir_name = self.cpu_dir_path(cpu_index)?;
|
||||
|
||||
let configure_path = dir_name.join("configure");
|
||||
self.ensure_accessible(&configure_path, libc::F_OK)
|
||||
.map_err(|_r| ChCpuError::CpuNotConfigurable(cpu_index))?;
|
||||
|
||||
let previous_config = self
|
||||
.read_value::<i32>(&configure_path)
|
||||
.map(|value| value != 0)?;
|
||||
|
||||
let new_state = if configure {
|
||||
"configured"
|
||||
} else {
|
||||
"deconfigured"
|
||||
};
|
||||
|
||||
if configure == previous_config {
|
||||
let mut stdout = stdout().lock();
|
||||
return writeln!(&mut stdout, "CPU {cpu_index} is already {new_state}")
|
||||
.map_err(|err| ChCpuError::io0("write standard output", err));
|
||||
}
|
||||
|
||||
if let Some(enabled_cpu_list) = enabled_cpu_list {
|
||||
if previous_config && !configure && enabled_cpu_list.0.contains(&cpu_index) {
|
||||
return Err(ChCpuError::CpuIsEnabled(cpu_index));
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(err) = self.write_value(&configure_path, u8::from(configure)) {
|
||||
let operation = if configure {
|
||||
"configure"
|
||||
} else {
|
||||
"deconfigure"
|
||||
};
|
||||
Err(err.with_io_message(format!("CPU {cpu_index} {operation} failed")))
|
||||
} else {
|
||||
let mut stdout = stdout().lock();
|
||||
writeln!(&mut stdout, "CPU {cpu_index} {new_state}",)
|
||||
.map_err(|err| ChCpuError::io0("write standard output", err))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_dispatch_mode(&self, mode: DispatchMode) -> Result<(), ChCpuError> {
|
||||
self.ensure_accessible("dispatching", libc::F_OK)
|
||||
.map_err(|_r| ChCpuError::SetCpuDispatchUnsupported)?;
|
||||
|
||||
self.write_value("dispatching", mode as u8)
|
||||
.map_err(|err| err.with_io_message("failed to set dispatch mode"))?;
|
||||
|
||||
let mut stdout = stdout().lock();
|
||||
writeln!(&mut stdout, "Successfully set {mode} dispatching mode")
|
||||
.map_err(|err| ChCpuError::io0("write standard output", err))
|
||||
}
|
||||
|
||||
pub(crate) fn rescan_cpus(&self) -> Result<(), ChCpuError> {
|
||||
self.ensure_accessible("rescan", libc::F_OK)
|
||||
.map_err(|_r| ChCpuError::CpuRescanUnsupported)?;
|
||||
|
||||
self.write_value("rescan", "1")
|
||||
.map_err(|err| err.with_io_message("failed to trigger rescan of CPUs"))?;
|
||||
|
||||
let mut stdout = stdout().lock();
|
||||
writeln!(&mut stdout, "Triggered rescan of CPUs")
|
||||
.map_err(|err| ChCpuError::io0("write standard output", err))
|
||||
}
|
||||
}
|
||||
|
||||
fn c_string_from_path(path: &Path) -> Result<CString, ChCpuError> {
|
||||
use std::io::{Error, ErrorKind};
|
||||
|
||||
CString::new(path.as_os_str().as_bytes())
|
||||
.map_err(|_r| ChCpuError::io1("invalid name", path, Error::from(ErrorKind::InvalidInput)))
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user