Compare commits

..

No commits in common. "main" and "main" have entirely different histories.
main ... main

5 changed files with 194 additions and 350 deletions

237
Cargo.lock generated
View file

@ -26,12 +26,6 @@ dependencies = [
"memchr",
]
[[package]]
name = "allocator-api2"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "anstream"
version = "0.6.18"
@ -73,26 +67,26 @@ dependencies = [
[[package]]
name = "anstyle-wincon"
version = "3.0.8"
version = "3.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6680de5231bd6ee4c6191b8a1325daa282b415391ec9d3a37bd34f2060dc73fa"
checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
dependencies = [
"anstyle",
"once_cell_polyfill",
"once_cell",
"windows-sys 0.59.0",
]
[[package]]
name = "anyhow"
version = "1.0.98"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
[[package]]
name = "async-trait"
version = "0.1.88"
version = "0.1.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5"
checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d"
dependencies = [
"proc-macro2",
"quote",
@ -107,9 +101,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "backtrace"
version = "0.3.75"
version = "0.3.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
dependencies = [
"addr2line",
"cfg-if",
@ -122,15 +116,15 @@ dependencies = [
[[package]]
name = "bitflags"
version = "2.9.1"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
[[package]]
name = "bstr"
version = "1.12.0"
version = "1.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4"
checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0"
dependencies = [
"memchr",
"serde",
@ -138,15 +132,9 @@ dependencies = [
[[package]]
name = "bytes"
version = "1.10.1"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "bytesize"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3c8f83209414aacf0eeae3cf730b18d6981697fba62f200fcfb92b9f082acba"
checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9"
[[package]]
name = "cfg-if"
@ -162,9 +150,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "clap"
version = "4.5.39"
version = "4.5.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f"
checksum = "92b7b18d71fad5313a1e320fa9897994228ce274b60faa4d694fe0ea89cd9e6d"
dependencies = [
"clap_builder",
"clap_derive",
@ -172,9 +160,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.39"
version = "4.5.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51"
checksum = "a35db2071778a7344791a4fb4f95308b5673d219dee3ae348b86642574ecc90c"
dependencies = [
"anstream",
"anstyle",
@ -184,9 +172,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.5.32"
version = "4.5.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7"
checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed"
dependencies = [
"heck",
"proc-macro2",
@ -243,14 +231,14 @@ dependencies = [
[[package]]
name = "env_logger"
version = "0.11.8"
version = "0.11.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0"
dependencies = [
"anstream",
"anstyle",
"env_filter",
"jiff",
"humantime",
"log",
]
@ -266,12 +254,6 @@ version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
[[package]]
name = "foldhash"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "gimli"
version = "0.31.1"
@ -280,9 +262,9 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
name = "globset"
version = "0.4.16"
version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5"
checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19"
dependencies = [
"aho-corasick",
"bstr",
@ -293,9 +275,9 @@ dependencies = [
[[package]]
name = "goblin"
version = "0.10.0"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e961b33649994dcf69303af6b3a332c1228549e604d455d61ec5d2ab5e68d3a"
checksum = "daa0a64d21a7eb230583b4c5f4e23b7e4e57974f96620f42a7e75e08ae66d745"
dependencies = [
"log",
"plain",
@ -304,14 +286,9 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.15.3"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
dependencies = [
"allocator-api2",
"equivalent",
"foldhash",
]
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
[[package]]
name = "heck"
@ -319,6 +296,12 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "ignore"
version = "0.4.23"
@ -337,9 +320,9 @@ dependencies = [
[[package]]
name = "indexmap"
version = "2.9.0"
version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
dependencies = [
"equivalent",
"hashbrown",
@ -347,9 +330,9 @@ dependencies = [
[[package]]
name = "indoc"
version = "2.0.6"
version = "2.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
[[package]]
name = "is_terminal_polyfill"
@ -357,41 +340,17 @@ version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "jiff"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93"
dependencies = [
"jiff-static",
"log",
"portable-atomic",
"portable-atomic-util",
"serde",
]
[[package]]
name = "jiff-static"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "libc"
version = "0.2.172"
version = "0.2.169"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
[[package]]
name = "lock_api"
version = "0.4.13"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
dependencies = [
"autocfg",
"scopeguard",
@ -399,9 +358,9 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.27"
version = "0.4.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
[[package]]
name = "memchr"
@ -420,29 +379,29 @@ dependencies = [
[[package]]
name = "miniz_oxide"
version = "0.8.8"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b"
dependencies = [
"adler2",
]
[[package]]
name = "mio"
version = "1.0.4"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
dependencies = [
"libc",
"wasi",
"windows-sys 0.59.0",
"windows-sys 0.52.0",
]
[[package]]
name = "nix"
version = "0.30.1"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
dependencies = [
"bitflags",
"cfg-if",
@ -460,16 +419,16 @@ dependencies = [
]
[[package]]
name = "once_cell_polyfill"
version = "1.70.1"
name = "once_cell"
version = "1.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
[[package]]
name = "parking_lot"
version = "0.12.4"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
dependencies = [
"lock_api",
"parking_lot_core",
@ -477,9 +436,9 @@ dependencies = [
[[package]]
name = "parking_lot_core"
version = "0.9.11"
version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [
"cfg-if",
"libc",
@ -490,14 +449,12 @@ dependencies = [
[[package]]
name = "petgraph"
version = "0.8.1"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a98c6720655620a521dcc722d0ad66cd8afd5d86e34a89ef691c50b7b24de06"
checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772"
dependencies = [
"fixedbitset",
"hashbrown",
"indexmap",
"serde",
]
[[package]]
@ -512,44 +469,29 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
[[package]]
name = "portable-atomic"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
[[package]]
name = "portable-atomic-util"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
dependencies = [
"portable-atomic",
]
[[package]]
name = "proc-macro2"
version = "1.0.95"
version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
dependencies = [
"unicode-ident",
]
[[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 = "redox_syscall"
version = "0.5.12"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af"
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
dependencies = [
"bitflags",
]
@ -606,18 +548,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "scroll"
version = "0.13.0"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1257cd4248b4132760d6524d6dda4e053bc648c9070b960929bf50cfb1e7add"
checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6"
dependencies = [
"scroll_derive",
]
[[package]]
name = "scroll_derive"
version = "0.13.0"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22fc4f90c27b57691bbaf11d8ecc7cfbfe98a4da6dbe60226115d322aa80c06e"
checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932"
dependencies = [
"proc-macro2",
"quote",
@ -626,18 +568,18 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.219"
version = "1.0.217"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.219"
version = "1.0.217"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
dependencies = [
"proc-macro2",
"quote",
@ -646,24 +588,24 @@ dependencies = [
[[package]]
name = "signal-hook-registry"
version = "1.4.5"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410"
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
dependencies = [
"libc",
]
[[package]]
name = "smallvec"
version = "1.15.0"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
[[package]]
name = "socket2"
version = "0.5.10"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
dependencies = [
"libc",
"windows-sys 0.52.0",
@ -677,9 +619,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.101"
version = "2.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
dependencies = [
"proc-macro2",
"quote",
@ -688,11 +630,10 @@ dependencies = [
[[package]]
name = "sysroot-cleaner"
version = "0.9.0"
version = "0.1.0"
dependencies = [
"anyhow",
"async-trait",
"bytesize",
"clap",
"env_logger",
"goblin",
@ -708,9 +649,9 @@ dependencies = [
[[package]]
name = "tokio"
version = "1.45.1"
version = "1.43.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e"
dependencies = [
"backtrace",
"bytes",
@ -737,9 +678,9 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.18"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe"
[[package]]
name = "utf8parse"

View file

@ -4,7 +4,7 @@
[package]
name = "sysroot-cleaner"
authors = ["Matteo Settenvini <matteo.settenvini@montecristosoftware.eu>"]
version = "0.9.0"
version = "0.1.0"
edition = "2024"
license = "EUPL-1.2"
readme = "README.md"
@ -16,11 +16,10 @@ clap = { version = "4.5", features = ["derive"] }
env_logger = { version = "0.11" }
ignore = { version = "0.4" }
indoc = { version = "2.0" }
goblin = { version = "0.10" }
goblin = { version = "0.9" }
log = { version = "0.4" }
memmap2 = { version = "0.9" }
nix = { version = "0.30", features = ["fs"] }
petgraph = { version = "0.8" }
nix = { version = "0.29", features = ["fs"] }
petgraph = { version = "0.7" }
tokio = { version = "1", features = ["full"] }
walkdir = { version = "2" }
bytesize = { version = "2.0" }

View file

@ -3,30 +3,7 @@
use std::path::PathBuf;
use clap::{
builder::{PathBufValueParser, TypedValueParser},
Parser,
};
#[derive(Clone, Default)]
struct AbsolutePathBufValueParser;
impl TypedValueParser for AbsolutePathBufValueParser {
type Value = PathBuf;
fn parse_ref(
&self,
cmd: &clap::Command,
arg: Option<&clap::Arg>,
value: &std::ffi::OsStr,
) -> Result<Self::Value, clap::Error> {
let pathbuf_parser = PathBufValueParser::new();
let v = pathbuf_parser.parse_ref(cmd, arg, value)?;
v.canonicalize()
.map_err(|e| clap::Error::raw(clap::error::ErrorKind::Io, e))
}
}
use clap::Parser;
/// A tool to clean up sysroots for Linux embedded devices to save storage space.
#[derive(Parser, Debug)]
@ -42,15 +19,13 @@ pub struct Args {
pub split_to: Option<PathBuf>,
/// An allowlist of files to keep, in .gitignore format.
/// Can be passed multiple times.
/// Note: this will take precedence over all other removal decisions.
#[arg(long, value_parser = AbsolutePathBufValueParser::default())]
pub allowlist: Vec<PathBuf>,
#[arg(long)]
pub allowlist: Option<PathBuf>,
/// A blocklist of files to remove, in .gitignore format.
/// Can be passed multiple times.
#[arg(long)]
pub blocklist: Vec<PathBuf>,
pub blocklist: Option<PathBuf>,
/// An optional path to save the file graph of the DSO cleaner
/// in GraphViz format. Useful for debugging.
@ -59,20 +34,4 @@ pub struct Args {
/// The location of the sysroot to clean up
pub sysroot_location: PathBuf,
/// An additional path to consider when resolving
/// libraries, relative to the sysroot.
/// Their behavior is similar of the one of the
/// `LD_LIBRARY_PATH` environment variable when
/// specified to the dynamic linker.
#[arg(long = "ld-path", value_parser = relativize_path)]
pub extra_library_paths: Vec<PathBuf>,
}
fn relativize_path(arg: &str) -> anyhow::Result<PathBuf> {
let mut p = PathBuf::from(arg);
if p.is_absolute() {
p = p.strip_prefix("/")?.into();
}
Ok(p)
}

View file

@ -10,11 +10,10 @@ use crate::{
};
use anyhow::{Error, Result};
use async_trait::async_trait;
use bytesize::ByteSize;
use dso::DsoCleaner;
use list::ListCleaner;
use nix::libc::EXDEV;
use std::{collections::HashMap, fmt, io, ops::AddAssign, path::Path};
use std::{collections::HashMap, io, path::Path};
use tokio::{sync::mpsc, task::JoinSet};
use walkdir::{DirEntry, WalkDir};
@ -27,22 +26,8 @@ pub trait Cleaner {
) -> Result<()>;
}
struct FileSize(u64);
impl fmt::Display for FileSize {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", ByteSize(self.0))
}
}
impl AddAssign for FileSize {
fn add_assign(&mut self, rhs: Self) {
self.0.add_assign(rhs.0);
}
}
type Cleaners = Vec<Box<dyn Cleaner + Send>>;
type RemovalFn = Box<dyn Fn(&Path) -> io::Result<FileSize>>;
type RemovalFn = Box<dyn Fn(&Path) -> io::Result<()>>;
pub struct Runner {
cleaners: Cleaners,
@ -56,18 +41,15 @@ impl Runner {
let removal_fn = Self::new_removal_fn(&args);
let mut cleaners: Cleaners = vec![];
for wl in args.allowlist {
if let Some(wl) = args.allowlist {
cleaners.push(Box::new(ListCleaner::new(list::ListType::Allow, wl)));
}
for bl in args.blocklist {
if let Some(bl) = args.blocklist {
cleaners.push(Box::new(ListCleaner::new(list::ListType::Block, bl)));
}
cleaners.push(Box::new(DsoCleaner::new(
args.extra_library_paths,
args.output_dotfile,
)));
cleaners.push(Box::new(DsoCleaner::new(args.output_dotfile)));
Self {
cleaners,
@ -147,8 +129,6 @@ impl Runner {
async fn final_decision(removal_fn: RemovalFn, mut output_rx: mpsc::Receiver<Decision>) {
let mut final_decisions = HashMap::new();
let mut total_removed_size = FileSize(0);
while let Some(input_decision) = output_rx.recv().await {
if input_decision.action == Action::Undecided {
continue;
@ -167,76 +147,48 @@ impl Runner {
for (file, action) in final_decisions {
if action == Action::Remove {
let removed_size = match (removal_fn)(&file) {
Ok(size) => size,
Err(err) => {
if let Err(err) = (removal_fn)(&file) {
log::error!("{}: {}", file.display(), err);
FileSize(0)
}
};
total_removed_size += removed_size;
}
}
log::info!("Total space removed: {}", total_removed_size);
}
}
fn new_removal_fn(args: &Args) -> RemovalFn {
if let Some(dest) = args.split_to.clone() {
if args.dry_run {
Box::new(move |path| {
let size = Self::get_file_size(path)?;
log::info!(
"(dry-run) would move {} to {} ({})",
"(dry-run) would move {} to {}",
path.display(),
dest.display(),
size
dest.display()
);
Ok(size)
Ok(())
})
} else {
Box::new(move |path| {
let size = Self::get_file_size(path)?;
log::info!("moving {} to {} ({})", path.display(), dest.display(), size);
Self::move_preserve(path, &dest)?;
Ok(size)
log::info!("moving {} to {}", path.display(), dest.display());
Self::move_preserve(&path, &dest)
})
}
} else if args.dry_run {
} else {
if args.dry_run {
Box::new(|path| {
let ty = if path.is_symlink() {
"symlink"
} else {
"regular file"
};
let size = Self::get_file_size(path)?;
log::info!(
"(dry-run) would remove {} {} ({})",
ty,
path.display(),
size
);
Ok(size)
log::info!("(dry-run) would remove {} {}", ty, path.display());
Ok(())
})
} else {
Box::new(move |path| {
let size = Self::get_file_size(path)?;
log::info!("removing {} ({})", path.display(), size);
std::fs::remove_file(path)?;
Ok(size)
log::info!("removing {}", path.display());
std::fs::remove_file(&path)
})
}
}
fn get_file_size(file: &Path) -> io::Result<FileSize> {
let lstat = nix::sys::stat::lstat(file);
let size = match lstat {
Err(err) => {
log::error!("failed to get metadata from: {}, {}", file.display(), err);
FileSize(0)
}
Ok(lstat) => FileSize(lstat.st_size as u64),
};
Ok(size)
}
fn move_preserve(src: &Path, dest: &Path) -> io::Result<()> {
@ -245,7 +197,7 @@ impl Runner {
if let Some(parent) = abs_dest.parent() {
std::fs::create_dir_all(parent)?;
}
match std::fs::rename(src, &abs_dest) {
match std::fs::rename(&src, &abs_dest) {
Err(err) if err.raw_os_error() == Some(EXDEV) => {
log::trace!(
"different filesystems, falling back to copying {} to {}",

View file

@ -27,22 +27,17 @@ type InodeGraph = DiGraphMap<ino_t, ()>;
/// Cleans up unused shared libraries
/// and warns about broken dependencies as well
pub struct DsoCleaner {
extra_library_paths: Vec<PathBuf>,
output_dot: Option<PathBuf>,
}
struct State {
ld_library_path: Vec<String>,
paths_map: InodeMap,
graph: InodeGraph,
}
impl DsoCleaner {
pub fn new(extra_library_paths: Vec<PathBuf>, output_dot: Option<PathBuf>) -> Self {
Self {
extra_library_paths,
output_dot,
}
pub fn new(output_dot: Option<PathBuf>) -> Self {
Self { output_dot }
}
}
@ -57,11 +52,6 @@ impl Cleaner for DsoCleaner {
output: mpsc::Sender<Decision>,
) -> Result<()> {
let mut state = State::default();
state.ld_library_path = self
.extra_library_paths
.iter()
.map(|p| p.to_str().unwrap().to_owned())
.collect();
let mut inodes_to_keep = HashSet::new();
inodes_to_keep.insert(ROOT_NODE);
@ -72,7 +62,7 @@ impl Cleaner for DsoCleaner {
// that also its dependencies will not be kept.
if decision.action != Action::Remove {
state.process_path(&decision.path).unwrap_or_else(|e| {
log::error!(
log::warn!(
"{}: {} (this might produce wrong results!)",
decision.path.display(),
e
@ -102,12 +92,12 @@ impl Cleaner for DsoCleaner {
}
if let Some(dot) = &self.output_dot {
state.debug_print_graph(dot)?;
state.debug_print_graph(&dot)?;
}
let mut dfs = Dfs::empty(&state.graph);
dfs.stack = inodes_to_keep.into_iter().collect();
while dfs.next(&state.graph).is_some() {}
while let Some(_) = dfs.next(&state.graph) {}
for (inode, paths) in state.paths_map.into_iter() {
let action = if !dfs.discovered.contains(&inode) {
@ -137,11 +127,7 @@ impl Default for State {
paths_map.insert(ROOT_NODE, HashSet::from([fake_root_node]));
graph.add_node(ROOT_NODE);
Self {
ld_library_path: vec![],
paths_map,
graph,
}
Self { paths_map, graph }
}
}
@ -173,7 +159,7 @@ impl State {
}
let current_dir = std::env::current_dir()?;
let mut dst_path = fs::read_link(path)?;
let mut dst_path = std::fs::read_link(path)?;
if dst_path.is_absolute() {
dst_path = dst_path.strip_prefix("/")?.into();
} else {
@ -210,13 +196,11 @@ impl State {
self.update_graph("".into(), ROOT_NODE, path.to_owned(), src.st_ino);
}
let search_paths = self.determine_lib_search_paths(path, elf)?;
log::trace!("determined search paths {:#?}", search_paths);
let search_paths = determine_lib_search_paths(path, elf)?;
'next_lib: for &library in elf.libraries.iter() {
for lib_path in search_paths.iter() {
assert!(Path::new(&lib_path).is_relative());
let tentative_path = PathBuf::from(lib_path).join(library);
let tentative_path = PathBuf::from(lib_path).strip_prefix("/")?.join(library);
let dst = match nix::sys::stat::lstat(&tentative_path) {
Ok(dst) => dst,
Err(Errno::ENOENT) => continue,
@ -235,11 +219,7 @@ impl State {
continue 'next_lib;
}
log::warn!(
"{}: unable to find library {}, ignoring (this might produce wrong results)!",
path.display(),
library
);
anyhow::bail!("{}: unable to find library {}", path.display(), library);
}
Ok(())
@ -277,7 +257,7 @@ impl State {
{:?}
}}"
},
dot::Dot::with_attr_getters(
petgraph::dot::Dot::with_attr_getters(
&self.graph,
&[
dot::Config::NodeNoLabel,
@ -287,12 +267,10 @@ impl State {
&|_, _| { String::new() },
&|_, n| {
let paths = self.paths_map.get(&n.id()).unwrap();
let first_path = paths.iter().next().unwrap_or_else(|| {
panic!(
let first_path = paths.iter().next().expect(&format!(
"dso: you have a path map with an empty entry for inode {}",
n.id()
)
});
));
format!(
"label = \"({}, {})\"",
n.weight(),
@ -306,18 +284,13 @@ impl State {
)?;
Ok(())
}
}
// Contract: only relative paths starting from the sysroot dir should be returned from this function
fn determine_lib_search_paths(&self, path: &Path, elf: &Elf<'_>) -> Result<Vec<String>> {
log::trace!(
"{}: elf.runpaths = {:#?}, elf.rpaths = {:#?}",
path.display(),
elf.runpaths,
elf.rpaths
);
fn determine_lib_search_paths(path: &Path, elf: &Elf<'_>) -> Result<Vec<String>> {
let mut search_paths = vec![];
let current_dir = std::env::current_dir()?;
let origin = fs::canonicalize(path)?
let origin = std::fs::canonicalize(path)?
.parent()
.unwrap()
.strip_prefix(current_dir)?
@ -326,25 +299,45 @@ impl State {
.into_string()
.map_err(|s| anyhow::anyhow!("cannot represent {:?} as a UTF-8 string", s))?;
let mut search_paths = vec![];
if elf.runpaths.is_empty() {
search_paths.extend(collect_paths(&elf.rpaths, &origin));
if elf.rpaths != vec![""] {
if elf.runpaths != vec![""] {
let mut rpaths = elf
.rpaths
.iter()
.map(|p| p.replace("$ORIGIN", &origin))
.collect::<Vec<_>>();
search_paths.append(&mut rpaths);
}
search_paths.extend(self.ld_library_path.clone());
search_paths.extend(collect_paths(&elf.runpaths, &origin));
search_paths.extend(["usr/local/lib".into(), "lib".into(), "usr/lib".into()]);
search_paths.append(&mut get_env_library_paths());
}
if elf.runpaths != vec![""] {
let mut runpaths = elf
.runpaths
.iter()
.map(|p| p.replace("$ORIGIN", &origin))
.collect::<Vec<_>>();
search_paths.append(&mut runpaths);
}
search_paths.push("/usr/local/lib".into());
search_paths.push("/lib".into());
search_paths.push("/usr/lib".into());
Ok(search_paths)
}
}
fn collect_paths(elf_paths: &Vec<&str>, origin: &str) -> impl Iterator<Item = String> {
elf_paths
.iter()
.flat_map(|&p| p.split(':')) // Split multiple elements in r(un)?path separated by ':'
.filter(|&p| !p.is_empty()) // ignore empty items
.map(|p| p.replace("$ORIGIN", origin)) // replace $ORIGIN with path rel to sysroot
.map(|p| p.trim_start_matches('/').to_string()) // relativize paths from sysroot
fn get_env_library_paths() -> Vec<String> {
let ld_config_path = std::env::var("LD_LIBRARY_PATH");
ld_config_path
.as_ref()
.map(|env| {
env.split(':')
.filter(|s| s.is_empty())
.map(|s| s.into())
.collect()
})
.unwrap_or_default()
}
fn is_elf(f: &mut File) -> Result<bool> {