1use std::fs;
34use std::path::{Path, PathBuf};
35
36pub mod loadavg;
37pub mod meminfo;
38pub mod stat;
39pub mod uptime;
40pub mod vmstat;
41
42pub mod diskstats;
43pub mod netdevs;
44
45pub mod cpufreqs;
46pub mod pidentries;
47
48mod parser;
49mod util;
50
51pub type Pid = i32;
52
53pub struct System {
55 base_path: PathBuf,
56 fb: util::FileBuffer,
57}
58
59impl System {
60 pub fn new<P: AsRef<Path>>(base_path: P) -> Self {
68 Self {
69 base_path: base_path.as_ref().to_path_buf(),
70 fb: util::FileBuffer::new(),
71 }
72 }
73 pub fn get_loadavg(&mut self) -> loadavg::LoadAvg {
76 static PROC_FB: util::ProcFb = util::ProcFb {
77 capacity: 40,
78 name: "loadavg",
79 };
80 let slice = PROC_FB.update(&self.base_path, &mut self.fb);
81 parser::loadavg::LoadAvgParser::default().parse(slice)
82 }
83 pub fn get_meminfo(&mut self) -> meminfo::MemInfo {
86 static PROC_FB: util::ProcFb = util::ProcFb {
87 capacity: 1300,
88 name: "meminfo",
89 };
90 let slice = PROC_FB.update(&self.base_path, &mut self.fb);
91 parser::meminfo::MemInfoParser::default().parse(slice)
92 }
93 pub fn get_stat(&mut self) -> stat::Stat {
96 static PROC_FB: util::ProcFb = util::ProcFb {
97 capacity: 1500,
98 name: "stat",
99 };
100 let slice = PROC_FB.update(&self.base_path, &mut self.fb);
101 parser::stat::StatParser::default().parse(slice)
102 }
103 pub fn get_uptime(&mut self) -> uptime::Uptime {
106 static PROC_FB: util::ProcFb = util::ProcFb {
107 capacity: 30,
108 name: "uptime",
109 };
110 let slice = PROC_FB.update(&self.base_path, &mut self.fb);
111 parser::uptime::UptimeParser::default().parse(slice)
112 }
113 pub fn get_vmstat(&mut self) -> vmstat::VmStat {
116 static PROC_FB: util::ProcFb = util::ProcFb {
117 capacity: 2600,
118 name: "vmstat",
119 };
120 let slice = PROC_FB.update(&self.base_path, &mut self.fb);
121 parser::vmstat::VmStatParser::default().parse(slice)
122 }
123 pub fn get_diskstats(&mut self) -> diskstats::DiskStats {
126 static PROC_FB: util::ProcFb = util::ProcFb {
127 capacity: 3000,
128 name: "diskstats",
129 };
130 let slice = PROC_FB.update(&self.base_path, &mut self.fb);
131 parser::diskstats::DiskStatsParser::default().parse(slice)
132 }
133 pub fn get_netdevs(&mut self) -> netdevs::NetDevs {
136 static PROC_FB: util::ProcFb = util::ProcFb {
137 capacity: 2000,
138 name: "net/dev",
139 };
140 let slice = PROC_FB.update(&self.base_path, &mut self.fb);
141 parser::netdevs::NetDevsParser::default().parse(slice)
142 }
143 pub fn get_max_cpu_num(&mut self) -> usize {
146 let mut max_cpu_num = 0;
147 let cpu_path = format!(
149 "{}/sys/devices/system/cpu",
150 &self.base_path.to_str().unwrap()
151 );
152 for entry in fs::read_dir(cpu_path).unwrap() {
153 let entry = entry.unwrap();
154 let os_name = entry.file_name();
155 let name = os_name.to_string_lossy();
156 if name.starts_with("cpu") && name.len() > 3 {
157 let sl = &name[3..];
158 if let Ok(n) = sl.parse::<usize>() {
159 if n > max_cpu_num {
160 max_cpu_num = n;
161 }
162 }
163 }
164 }
165 max_cpu_num + 1
167 }
168 pub fn get_cpufreqs(&mut self, max_cpu_num: usize) -> cpufreqs::CpuFreqs {
171 static SYS_CPUFREQ_CUR: util::SysCpuFb = util::SysCpuFb {
172 capacity: 10,
173 name: "cpufreq/cpuinfo_cur_freq",
174 };
175 static SYS_CPUFREQ_MAX: util::SysCpuFb = util::SysCpuFb {
176 capacity: 10,
177 name: "cpufreq/cpuinfo_max_freq",
178 };
179 static SYS_CPUFREQ_STATS_TIME_IN_STATE: util::SysCpuFb = util::SysCpuFb {
180 capacity: 100,
181 name: "cpufreq/stats/time_in_state",
182 };
183 let mut cpufreqs = cpufreqs::CpuFreqs::default();
185 cpufreqs
186 .cpufreqs
187 .resize(max_cpu_num, cpufreqs::CpuFreq::default());
188 for idx in 0..max_cpu_num {
189 let cpufreq = &mut cpufreqs.cpufreqs[idx];
190 cpufreq.cur = {
191 let slice = SYS_CPUFREQ_CUR.update_with_cpu_num(&self.base_path, &mut self.fb, idx);
192 parser::cpufreqs::CpuFreqMaxParser::default().parse(slice)
193 };
194 cpufreq.max = {
195 let slice = SYS_CPUFREQ_MAX.update_with_cpu_num(&self.base_path, &mut self.fb, idx);
196 parser::cpufreqs::CpuFreqMaxParser::default().parse(slice)
197 };
198 cpufreq.time_in_states = {
199 let slice = SYS_CPUFREQ_STATS_TIME_IN_STATE.update_with_cpu_num(
200 &self.base_path,
201 &mut self.fb,
202 idx,
203 );
204 parser::cpufreqs::CpuFreqStatsTimeInStateParser::default().parse(slice)
205 };
206 }
207 cpufreqs
208 }
209 pub fn get_pids(&mut self) -> Vec<Pid> {
212 let mut v_pid = Vec::new();
213 let proc_path = format!("{}/proc", &self.base_path.to_str().unwrap());
215 for entry in fs::read_dir(proc_path).unwrap() {
216 let entry = entry.unwrap();
217 let os_name = entry.file_name();
218 let name = os_name.to_string_lossy();
219 if name.as_bytes().iter().any(|&b| !b.is_ascii_digit()) {
220 continue;
221 }
222 let pid: Pid = name.parse().unwrap();
223 v_pid.push(pid);
224 }
225 v_pid.sort_unstable();
226 v_pid
228 }
229 pub fn get_pidentries(&mut self) -> pidentries::PidEntries {
232 let pid_vec = self.get_pids();
233 let mut pids = pidentries::PidEntries::default();
235 pids.pidentries
236 .resize(pid_vec.len(), pidentries::PidEntry::default());
237 for (idx, &pid) in pid_vec.iter().enumerate() {
238 let pidentry = &mut pids.pidentries[idx];
239 pidentry.is_empty = true;
240 pidentry.stat = match self.get_pidentry_stat(pid) {
242 Some(a) => a,
243 None => continue,
244 };
245 pidentry.statm = match self.get_pidentry_statm(pid) {
246 Some(a) => a,
247 None => continue,
248 };
249 pidentry.status = match self.get_pidentry_status(pid) {
250 Some(a) => a,
251 None => continue,
252 };
253 pidentry.cmdline = match self.get_pidentry_cmdline(pid) {
254 Some(a) => a,
255 None => continue,
256 };
257 pidentry.is_empty = false;
259 }
260 pids
261 }
262 pub fn get_pidentry_stat(&mut self, pid: Pid) -> Option<pidentries::PidStat> {
265 static PIDPROCS_STAT: util::PidFb = util::PidFb {
266 capacity: 400,
267 name: "stat",
268 };
269 let slice = PIDPROCS_STAT.update_with_pid(&self.base_path, &mut self.fb, pid);
270 if !slice.is_empty() {
271 Some(parser::pidstat::PidStatParser::default().parse(slice))
272 } else {
273 None
274 }
275 }
276 pub fn get_pidentry_statm(&mut self, pid: Pid) -> Option<pidentries::PidStatm> {
279 static PIDPROCS_STATM: util::PidFb = util::PidFb {
280 capacity: 40,
281 name: "statm",
282 };
283 let slice = PIDPROCS_STATM.update_with_pid(&self.base_path, &mut self.fb, pid);
284 if !slice.is_empty() {
285 Some(parser::pidstatm::PidStatmParser::default().parse(slice))
286 } else {
287 None
288 }
289 }
290 pub fn get_pidentry_status(&mut self, pid: Pid) -> Option<pidentries::PidStatus> {
293 static PIDPROCS_STATUS: util::PidFb = util::PidFb {
294 capacity: 1100,
295 name: "status",
296 };
297 let slice = PIDPROCS_STATUS.update_with_pid(&self.base_path, &mut self.fb, pid);
298 if !slice.is_empty() {
299 Some(parser::pidstatus::PidStatusParser::default().parse(slice))
300 } else {
301 None
302 }
303 }
304 pub fn get_pidentry_cmdline(&mut self, pid: Pid) -> Option<pidentries::PidCmdline> {
307 static PIDPROCS_CMDLINE: util::PidFb = util::PidFb {
308 capacity: 600,
309 name: "cmdline",
310 };
311 let slice = PIDPROCS_CMDLINE.update_with_pid(&self.base_path, &mut self.fb, pid);
312 if !slice.is_empty() {
313 Some(parser::pidcmdline::PidCmdlineParser::default().parse(slice))
314 } else {
315 None
316 }
317 }
318 pub fn get_pidentry_comm(&mut self, pid: Pid) -> Option<pidentries::PidCmdline> {
321 static PIDPROCS_COMM: util::PidFb = util::PidFb {
322 capacity: 600,
323 name: "comm",
324 };
325 let slice = PIDPROCS_COMM.update_with_pid(&self.base_path, &mut self.fb, pid);
326 if !slice.is_empty() {
327 Some(parser::pidcmdline::PidCmdlineParser::default().parse(slice))
328 } else {
329 None
330 }
331 }
332}