fix(dso): allow specifying extra lib folders on the cmdline
Before we were relying on LD_LIBRARY_PATH, but it is misleading as it will most likely also affect the sysroot-cleaner binary itself. This instead introduces a separate command line argument, `--ld-path`, to specify a list of paths to search. Also includes some minor refactoring.
This commit is contained in:
parent
6d06377154
commit
1922297b4a
76
Cargo.lock
generated
76
Cargo.lock
generated
|
@ -73,12 +73,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.7"
|
||||
version = "3.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
|
||||
checksum = "6680de5231bd6ee4c6191b8a1325daa282b415391ec9d3a37bd34f2060dc73fa"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell",
|
||||
"once_cell_polyfill",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
|
@ -107,9 +107,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
|||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.74"
|
||||
version = "0.3.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
|
||||
checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cfg-if",
|
||||
|
@ -122,9 +122,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.0"
|
||||
version = "2.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
||||
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
|
@ -162,9 +162,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.37"
|
||||
version = "4.5.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071"
|
||||
checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
@ -172,9 +172,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.37"
|
||||
version = "4.5.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2"
|
||||
checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
@ -293,9 +293,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "goblin"
|
||||
version = "0.9.3"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "daa0a64d21a7eb230583b4c5f4e23b7e4e57974f96620f42a7e75e08ae66d745"
|
||||
checksum = "0e961b33649994dcf69303af6b3a332c1228549e604d455d61ec5d2ab5e68d3a"
|
||||
dependencies = [
|
||||
"log",
|
||||
"plain",
|
||||
|
@ -359,9 +359,9 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
|||
|
||||
[[package]]
|
||||
name = "jiff"
|
||||
version = "0.2.12"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d07d8d955d798e7a4d6f9c58cd1f1916e790b42b092758a9ef6e16fef9f1b3fd"
|
||||
checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93"
|
||||
dependencies = [
|
||||
"jiff-static",
|
||||
"log",
|
||||
|
@ -372,9 +372,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "jiff-static"
|
||||
version = "0.2.12"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f244cfe006d98d26f859c7abd1318d85327e1882dc9cef80f62daeeb0adcf300"
|
||||
checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -389,9 +389,9 @@ checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
|||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.12"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
|
||||
checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
|
@ -429,13 +429,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
|
||||
checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -460,16 +460,16 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.3"
|
||||
name = "once_cell_polyfill"
|
||||
version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.3"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
|
||||
checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
|
@ -477,9 +477,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.10"
|
||||
version = "0.9.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
||||
checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
|
@ -606,18 +606,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
|||
|
||||
[[package]]
|
||||
name = "scroll"
|
||||
version = "0.12.0"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6"
|
||||
checksum = "c1257cd4248b4132760d6524d6dda4e053bc648c9070b960929bf50cfb1e7add"
|
||||
dependencies = [
|
||||
"scroll_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scroll_derive"
|
||||
version = "0.12.1"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d"
|
||||
checksum = "22fc4f90c27b57691bbaf11d8ecc7cfbfe98a4da6dbe60226115d322aa80c06e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -661,9 +661,9 @@ checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
|||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.9"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef"
|
||||
checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
|
@ -688,7 +688,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sysroot-cleaner"
|
||||
version = "0.1.0"
|
||||
version = "0.9.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
@ -708,9 +708,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.44.2"
|
||||
version = "1.45.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
|
||||
checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
[package]
|
||||
name = "sysroot-cleaner"
|
||||
authors = ["Matteo Settenvini <matteo.settenvini@montecristosoftware.eu>"]
|
||||
version = "0.1.0"
|
||||
version = "0.9.0"
|
||||
edition = "2024"
|
||||
license = "EUPL-1.2"
|
||||
readme = "README.md"
|
||||
|
@ -16,11 +16,11 @@ clap = { version = "4.5", features = ["derive"] }
|
|||
env_logger = { version = "0.11" }
|
||||
ignore = { version = "0.4" }
|
||||
indoc = { version = "2.0" }
|
||||
goblin = { version = "0.9" }
|
||||
goblin = { version = "0.10" }
|
||||
log = { version = "0.4" }
|
||||
memmap2 = { version = "0.9" }
|
||||
nix = { version = "0.30", features = ["fs"] }
|
||||
petgraph = { version = "0.8" }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
walkdir = { version = "2" }
|
||||
bytesize = { version = "2.0" }
|
||||
bytesize = { version = "2.0" }
|
||||
|
|
18
src/args.rs
18
src/args.rs
|
@ -4,8 +4,8 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use clap::{
|
||||
Parser,
|
||||
builder::{PathBufValueParser, TypedValueParser},
|
||||
Parser,
|
||||
};
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
|
@ -59,4 +59,20 @@ 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)
|
||||
}
|
||||
|
|
|
@ -64,7 +64,10 @@ impl Runner {
|
|||
cleaners.push(Box::new(ListCleaner::new(list::ListType::Block, bl)));
|
||||
}
|
||||
|
||||
cleaners.push(Box::new(DsoCleaner::new(args.output_dotfile)));
|
||||
cleaners.push(Box::new(DsoCleaner::new(
|
||||
args.extra_library_paths,
|
||||
args.output_dotfile,
|
||||
)));
|
||||
|
||||
Self {
|
||||
cleaners,
|
||||
|
|
|
@ -27,17 +27,22 @@ 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(output_dot: Option<PathBuf>) -> Self {
|
||||
Self { output_dot }
|
||||
pub fn new(extra_library_paths: Vec<PathBuf>, output_dot: Option<PathBuf>) -> Self {
|
||||
Self {
|
||||
extra_library_paths,
|
||||
output_dot,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,6 +57,11 @@ 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);
|
||||
|
@ -127,7 +137,11 @@ impl Default for State {
|
|||
paths_map.insert(ROOT_NODE, HashSet::from([fake_root_node]));
|
||||
graph.add_node(ROOT_NODE);
|
||||
|
||||
Self { paths_map, graph }
|
||||
Self {
|
||||
ld_library_path: vec![],
|
||||
paths_map,
|
||||
graph,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,7 +210,7 @@ impl State {
|
|||
self.update_graph("".into(), ROOT_NODE, path.to_owned(), src.st_ino);
|
||||
}
|
||||
|
||||
let search_paths = determine_lib_search_paths(path, elf)?;
|
||||
let search_paths = self.determine_lib_search_paths(path, elf)?;
|
||||
log::trace!("determined search paths {:#?}", search_paths);
|
||||
|
||||
'next_lib: for &library in elf.libraries.iter() {
|
||||
|
@ -292,61 +306,45 @@ impl State {
|
|||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn determine_lib_search_paths(path: &Path, elf: &Elf<'_>) -> Result<Vec<String>> {
|
||||
log::trace!("elf.runpaths = {:#?}", elf.runpaths);
|
||||
log::trace!("elf.rpaths = {:#?}", elf.rpaths);
|
||||
// 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
|
||||
);
|
||||
|
||||
let mut search_paths = vec![];
|
||||
let current_dir = std::env::current_dir()?;
|
||||
let origin = fs::canonicalize(path)?
|
||||
.parent()
|
||||
.unwrap()
|
||||
.strip_prefix(current_dir)?
|
||||
.to_path_buf()
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.map_err(|s| anyhow::anyhow!("cannot represent {:?} as a UTF-8 string", s))?;
|
||||
|
||||
let current_dir = std::env::current_dir()?;
|
||||
let origin = fs::canonicalize(path)?
|
||||
.parent()
|
||||
.unwrap()
|
||||
.strip_prefix(current_dir)?
|
||||
.to_path_buf()
|
||||
.into_os_string()
|
||||
.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.runpaths.is_empty() {
|
||||
collect_paths(&elf.rpaths, &mut search_paths, &origin);
|
||||
}
|
||||
|
||||
search_paths.append(&mut get_env_library_paths());
|
||||
|
||||
collect_paths(&elf.runpaths, &mut search_paths, &origin);
|
||||
|
||||
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>, search_paths: &mut Vec<String>, origin: &str) {
|
||||
if elf_paths.iter().any(|p| !p.is_empty()) {
|
||||
let mut paths = elf_paths
|
||||
.iter()
|
||||
.flat_map(|p| p.split(':'))
|
||||
.map(|p| p.replace("$ORIGIN", origin))
|
||||
.map(|p| p.trim_start_matches('/').to_string())
|
||||
.collect::<Vec<_>>();
|
||||
search_paths.append(&mut paths);
|
||||
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()]);
|
||||
Ok(search_paths)
|
||||
}
|
||||
}
|
||||
|
||||
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 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 is_elf(f: &mut File) -> Result<bool> {
|
||||
|
|
Loading…
Reference in a new issue