sysctl/linux/
ctl_iter.rs
1use super::ctl::Ctl;
4use ctl_error::SysctlError;
5use traits::Sysctl;
6
7pub struct CtlIter {
9 direntries: Vec<walkdir::DirEntry>,
10 base: String,
11 cur_idx: usize,
12}
13
14impl CtlIter {
15 pub fn root() -> Self {
17 let entries: Vec<walkdir::DirEntry> = walkdir::WalkDir::new("/proc/sys")
18 .sort_by(|a, b| a.path().cmp(b.path()))
19 .follow_links(false)
20 .into_iter()
21 .filter_map(|e| e.ok())
22 .filter(|e| e.file_type().is_file())
23 .collect();
24 CtlIter {
25 direntries: entries,
26 base: "/proc/sys".to_owned(),
27 cur_idx: 0,
28 }
29 }
30
31 pub fn below(node: Ctl) -> Self {
33 let root = node.path();
34 let entries: Vec<walkdir::DirEntry> = walkdir::WalkDir::new(&root)
35 .sort_by(|a, b| a.path().cmp(b.path()))
36 .follow_links(false)
37 .into_iter()
38 .filter_map(|e| e.ok())
39 .filter(|e| e.file_type().is_file())
40 .collect();
41 CtlIter {
42 direntries: entries,
43 base: root,
44 cur_idx: 0,
45 }
46 }
47}
48
49impl Iterator for CtlIter {
50 type Item = Result<Ctl, SysctlError>;
51
52 fn next(&mut self) -> Option<Self::Item> {
53 if self.cur_idx >= self.direntries.len() {
54 return None;
55 }
56
57 let e: &walkdir::DirEntry = &self.direntries[self.cur_idx];
58 self.cur_idx += 1;
59
60 if let Some(path) = e.path().to_str() {
62 if path.starts_with(&self.base) {
63 Some(Ctl::new(path))
64 } else {
65 None
66 }
67 } else {
68 Some(Err(SysctlError::ParseError))
69 }
70 }
71}
72
73impl IntoIterator for Ctl {
87 type Item = Result<Ctl, SysctlError>;
88 type IntoIter = CtlIter;
89
90 fn into_iter(self: Self) -> Self::IntoIter {
91 CtlIter::below(self)
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use crate::Sysctl;
98
99 #[test]
100 fn ctl_iter_iterate_all() {
101 let root = crate::CtlIter::root();
102 let all_ctls: Vec<super::Ctl> = root.into_iter().filter_map(Result::ok).collect();
103 assert_ne!(all_ctls.len(), 0);
104 for ctl in &all_ctls {
105 println!("{:?}", ctl.name());
106 }
107 }
108
109 #[test]
110 fn ctl_iter_below_compare_outputs() {
111 let output = std::process::Command::new("sysctl")
114 .arg("user")
115 .output()
116 .expect("failed to execute process");
117 let expected = String::from_utf8_lossy(&output.stdout);
118
119 let node = crate::Ctl::new("user").expect("could not get node");
120 let ctls = crate::CtlIter::below(node);
121 let mut actual: Vec<String> = vec![];
122
123 for ctl in ctls {
124 let ctl = match ctl {
125 Err(_) => panic!("ctl error"),
126 Ok(s) => s,
127 };
128
129 let name = match ctl.name() {
130 Ok(s) => s,
131 Err(_) => panic!("get ctl name"),
132 };
133
134 match ctl.value_type().expect("could not get value type") {
135 crate::CtlType::String => {
136 actual.push(format!(
137 "{} = {}",
138 name,
139 ctl.value_string()
140 .expect(&format!("could not get value as string for {}", name))
141 ));
142 }
143 _ => panic!("sysctl not string type"),
144 };
145 }
146 assert_eq!(actual.join("\n").trim(), expected.trim());
147 }
148}