Skip to main content

onelf_sysroot/
lib.rs

1//! Pinned sysroots as a source of truth for what a bundle contains.
2//!
3//! A sysroot is a root filesystem with a package database. Every file in
4//! it belongs to a package, and every package declares what it depends
5//! on, so the set of files an application can reach is known before any
6//! ELF is inspected. That is what a host scan cannot offer: a `dlopen` by
7//! computed name, a plugin directory, a schema file are all invisible to
8//! `DT_NEEDED`, and all recorded in the database.
9//!
10//! The crate reads the database, computes closures, materializes a
11//! sysroot from an archive, and prunes a closure by the three tiers a
12//! recipe may declare: the platform line the host supplies, a policy of
13//! paths that never ship, and optionally the files a traced run never
14//! opened.
15
16pub mod archive;
17pub mod closure;
18pub mod db;
19pub mod ldconf;
20pub mod path;
21pub mod platform;
22pub mod prune;
23
24pub use closure::Closure;
25pub use db::{Database, Package};
26pub use platform::Pin;
27pub use prune::{PlatformLine, Policy, Pruned, Trace};
28
29/// Directories a distribution keeps shared libraries in, relative to a
30/// sysroot root: the flat legacy dirs and Debian's multiarch triplets.
31/// Package databases and traces name files under these without a leading
32/// slash.
33pub const LIB_DIRS: &[&str] = &[
34    "usr/lib",
35    "usr/lib64",
36    "usr/lib32",
37    "usr/lib/x86_64-linux-gnu",
38    "usr/lib/aarch64-linux-gnu",
39    "usr/lib/i386-linux-gnu",
40    "usr/lib/arm-linux-gnueabihf",
41    "lib",
42    "lib64",
43    "lib32",
44    "lib/x86_64-linux-gnu",
45    "lib/aarch64-linux-gnu",
46    "lib/i386-linux-gnu",
47    "lib/arm-linux-gnueabihf",
48];
49
50/// [`LIB_DIRS`] as absolute host paths.
51pub const LIB_PATHS: &[&str] = &[
52    "/usr/lib",
53    "/usr/lib64",
54    "/usr/lib32",
55    "/usr/lib/x86_64-linux-gnu",
56    "/usr/lib/aarch64-linux-gnu",
57    "/usr/lib/i386-linux-gnu",
58    "/usr/lib/arm-linux-gnueabihf",
59    "/lib",
60    "/lib64",
61    "/lib32",
62    "/lib/x86_64-linux-gnu",
63    "/lib/aarch64-linux-gnu",
64    "/lib/i386-linux-gnu",
65    "/lib/arm-linux-gnueabihf",
66];
67
68/// Whether `rel` (sysroot-relative) is a shared object sitting directly
69/// in a distribution library directory.
70///
71/// A host package owning such a file serves the host, not the bundle:
72/// its other files, Mesa's gallium and DRI drivers say, exist for that
73/// library, and so does what only it depended on.
74pub fn is_top_level_lib_object(rel: &str) -> bool {
75    let Some((dir, name)) = rel.rsplit_once('/') else {
76        return false;
77    };
78    LIB_DIRS.contains(&dir) && name.contains(".so")
79}
80
81#[cfg(test)]
82mod lib_dirs_tests {
83    use super::is_top_level_lib_object;
84
85    #[test]
86    fn top_level_libraries_in_flat_and_multiarch_dirs() {
87        assert!(is_top_level_lib_object("usr/lib/libGL.so.1"));
88        assert!(is_top_level_lib_object("usr/lib64/libEGL.so.1"));
89        assert!(is_top_level_lib_object(
90            "usr/lib/x86_64-linux-gnu/libEGL.so.1"
91        ));
92        assert!(is_top_level_lib_object("lib/aarch64-linux-gnu/libc.so.6"));
93    }
94
95    #[test]
96    fn nested_or_non_library_files_are_not_top_level() {
97        assert!(!is_top_level_lib_object("usr/lib/fixture/plugins/a.so"));
98        assert!(!is_top_level_lib_object("usr/bin/app"));
99        assert!(!is_top_level_lib_object("usr/share/doc/libfixture/README"));
100        assert!(!is_top_level_lib_object("libEGL.so.1"));
101    }
102}