container_device_interface/
spec_dirs.rs1use std::{
2 collections::HashMap,
3 error::Error,
4 fmt, fs,
5 path::{Path, PathBuf},
6};
7
8use lazy_static::lazy_static;
9use path_clean::clean;
10
11use crate::{
12 cache::{Cache, CdiOption},
13 spec::{read_spec, Spec},
14 utils::is_cdi_spec,
15};
16
17const DEFAULT_STATIC_DIR: &str = "/etc/cdi";
19const DEFAULT_DYNAMIC_DIR: &str = "/var/run/cdi";
21
22lazy_static! {
23 pub static ref DEFAULT_SPEC_DIRS: &'static [&'static str] = &[
30 DEFAULT_STATIC_DIR,
31 DEFAULT_DYNAMIC_DIR,
32 ];
33}
34
35#[derive(Debug)]
36pub struct SpecError {
37 message: String,
38}
39
40impl SpecError {
41 pub fn new(info: &str) -> Self {
42 Self {
43 message: info.to_owned(),
44 }
45 }
46}
47
48impl fmt::Display for SpecError {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 write!(f, "spec error message {}", self.message)
51 }
52}
53
54impl Error for SpecError {}
55
56pub fn convert_errors(
57 spec_errors: &HashMap<String, Vec<Box<dyn Error>>>,
58) -> HashMap<String, Vec<Box<dyn Error + Send + Sync + 'static>>> {
59 spec_errors
60 .iter()
61 .map(|(key, value)| {
62 (
63 key.clone(),
64 value
65 .iter()
66 .map(|error| {
67 Box::new(SpecError::new(&error.to_string()))
68 as Box<dyn Error + Send + Sync + 'static>
69 })
70 .collect(),
71 )
72 })
73 .collect()
74}
75
76pub fn with_spec_dirs(dirs: &[&str]) -> CdiOption {
78 let cleaned_dirs: Vec<String> = dirs
79 .iter()
80 .map(|dir| {
81 clean(PathBuf::from(*dir))
82 .into_os_string()
83 .into_string()
84 .unwrap()
85 })
86 .collect();
87
88 Box::new(move |cache: &mut Cache| {
89 cache.spec_dirs.clone_from(&cleaned_dirs);
90 })
91}
92
93#[allow(dead_code)]
94fn traverse_dir<F>(dir_path: &Path, traverse_fn: &mut F) -> Result<(), Box<dyn Error>>
95where
96 F: FnMut(&Path) -> Result<(), Box<dyn Error>>,
97{
98 if let Ok(entries) = fs::read_dir(dir_path) {
99 for entry in entries.flatten() {
100 let path = entry.path();
101 if path.is_dir() {
102 traverse_dir(&path, traverse_fn)?;
103 } else {
104 traverse_fn(&path)?;
105 }
106 }
107 }
108 Ok(())
109}
110
111#[allow(dead_code)]
117pub(crate) fn scan_spec_dirs<P: AsRef<Path>>(dirs: &[P]) -> Result<Vec<Spec>, Box<dyn Error>> {
118 let mut scaned_specs = Vec::new();
119 for (priority, dir) in dirs.iter().enumerate() {
120 let dir_path = dir.as_ref();
121 if !dir_path.is_dir() {
122 continue;
123 }
124
125 let mut operation = |path: &Path| -> Result<(), Box<dyn Error>> {
126 if !path.is_dir() && is_cdi_spec(path) {
127 let spec = match read_spec(&path.to_path_buf(), priority as i32) {
128 Ok(spec) => spec,
129 Err(err) => {
130 return Err(Box::new(SpecError::new(&err.to_string())));
131 }
132 };
133 scaned_specs.push(spec);
134 }
135 Ok(())
136 };
137
138 if let Err(e) = traverse_dir(dir_path, &mut operation) {
139 return Err(Box::new(SpecError::new(&e.to_string())));
140 }
141 }
142
143 Ok(scaned_specs)
144}
145
146#[cfg(test)]
147mod tests {
148 }