Compare commits

..

1 Commits
main ... choom

Author SHA1 Message Date
d66c2bcf45
WIP: choom 2025-03-10 22:16:32 +01:00
31 changed files with 273 additions and 1435 deletions

4
.gitignore vendored

@ -1,3 +1 @@
syntax: glob
/target/
/target

330
Cargo.lock generated

@ -84,18 +84,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "bitflags"
version = "2.9.0"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
[[package]]
name = "bumpalo"
@ -104,10 +95,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
[[package]]
name = "cc"
version = "1.2.16"
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cc"
version = "1.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda"
dependencies = [
"shlex",
]
@ -161,18 +158,18 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.32"
version = "4.5.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6088f3ae8c3608d19260cd7445411865a485688711b78b5be70d78cd96136f83"
checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.5.32"
version = "4.5.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22a7ef7f676155edfb82daa97f99441f3ebf4a58d5e32f295a56259f1b6facc8"
checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863"
dependencies = [
"anstream",
"anstyle",
@ -183,9 +180,9 @@ dependencies = [
[[package]]
name = "clap_complete"
version = "4.5.47"
version = "4.5.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06f5378ea264ad4f82bbc826628b5aad714a75abf6ece087e923010eb937fb6"
checksum = "f5c5508ea23c5366f77e53f5a0070e5a84e51687ec3ef9e0464c86dc8d13ce98"
dependencies = [
"clap",
]
@ -243,21 +240,11 @@ version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "deranged"
version = "0.4.0"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
dependencies = [
"powerfmt",
]
@ -268,16 +255,6 @@ version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "dns-lookup"
version = "2.0.4"
@ -292,15 +269,15 @@ dependencies = [
[[package]]
name = "either"
version = "1.15.0"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "equivalent"
version = "1.0.2"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "errno"
@ -318,26 +295,16 @@ version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.3.2"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
dependencies = [
"cfg-if",
"libc",
"r-efi",
"wasi",
"windows-targets 0.52.6",
]
[[package]]
@ -383,9 +350,9 @@ dependencies = [
[[package]]
name = "indexmap"
version = "2.8.0"
version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
dependencies = [
"equivalent",
"hashbrown",
@ -399,9 +366,9 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itoa"
version = "1.0.15"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
[[package]]
name = "js-sys"
@ -415,9 +382,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.171"
version = "0.2.170"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828"
[[package]]
name = "linux-raw-sys"
@ -427,25 +394,15 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
[[package]]
name = "linux-raw-sys"
version = "0.9.3"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
checksum = "6db9c683daf087dc577b7506e9695b3d556a9f3849903fa28186283afd6809e9"
[[package]]
name = "log"
version = "0.4.26"
version = "0.4.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
[[package]]
name = "md-5"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
dependencies = [
"cfg-if",
"digest",
]
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
[[package]]
name = "memchr"
@ -515,9 +472,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "once_cell"
version = "1.21.1"
version = "1.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc"
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
[[package]]
name = "os_display"
@ -594,11 +551,11 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "ppv-lite86"
version = "0.2.21"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
dependencies = [
"zerocopy",
"zerocopy 0.7.35",
]
[[package]]
@ -613,9 +570,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.94"
version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
dependencies = [
"unicode-ident",
]
@ -644,19 +601,13 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.40"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
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 +624,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
dependencies = [
"rand_chacha",
"rand_core 0.9.3",
"zerocopy",
"rand_core 0.9.0",
"zerocopy 0.8.17",
]
[[package]]
@ -684,7 +635,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
"rand_core 0.9.3",
"rand_core 0.9.0",
]
[[package]]
@ -695,19 +646,14 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
[[package]]
name = "rand_core"
version = "0.9.3"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff"
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"
@ -787,28 +733,28 @@ dependencies = [
[[package]]
name = "rustix"
version = "1.0.3"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96"
checksum = "17f8dcd64f141950290e45c99f7710ede1b600297c91818bb30b3667c0f45dc0"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys 0.9.3",
"linux-raw-sys 0.9.2",
"windows-sys 0.59.0",
]
[[package]]
name = "rustversion"
version = "1.0.20"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
[[package]]
name = "ryu"
version = "1.0.20"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
[[package]]
name = "serde"
@ -879,21 +825,15 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.100"
version = "2.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
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"
@ -910,24 +850,25 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.19.1"
version = "3.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf"
checksum = "2c317e0a526ee6120d8dabad239c8dadca62b24b6f168914bbbc8e2fb1f0e567"
dependencies = [
"cfg-if",
"fastrand",
"getrandom",
"once_cell",
"rustix 1.0.3",
"rustix 1.0.0",
"windows-sys 0.59.0",
]
[[package]]
name = "terminal_size"
version = "0.4.2"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed"
checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9"
dependencies = [
"rustix 1.0.3",
"rustix 0.38.44",
"windows-sys 0.59.0",
]
@ -943,31 +884,11 @@ dependencies = [
"unicode-width 0.2.0",
]
[[package]]
name = "thiserror"
version = "2.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
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"
version = "0.3.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d9c75b47bdff86fa3334a3db91356b8d7d86a9b839dab7d0bdc5c3d3a077618"
checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21"
dependencies = [
"deranged",
"itoa",
@ -982,31 +903,25 @@ dependencies = [
[[package]]
name = "time-core"
version = "0.1.4"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "time-macros"
version = "0.2.21"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29aa485584182073ed57fd5004aa09c371f021325014694e432313345865fd04"
checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de"
dependencies = [
"num-conv",
"time-core",
]
[[package]]
name = "typenum"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
[[package]]
name = "unicode-ident"
version = "1.0.18"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
[[package]]
name = "unicode-linebreak"
@ -1054,7 +969,7 @@ dependencies = [
"tempfile",
"textwrap",
"uu_blockdev",
"uu_chcpu",
"uu_choom",
"uu_ctrlaltdel",
"uu_dmesg",
"uu_fsfreeze",
@ -1062,10 +977,7 @@ dependencies = [
"uu_lscpu",
"uu_lslocks",
"uu_lsmem",
"uu_mcookie",
"uu_mesg",
"uu_mountpoint",
"uu_renice",
"uu_rev",
"uu_setsid",
"uucore",
@ -1077,21 +989,18 @@ name = "uu_blockdev"
version = "0.0.1"
dependencies = [
"clap",
"linux-raw-sys 0.9.3",
"linux-raw-sys 0.9.2",
"regex",
"sysinfo",
"uucore",
]
[[package]]
name = "uu_chcpu"
name = "uu_choom"
version = "0.0.1"
dependencies = [
"clap",
"libc",
"rangemap",
"syscall-numbers",
"thiserror",
"linux-raw-sys 0.9.2",
"uucore",
]
@ -1121,7 +1030,7 @@ name = "uu_fsfreeze"
version = "0.0.1"
dependencies = [
"clap",
"linux-raw-sys 0.9.3",
"linux-raw-sys 0.9.2",
"regex",
"sysinfo",
"uucore",
@ -1168,25 +1077,6 @@ dependencies = [
"uucore",
]
[[package]]
name = "uu_mcookie"
version = "0.0.1"
dependencies = [
"clap",
"md-5",
"rand 0.9.0",
"uucore",
]
[[package]]
name = "uu_mesg"
version = "0.0.1"
dependencies = [
"clap",
"nix",
"uucore",
]
[[package]]
name = "uu_mountpoint"
version = "0.0.1"
@ -1195,15 +1085,6 @@ dependencies = [
"uucore",
]
[[package]]
name = "uu_renice"
version = "0.0.1"
dependencies = [
"clap",
"libc",
"uucore",
]
[[package]]
name = "uu_rev"
version = "0.0.1"
@ -1259,17 +1140,11 @@ version = "0.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bb6d972f580f8223cb7052d8580aea2b7061e368cf476de32ea9457b19459ed"
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "wasi"
version = "0.14.2+wasi-0.2.4"
version = "0.13.3+wasi-0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
dependencies = [
"wit-bindgen-rt",
]
@ -1418,9 +1293,9 @@ dependencies = [
[[package]]
name = "windows-link"
version = "0.1.1"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3"
[[package]]
name = "windows-result"
@ -1581,9 +1456,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "wit-bindgen-rt"
version = "0.39.0"
version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
dependencies = [
"bitflags",
]
@ -1595,7 +1470,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e"
dependencies = [
"libc",
"rustix 1.0.3",
"rustix 1.0.0",
]
[[package]]
@ -1606,18 +1481,39 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
[[package]]
name = "zerocopy"
version = "0.8.23"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"zerocopy-derive",
"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",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.23"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154"
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"
dependencies = [
"proc-macro2",
"quote",

@ -27,7 +27,7 @@ uudoc = []
feat_common_core = [
"blockdev",
"chcpu",
"choom",
"ctrlaltdel",
"dmesg",
"fsfreeze",
@ -35,10 +35,7 @@ feat_common_core = [
"lscpu",
"lslocks",
"lsmem",
"mcookie",
"mesg",
"mountpoint",
"renice",
"rev",
"setsid",
]
@ -50,7 +47,6 @@ clap_mangen = "0.2"
dns-lookup = "2.0.4"
libc = "0.2.152"
linux-raw-sys = { version = "0.9.0", features = ["ioctl"] }
md-5 = "0.10.6"
nix = { version = "0.29", default-features = false }
phf = "0.11.2"
phf_codegen = "0.11.2"
@ -61,11 +57,8 @@ 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 }
@ -80,7 +73,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" }
choom = { optional = true, version = "0.0.1", package = "uu_choom", path = "src/uu/choom" }
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" }
@ -88,10 +81,7 @@ last = { optional = true, version = "0.0.1", package = "uu_last", path = "src/uu
lscpu = { optional = true, version = "0.0.1", package = "uu_lscpu", path = "src/uu/lscpu" }
lslocks = { optional = true, version = "0.0.1", package = "uu_lslocks", path = "src/uu/lslocks" }
lsmem = { optional = true, version = "0.0.1", package = "uu_lsmem", path = "src/uu/lsmem" }
mcookie = { optional = true, version = "0.0.1", package = "uu_mcookie", path = "src/uu/mcookie" }
mesg = { optional = true, version = "0.0.1", package = "uu_mesg", path = "src/uu/mesg" }
mountpoint = { optional = true, version = "0.0.1", package = "uu_mountpoint", path = "src/uu/mountpoint" }
renice = { optional = true, version = "0.0.1", package = "uu_renice", path = "src/uu/renice" }
rev = { optional = true, version = "0.0.1", package = "uu_rev", path = "src/uu/rev" }
setsid = { optional = true, version = "0.0.1", package = "uu_setsid", path ="src/uu/setsid" }

@ -1,4 +1,4 @@
// This file is part of the uutils util-linux package.
// This file is part of the uutils coreutils package.
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
@ -11,13 +11,14 @@ use std::io::Write;
use std::path::Path;
pub fn main() {
const ENV_FEATURE_PREFIX: &str = "CARGO_FEATURE_";
const FEATURE_PREFIX: &str = "feat_";
if let Ok(profile) = env::var("PROFILE") {
println!("cargo:rustc-cfg=build={profile:?}");
}
const ENV_FEATURE_PREFIX: &str = "CARGO_FEATURE_";
const FEATURE_PREFIX: &str = "feat_";
const OVERRIDE_PREFIX: &str = "uu_";
let out_dir = env::var("OUT_DIR").unwrap();
let mut crates = Vec::new();
@ -53,7 +54,45 @@ pub fn main() {
let mut phf_map = phf_codegen::OrderedMap::<&str>::new();
for krate in &crates {
let map_value = format!("({krate}::uumain, {krate}::uu_app)");
phf_map.entry(krate, &map_value);
match krate.as_ref() {
// 'test' is named uu_test to avoid collision with rust core crate 'test'.
// It can also be invoked by name '[' for the '[ expr ] syntax'.
"uu_test" => {
phf_map.entry("test", &map_value);
phf_map.entry("[", &map_value);
}
k if k.starts_with(OVERRIDE_PREFIX) => {
phf_map.entry(&k[OVERRIDE_PREFIX.len()..], &map_value);
}
"false" | "true" => {
phf_map.entry(krate, &format!("(r#{krate}::uumain, r#{krate}::uu_app)"));
}
"hashsum" => {
phf_map.entry(krate, &format!("({krate}::uumain, {krate}::uu_app_custom)"));
let map_value = format!("({krate}::uumain, {krate}::uu_app_common)");
let map_value_bits = format!("({krate}::uumain, {krate}::uu_app_bits)");
let map_value_b3sum = format!("({krate}::uumain, {krate}::uu_app_b3sum)");
phf_map.entry("md5sum", &map_value);
phf_map.entry("sha1sum", &map_value);
phf_map.entry("sha224sum", &map_value);
phf_map.entry("sha256sum", &map_value);
phf_map.entry("sha384sum", &map_value);
phf_map.entry("sha512sum", &map_value);
phf_map.entry("sha3sum", &map_value_bits);
phf_map.entry("sha3-224sum", &map_value);
phf_map.entry("sha3-256sum", &map_value);
phf_map.entry("sha3-384sum", &map_value);
phf_map.entry("sha3-512sum", &map_value);
phf_map.entry("shake128sum", &map_value_bits);
phf_map.entry("shake256sum", &map_value_bits);
phf_map.entry("b2sum", &map_value);
phf_map.entry("b3sum", &map_value_b3sum);
}
_ => {
phf_map.entry(krate, &map_value);
}
}
}
write!(mf, "{}", phf_map.build()).unwrap();
mf.write_all(b"\n}\n").unwrap();

@ -230,8 +230,8 @@ mod linux {
fn get_partition_offset(device_file: &File) -> UResult<usize> {
let rdev = device_file.metadata()?.rdev();
let major = libc::major(rdev);
let minor = libc::minor(rdev);
let major = unsafe { libc::major(rdev) };
let minor = unsafe { libc::minor(rdev) };
if Path::new(&format!("/sys/dev/block/{}:{}/partition", major, minor)).exists() {
let mut start_fd = File::open(format!("/sys/dev/block/{}:{}/start", major, minor))?;
let mut str = String::new();

@ -1,19 +0,0 @@
[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 }

@ -1,11 +0,0 @@
# 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.

@ -1,338 +0,0 @@
// 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!()
}

@ -1,92 +0,0 @@
// 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 +0,0 @@
uucore::bin!(uu_chcpu);

@ -1,270 +0,0 @@
// 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)))
}

@ -1,16 +1,16 @@
[package]
name = "uu_mesg"
name = "uu_choom"
version = "0.0.1"
edition = "2021"
[lib]
path = "src/mesg.rs"
path = "src/choom.rs"
[[bin]]
name = "mesg"
name = "choom"
path = "src/main.rs"
[dependencies]
clap = { workspace = true }
nix = { workspace = true }
linux-raw-sys = { workspace = true }
uucore = { workspace = true }

9
src/uu/choom/choom.md Normal file

@ -0,0 +1,9 @@
# choom
```
choom [OPTION] -p pid
choom [OPTION] -n number -p pid
choom [OPTION] -n number [--] command [args...]]
```
Display and adjust OOM-killer score.

97
src/uu/choom/src/choom.rs Normal file

@ -0,0 +1,97 @@
// 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.
use clap::{crate_version, Arg, ArgAction, ArgGroup, Command};
use std::io::Write;
use uucore::{error::UResult, format_usage, help_about, help_usage};
const ABOUT: &str = help_about!("choom.md");
const USAGE: &str = help_usage!("choom.md");
mod options {
pub const PID: &str = "pid";
pub const ADJUST: &str = "adjust";
}
#[cfg(target_os = "linux")]
#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let matches: clap::ArgMatches = uu_app().try_get_matches_from(args)?;
if let Some(adjust) = matches.get_one::<i32>(options::ADJUST) {
let pid = match matches.get_one::<u32>(options::PID) {
Some(pid) => *pid,
None => std::process::id(),
};
adjust_oom_score(pid, *adjust)?;
} else if let Some(pid) = matches.get_one::<u32>(options::PID) {
print_oom_score(*pid)?;
}
Ok(())
}
pub fn adjust_oom_score(pid: u32, adjust: i32) -> UResult<()> {
let path = format!("/proc/{}/oom_score_adj", pid);
let mut file = std::fs::OpenOptions::new().write(true).open(path)?;
file.write_all(adjust.to_string().as_bytes())?;
Ok(())
}
pub fn print_oom_score(pid: u32) -> UResult<()> {
let path = format!("/proc/{}/oom_score", pid);
let score = std::fs::read_to_string(path)?;
println!("pid {}'s current OOM score: {}", pid, score.trim());
let path = format!("/proc/{}/oom_score_adj", pid);
let score = std::fs::read_to_string(path)?;
println!(
"pid {}'s current OOM score adjust value: {}",
pid,
score.trim()
);
Ok(())
}
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(
Arg::new(options::ADJUST)
.short('n')
.long(options::ADJUST)
.help("specify the adjust score value")
.action(ArgAction::Set)
.value_name("num")
.value_parser(clap::value_parser!(i32)),
)
.arg(
Arg::new(options::PID)
.short('p')
.long(options::PID)
.help("process ID")
.action(ArgAction::Set)
.value_name("num")
.value_parser(clap::value_parser!(u32)),
)
.group(
ArgGroup::new("action")
.args([options::ADJUST, options::PID])
.required(true)
.multiple(true),
)
}
#[cfg(not(target_os = "linux"))]
#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let _matches: clap::ArgMatches = uu_app().try_get_matches_from(args)?;
Err(uucore::error::USimpleError::new(
1,
"`choom` is available only on Linux.",
))
}

1
src/uu/choom/src/main.rs Normal file

@ -0,0 +1 @@
uucore::bin!(uu_choom);

@ -1,17 +0,0 @@
[package]
name = "uu_mcookie"
version = "0.0.1"
edition = "2021"
[lib]
path = "src/mcookie.rs"
[[bin]]
name = "mcookie"
path = "src/main.rs"
[dependencies]
uucore = { workspace = true }
clap = { workspace = true }
md-5 = { workspace = true }
rand = { workspace = true }

@ -1,7 +0,0 @@
# mcookie
```
mcookie [OPTION]...
```
Generate magic cookies for xauth.

@ -1 +0,0 @@
uucore::bin!(uu_mcookie);

@ -1,111 +0,0 @@
// 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.
use std::{fs::File, io::Read};
use clap::{crate_version, Arg, ArgAction, Command};
use md5::{Digest, Md5};
use rand::RngCore;
use uucore::{error::UResult, format_usage, help_about, help_usage};
mod options {
pub const FILE: &str = "file";
pub const MAX_SIZE: &str = "max-size";
pub const VERBOSE: &str = "verbose";
}
const ABOUT: &str = help_about!("mcookie.md");
const USAGE: &str = help_usage!("mcookie.md");
#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let matches: clap::ArgMatches = uu_app().try_get_matches_from(args)?;
let verbose = matches.get_flag(options::VERBOSE);
let seed_files: Vec<&str> = matches
.get_many::<String>(options::FILE)
.unwrap_or_default()
.map(|v| v.as_str())
.collect();
// TODO: Parse max size from human-readable strings (KiB, MiB, GiB etc.)
let max_size = matches
.get_one::<String>(options::MAX_SIZE)
.map(|v| v.parse::<u64>().expect("Failed to parse max-size value"));
let mut hasher = Md5::new();
for file in seed_files {
let mut f = File::open(file)?;
let mut buffer: Vec<u8> = Vec::new();
if let Some(max_bytes) = &max_size {
let mut handle = f.take(*max_bytes);
handle.read_to_end(&mut buffer)?;
} else {
f.read_to_end(&mut buffer)?;
}
if verbose {
eprintln!("Got {} bytes from {}", buffer.len(), file);
}
hasher.update(&buffer);
}
const RANDOM_BYTES: usize = 128;
let mut rng = rand::rng();
let mut rand_bytes = [0u8; RANDOM_BYTES];
rng.fill_bytes(&mut rand_bytes);
hasher.update(rand_bytes);
if verbose {
eprintln!("Got {} bytes from randomness source", RANDOM_BYTES);
}
let result = hasher.finalize();
let output = result
.iter()
.map(|byte| format!("{:02x}", byte))
.collect::<Vec<_>>()
.join("");
println!("{}", output);
Ok(())
}
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(
Arg::new(options::FILE)
.short('f')
.long("file")
.value_name("file")
.action(ArgAction::Append)
.help("use file as a cookie seed"),
)
.arg(
Arg::new(options::MAX_SIZE)
.short('m')
.long("max-size")
.value_name("num")
.action(ArgAction::Set)
.help("limit how much is read from seed files"),
)
.arg(
Arg::new(options::VERBOSE)
.short('v')
.long("verbose")
.action(ArgAction::SetTrue)
.help("explain what is being done"),
)
}

@ -1,7 +0,0 @@
# mesg
```
mesg [option] [y|n]
```
enables or disables displaying messages from other users

@ -1 +0,0 @@
uucore::bin!(uu_mesg);

@ -1,101 +0,0 @@
// 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.
use clap::{builder::PossibleValuesParser, crate_version, Arg, ArgAction, ArgMatches, Command};
#[cfg(target_family = "unix")]
use uucore::error::{set_exit_code, UIoError};
use uucore::{error::UResult, format_usage, help_about, help_usage};
const ABOUT: &str = help_about!("mesg.md");
const USAGE: &str = help_usage!("mesg.md");
#[cfg(target_family = "unix")]
pub fn do_mesg(matches: &ArgMatches) -> UResult<()> {
use nix::sys::stat::{fchmod, fstat, Mode};
use std::{io, os::fd::AsRawFd};
use std::{io::IsTerminal, os::fd::AsFd};
for fd in &[
std::io::stdin().as_fd(),
std::io::stdout().as_fd(),
std::io::stderr().as_fd(),
] {
if fd.is_terminal() {
let st = fstat(fd.as_raw_fd())?;
if let Some(enable) = matches.get_one::<String>("enable") {
// 'mesg y' on the GNU version seems to only modify the group write bit,
// but 'mesg n' modifies both group and others write bits.
let new_mode = if enable == "y" {
st.st_mode | 0o020
} else {
st.st_mode & !0o022
};
fchmod(fd.as_raw_fd(), Mode::from_bits_retain(new_mode))?;
if enable == "n" {
set_exit_code(1);
}
if matches.get_flag("verbose") {
println!(
"write access to your terminal is {}",
if enable == "y" { "allowed" } else { "denied" }
);
}
} else if st.st_mode & 0o022 != 0 {
println!("is y");
} else {
set_exit_code(1);
println!("is n");
}
return Ok(());
}
}
Err(UIoError::new(
io::ErrorKind::Other,
"stdin/stdout/stderr is not a terminal",
))
}
#[cfg(target_family = "unix")]
#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let matches = uu_app().try_get_matches_from(args)?;
if let Err(e) = do_mesg(&matches) {
set_exit_code(2);
uucore::show_error!("{}", e);
};
Ok(())
}
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(
Arg::new("verbose")
.short('v')
.long("verbose")
.help("Explain what is being done")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new("enable")
.help("Whether to allow or disallow messages")
.value_parser(PossibleValuesParser::new(["y", "n"]))
.action(ArgAction::Set),
)
}
#[cfg(not(target_family = "unix"))]
#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let _matches: ArgMatches = uu_app().try_get_matches_from(args)?;
Err(uucore::error::USimpleError::new(
1,
"`mesg` is available only on Unix platforms.",
))
}

@ -1,17 +0,0 @@
[package]
name = "uu_renice"
version = "0.0.1"
edition = "2021"
description = "renice ~ (uutils) Alter priority of running processes"
[lib]
path = "src/renice.rs"
[[bin]]
name = "renice"
path = "src/main.rs"
[dependencies]
clap = { workspace = true }
libc = { workspace = true }
uucore = { workspace = true }

@ -1,7 +0,0 @@
# renice
```
renice [--priority|--relative] priority [-g|-p|-u] identifier...
```
Alter priority of running processes

@ -1 +0,0 @@
uucore::bin!(uu_renice);

@ -1,65 +0,0 @@
// 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.
use clap::{crate_version, Arg, Command};
#[cfg(not(windows))]
use libc::PRIO_PROCESS;
use std::env;
#[cfg(not(windows))]
use std::io::Error;
use std::process;
use uucore::{error::UResult, format_usage, help_about, help_usage};
const ABOUT: &str = help_about!("renice.md");
const USAGE: &str = help_usage!("renice.md");
#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let matches = uu_app().try_get_matches_from(args)?;
let nice_value_str = matches.get_one::<String>("nice_value").unwrap(); // Retrieve as String
let nice_value = nice_value_str.parse::<i32>().unwrap_or_else(|_| {
eprintln!("Invalid nice value");
process::exit(1);
});
let pid_str = matches.get_one::<String>("pid").unwrap(); // Retrieve as String
let pid = pid_str.parse::<i32>().unwrap_or_else(|_| {
eprintln!("Invalid PID");
process::exit(1);
});
// TODO: implement functionality on windows
#[cfg(not(windows))]
if unsafe { libc::setpriority(PRIO_PROCESS, pid.try_into().unwrap(), nice_value) } == -1 {
eprintln!("Failed to set nice value: {}", Error::last_os_error());
process::exit(1);
}
println!("Nice value of process {} set to {}", pid, nice_value);
Ok(())
}
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(
Arg::new("nice_value")
.value_name("NICE_VALUE")
.help("The new nice value for the process")
.required(true)
.index(1),
)
.arg(
Arg::new("pid")
.value_name("PID")
.help("The PID of the process")
.required(true)
.index(2),
)
}

@ -3,7 +3,6 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
#[cfg(target_os = "linux")]
use crate::common::util::TestScenario;
#[test]

@ -1,65 +0,0 @@
// 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.
use std::io::Write;
use tempfile::NamedTempFile;
use crate::common::util::TestScenario;
#[test]
fn test_invalid_arg() {
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
}
#[test]
fn test_basic_usage() {
let res = new_ucmd!().succeeds();
let stdout = res.no_stderr().stdout_str();
// Expect 32 hex characters for the MD5 hash (after trimming the newline)
assert_eq!(stdout.trim_end().len(), 32);
assert!(stdout.trim_end().chars().all(|c| c.is_ascii_hexdigit()));
}
#[test]
fn test_verbose() {
let res = new_ucmd!().arg("--verbose").succeeds();
res.stderr_contains("Got 128 bytes from randomness source");
}
#[test]
fn test_seed_files_and_max_size() {
let mut file1 = NamedTempFile::new().unwrap();
const CONTENT1: &str = "Some seed data";
file1.write_all(CONTENT1.as_bytes()).unwrap();
let mut file2 = NamedTempFile::new().unwrap();
const CONTENT2: [u8; 2048] = [1; 2048];
file2.write_all(&CONTENT2).unwrap();
let res = new_ucmd!()
.arg("--verbose")
.arg("-f")
.arg(file1.path())
.arg("-f")
.arg(file2.path())
.arg("-m")
.arg("1337")
.succeeds();
res.stderr_contains(format!(
"Got {} bytes from {}",
CONTENT1.len(),
file1.path().to_str().unwrap()
));
// Ensure we only read up to the limit of bytes, despite the file being bigger
res.stderr_contains(format!(
"Got 1337 bytes from {}",
file2.path().to_str().unwrap()
));
}

@ -1,36 +0,0 @@
// 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.
use crate::common::util::TestScenario;
#[test]
fn test_invalid_verb() {
new_ucmd!().arg("foo").fails().code_is(1);
}
#[test]
#[cfg(target_family = "unix")]
fn test_no_terminal() {
for args in &[vec![], vec!["y"], vec!["n"]] {
new_ucmd!()
.args(args)
.fails()
.code_is(2)
.stderr_contains("stdin/stdout/stderr is not a terminal");
}
}
#[cfg(not(target_family = "unix"))]
mod non_unix {
use crate::common::util::TestScenario;
#[test]
fn test_fails_on_unsupported_platforms() {
new_ucmd!()
.fails()
.code_is(1)
.stderr_is("mesg: `mesg` is available only on Unix platforms.\n");
}
}

@ -1,12 +0,0 @@
// 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.
// spell-checker:ignore (words) symdir somefakedir
use crate::common::util::TestScenario;
#[test]
fn test_invalid_arg() {
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
}

@ -17,10 +17,6 @@ mod test_lsmem;
#[path = "by-util/test_lslocks.rs"]
mod test_lslocks;
#[cfg(feature = "mesg")]
#[path = "by-util/test_mesg.rs"]
mod test_mesg;
#[cfg(feature = "mountpoint")]
#[path = "by-util/test_mountpoint.rs"]
mod test_mountpoint;
@ -33,10 +29,6 @@ mod test_blockdev;
#[path = "by-util/test_ctrlaltdel.rs"]
mod test_ctrlaltdel;
#[cfg(feature = "renice")]
#[path = "by-util/test_renice.rs"]
mod test_renice;
#[cfg(feature = "rev")]
#[path = "by-util/test_rev.rs"]
mod test_rev;
@ -56,7 +48,3 @@ mod test_dmesg;
#[cfg(feature = "fsfreeze")]
#[path = "by-util/test_fsfreeze.rs"]
mod test_fsfreeze;
#[cfg(feature = "mcookie")]
#[path = "by-util/test_mcookie.rs"]
mod test_mcookie;