1use std::collections::VecDeque;
2use std::io::BufRead;
3use std::io::BufReader;
4use std::io::ErrorKind;
5use std::path::Path;
6use std::path::PathBuf;
7use std::process::Command;
8use std::process::Stdio;
9
10use crate::fs::File;
11use glob::glob;
12use log::log_enabled;
13use log::trace;
14use log::warn;
15use log::Level::Trace;
16
17pub fn get_search_dirs<P: AsRef<Path>>(rootfs_dir: P) -> Result<Vec<PathBuf>, std::io::Error> {
21 let rootfs_dir = rootfs_dir.as_ref();
22 let mut paths = Vec::new();
23 paths.extend([
24 rootfs_dir.join("lib"),
25 rootfs_dir.join("usr/local/lib"),
26 rootfs_dir.join("usr/lib"),
27 ]);
28 parse_ld_so_conf(rootfs_dir.join("etc/ld.so.conf"), rootfs_dir, &mut paths)?;
29 if log_enabled!(Trace) {
30 for path in paths.iter() {
31 trace!("Found system library path {:?}", path);
32 }
33 }
34 Ok(paths)
35}
36
37fn parse_ld_so_conf(
38 path: PathBuf,
39 rootfs_dir: &Path,
40 paths: &mut Vec<PathBuf>,
41) -> Result<(), std::io::Error> {
42 let mut conf_files = Vec::new();
43 let mut queue = VecDeque::new();
44 queue.push_back(path);
45 while let Some(path) = queue.pop_front() {
46 let file = match File::open(&path) {
47 Ok(file) => file,
48 Err(ref e) if e.kind() == ErrorKind::NotFound => continue,
49 Err(e) => {
50 warn!("Failed to open {path:?}: {e}");
51 continue;
52 }
53 };
54 conf_files.push(path);
55 let reader = BufReader::new(file);
56 for line in reader.lines() {
57 let line = line?;
58 let line = match line.find('#') {
59 Some(i) => &line[..i],
60 None => &line[..],
61 }
62 .trim();
63 if line.is_empty() {
64 continue;
65 }
66 if line.starts_with("include") {
67 let Some(i) = line.find(char::is_whitespace) else {
68 continue;
70 };
71 let pattern = if line.as_bytes().get(i + 1).copied() == Some(b'/') {
72 &line[i + 2..]
73 } else {
74 &line[i + 1..]
75 };
76 let pattern = rootfs_dir.join(pattern);
77 let Some(pattern) = pattern.to_str() else {
78 continue;
80 };
81 let Ok(more_paths) = glob(pattern) else {
82 continue;
84 };
85 for path in more_paths {
86 let Ok(path) = path else {
87 continue;
88 };
89 if !conf_files.contains(&path) {
90 queue.push_back(path);
91 }
92 }
93 }
94 if let Some(path) = line.strip_prefix("/") {
95 let path = rootfs_dir.join(path);
96 if !paths.contains(&path) {
97 paths.push(path);
98 }
99 }
100 }
101 }
102 Ok(())
103}
104
105pub fn get_hard_coded_search_dirs(
109 ld_so_exe: Option<Command>,
110) -> Result<Vec<PathBuf>, std::io::Error> {
111 let mut child = ld_so_exe
112 .unwrap_or_else(|| Command::new("ld.so"))
113 .arg("--list-diagnostics")
114 .stdin(Stdio::null())
115 .stdout(Stdio::piped())
116 .stderr(Stdio::null())
117 .spawn()?;
118 let mut paths = Vec::new();
119 if let Some(stdout) = child.stdout.take() {
120 let reader = BufReader::new(stdout);
121 for line in reader.lines() {
122 let line = line?;
123 let line = line.trim();
124 if !line.starts_with("path.system_dirs") {
125 continue;
126 }
127 let Some(i) = line.find('=') else {
128 continue;
129 };
130 let mut start = i + 1;
131 let mut end = line.len() - 1;
132 if line.as_bytes().get(i + 1) == Some(&b'"') {
134 start += 1;
135 }
136 if line.as_bytes().last() == Some(&b'"') {
137 end -= 1;
138 }
139 let path = &line[start..end];
140 paths.push(Path::new(path).to_path_buf());
141 }
142 }
143 Ok(paths)
144}