1#![crate_type = "bin"]
4#![allow(unused_must_use, non_upper_case_globals)]
5#![allow(clippy::manual_range_contains)]
6
7use std::io::{self, BufRead, Write};
8use std::str::FromStr;
9use sysinfo::{Components, Disks, Networks, Pid, Signal, System, Users};
10
11const signals: &[Signal] = &[
12 Signal::Hangup,
13 Signal::Interrupt,
14 Signal::Quit,
15 Signal::Illegal,
16 Signal::Trap,
17 Signal::Abort,
18 Signal::Bus,
19 Signal::FloatingPointException,
20 Signal::Kill,
21 Signal::User1,
22 Signal::Segv,
23 Signal::User2,
24 Signal::Pipe,
25 Signal::Alarm,
26 Signal::Term,
27 Signal::Child,
28 Signal::Continue,
29 Signal::Stop,
30 Signal::TSTP,
31 Signal::TTIN,
32 Signal::TTOU,
33 Signal::Urgent,
34 Signal::XCPU,
35 Signal::XFSZ,
36 Signal::VirtualAlarm,
37 Signal::Profiling,
38 Signal::Winch,
39 Signal::IO,
40 Signal::Power,
41 Signal::Sys,
42];
43
44fn print_help() {
45 writeln!(&mut io::stdout(), "== Help menu ==");
46 writeln!(&mut io::stdout(), "help : show this menu");
47 writeln!(
48 &mut io::stdout(),
49 "signals : show the available signals"
50 );
51 writeln!(
52 &mut io::stdout(),
53 "refresh : reloads all processes information"
54 );
55 writeln!(
56 &mut io::stdout(),
57 "refresh [pid] : reloads corresponding process information"
58 );
59 writeln!(
60 &mut io::stdout(),
61 "refresh_components : reloads components information"
62 );
63 writeln!(
64 &mut io::stdout(),
65 "refresh_cpu : reloads CPU information"
66 );
67 writeln!(
68 &mut io::stdout(),
69 "refresh_disks : reloads disks information"
70 );
71 writeln!(
72 &mut io::stdout(),
73 "refresh_users : reloads users information"
74 );
75 writeln!(
76 &mut io::stdout(),
77 "refresh_networks : reloads networks information"
78 );
79 writeln!(
80 &mut io::stdout(),
81 "show [pid | name] : show information of the given process \
82 corresponding to [pid | name]"
83 );
84 writeln!(
85 &mut io::stdout(),
86 "kill [pid] [signal]: send [signal] to the process with this \
87 [pid]. 0 < [signal] < 32"
88 );
89 writeln!(
90 &mut io::stdout(),
91 "cpus : Displays CPUs state"
92 );
93 writeln!(
94 &mut io::stdout(),
95 "memory : Displays memory state"
96 );
97 writeln!(
98 &mut io::stdout(),
99 "temperature : Displays components' temperature"
100 );
101 writeln!(
102 &mut io::stdout(),
103 "disks : Displays disks' information"
104 );
105 writeln!(
106 &mut io::stdout(),
107 "network : Displays network' information"
108 );
109 writeln!(
110 &mut io::stdout(),
111 "all : Displays all process name and pid"
112 );
113 writeln!(
114 &mut io::stdout(),
115 "uptime : Displays system uptime"
116 );
117 writeln!(
118 &mut io::stdout(),
119 "boot_time : Displays system boot time"
120 );
121 writeln!(
122 &mut io::stdout(),
123 "vendor_id : Displays CPU vendor id"
124 );
125 writeln!(&mut io::stdout(), "brand : Displays CPU brand");
126 writeln!(
127 &mut io::stdout(),
128 "load_avg : Displays system load average"
129 );
130 writeln!(
131 &mut io::stdout(),
132 "frequency : Displays CPU frequency"
133 );
134 writeln!(
135 &mut io::stdout(),
136 "users : Displays all users and their groups"
137 );
138 writeln!(
139 &mut io::stdout(),
140 "system : Displays system information (such as name, version and hostname)"
141 );
142 writeln!(
143 &mut io::stdout(),
144 "pid : Display this example's PID"
145 );
146 writeln!(&mut io::stdout(), "quit : Exit the program");
147}
148
149fn interpret_input(
150 input: &str,
151 sys: &mut System,
152 networks: &mut Networks,
153 disks: &mut Disks,
154 components: &mut Components,
155 users: &mut Users,
156) -> bool {
157 match input.trim() {
158 "help" => print_help(),
159 "refresh_disks" => {
160 writeln!(&mut io::stdout(), "Refreshing disk list...");
161 disks.refresh(true);
162 writeln!(&mut io::stdout(), "Done.");
163 }
164 "refresh_users" => {
165 writeln!(&mut io::stdout(), "Refreshing user list...");
166 users.refresh();
167 writeln!(&mut io::stdout(), "Done.");
168 }
169 "refresh_networks" => {
170 writeln!(&mut io::stdout(), "Refreshing network list...");
171 networks.refresh(true);
172 writeln!(&mut io::stdout(), "Done.");
173 }
174 "refresh_components" => {
175 writeln!(&mut io::stdout(), "Refreshing component list...");
176 components.refresh(true);
177 writeln!(&mut io::stdout(), "Done.");
178 }
179 "refresh_cpu" => {
180 writeln!(&mut io::stdout(), "Refreshing CPUs...");
181 sys.refresh_cpu_all();
182 writeln!(&mut io::stdout(), "Done.");
183 }
184 "signals" => {
185 let mut nb = 1i32;
186
187 for sig in signals {
188 writeln!(&mut io::stdout(), "{nb:2}:{sig:?}");
189 nb += 1;
190 }
191 }
192 "cpus" => {
193 writeln!(
196 &mut io::stdout(),
197 "number of physical cores: {}",
198 sys.physical_core_count()
199 .map(|c| c.to_string())
200 .unwrap_or_else(|| "Unknown".to_owned()),
201 );
202 writeln!(
203 &mut io::stdout(),
204 "total CPU usage: {}%",
205 sys.global_cpu_usage(),
206 );
207 for cpu in sys.cpus() {
208 writeln!(&mut io::stdout(), "{cpu:?}");
209 }
210 }
211 "memory" => {
212 writeln!(
213 &mut io::stdout(),
214 "total memory: {: >10} KB",
215 sys.total_memory() / 1_000
216 );
217 writeln!(
218 &mut io::stdout(),
219 "available memory: {: >10} KB",
220 sys.available_memory() / 1_000
221 );
222 writeln!(
223 &mut io::stdout(),
224 "used memory: {: >10} KB",
225 sys.used_memory() / 1_000
226 );
227 writeln!(
228 &mut io::stdout(),
229 "total swap: {: >10} KB",
230 sys.total_swap() / 1_000
231 );
232 writeln!(
233 &mut io::stdout(),
234 "used swap: {: >10} KB",
235 sys.used_swap() / 1_000
236 );
237 }
238 "quit" | "exit" => return true,
239 "all" => {
240 for (pid, proc_) in sys.processes() {
241 writeln!(
242 &mut io::stdout(),
243 "{}:{} status={:?}",
244 pid,
245 proc_.name().to_string_lossy(),
246 proc_.status()
247 );
248 }
249 }
250 "frequency" => {
251 for cpu in sys.cpus() {
252 writeln!(
253 &mut io::stdout(),
254 "[{}] {} MHz",
255 cpu.name(),
256 cpu.frequency(),
257 );
258 }
259 }
260 "vendor_id" => {
261 writeln!(
262 &mut io::stdout(),
263 "vendor ID: {}",
264 sys.cpus()[0].vendor_id()
265 );
266 }
267 "brand" => {
268 writeln!(&mut io::stdout(), "brand: {}", sys.cpus()[0].brand());
269 }
270 "load_avg" => {
271 let load_avg = System::load_average();
272 writeln!(&mut io::stdout(), "one minute : {}%", load_avg.one);
273 writeln!(&mut io::stdout(), "five minutes : {}%", load_avg.five);
274 writeln!(&mut io::stdout(), "fifteen minutes: {}%", load_avg.fifteen);
275 }
276 e if e.starts_with("show ") => {
277 let tmp: Vec<&str> = e.split(' ').collect();
278
279 if tmp.len() != 2 {
280 writeln!(
281 &mut io::stdout(),
282 "show command takes a pid or a name in parameter!"
283 );
284 writeln!(&mut io::stdout(), "example: show 1254");
285 } else if let Ok(pid) = Pid::from_str(tmp[1]) {
286 match sys.process(pid) {
287 Some(p) => writeln!(&mut io::stdout(), "{:?}", *p),
288 None => writeln!(&mut io::stdout(), "pid \"{pid:?}\" not found"),
289 };
290 } else {
291 let proc_name = tmp[1];
292 for proc_ in sys.processes_by_name(proc_name.as_ref()) {
293 writeln!(
294 &mut io::stdout(),
295 "==== {} ====",
296 proc_.name().to_string_lossy()
297 );
298 writeln!(&mut io::stdout(), "{proc_:?}");
299 }
300 }
301 }
302 "temperature" => {
303 for component in components.iter() {
304 writeln!(&mut io::stdout(), "{component:?}");
305 }
306 }
307 "network" => {
308 for (interface_name, data) in networks.iter() {
309 writeln!(
310 &mut io::stdout(),
311 "{}:\n ether {}\n input data (new / total): {} / {} B\n output data (new / total): {} / {} B",
312 interface_name,
313 data.mac_address(),
314 data.received(),
315 data.total_received(),
316 data.transmitted(),
317 data.total_transmitted(),
318 );
319 }
320 }
321 "show" => {
322 writeln!(
323 &mut io::stdout(),
324 "'show' command expects a pid number or a process name"
325 );
326 }
327 e if e.starts_with("kill ") => {
328 let tmp: Vec<&str> = e.split(' ').collect();
329
330 if tmp.len() != 3 {
331 writeln!(
332 &mut io::stdout(),
333 "kill command takes the pid and a signal number in parameter!"
334 );
335 writeln!(&mut io::stdout(), "example: kill 1254 9");
336 } else {
337 let pid = Pid::from_str(tmp[1]).unwrap();
338 let signal = i32::from_str(tmp[2]).unwrap();
339
340 if signal < 1 || signal > 31 {
341 writeln!(
342 &mut io::stdout(),
343 "Signal must be between 0 and 32 ! See the signals list with the \
344 signals command"
345 );
346 } else {
347 match sys.process(pid) {
348 Some(p) => {
349 if let Some(res) =
350 p.kill_with(*signals.get(signal as usize - 1).unwrap())
351 {
352 writeln!(&mut io::stdout(), "kill: {res}");
353 } else {
354 writeln!(
355 &mut io::stdout(),
356 "kill: signal not supported on this platform"
357 );
358 }
359 }
360 None => {
361 writeln!(&mut io::stdout(), "pid not found");
362 }
363 };
364 }
365 }
366 }
367 "disks" => {
368 for disk in disks {
369 writeln!(&mut io::stdout(), "{disk:?}");
370 }
371 }
372 "users" => {
373 for user in users {
374 writeln!(
375 &mut io::stdout(),
376 "{:?} => {:?}",
377 user.name(),
378 user.groups()
379 );
380 }
381 }
382 "boot_time" => {
383 writeln!(&mut io::stdout(), "{} seconds", System::boot_time());
384 }
385 "uptime" => {
386 let up = System::uptime();
387 let mut uptime = up;
388 let days = uptime / 86400;
389 uptime -= days * 86400;
390 let hours = uptime / 3600;
391 uptime -= hours * 3600;
392 let minutes = uptime / 60;
393 writeln!(
394 &mut io::stdout(),
395 "{days} days {hours} hours {minutes} minutes ({up} seconds in total)",
396 );
397 }
398 x if x.starts_with("refresh") => {
399 if x == "refresh" {
400 writeln!(&mut io::stdout(), "Getting processes' information...");
401 sys.refresh_all();
402 writeln!(&mut io::stdout(), "Done.");
403 } else if x.starts_with("refresh ") {
404 writeln!(&mut io::stdout(), "Getting process' information...");
405 if let Some(pid) = x
406 .split(' ')
407 .filter_map(|pid| pid.parse().ok())
408 .take(1)
409 .next()
410 {
411 if sys.refresh_processes(sysinfo::ProcessesToUpdate::Some(&[pid]), true) != 0 {
412 writeln!(&mut io::stdout(), "Process `{pid}` updated successfully");
413 } else {
414 writeln!(&mut io::stdout(), "Process `{pid}` couldn't be updated...");
415 }
416 } else {
417 writeln!(&mut io::stdout(), "Invalid [pid] received...");
418 }
419 } else {
420 writeln!(
421 &mut io::stdout(),
422 "\"{x}\": Unknown command. Enter 'help' if you want to get the commands' \
423 list.",
424 );
425 }
426 }
427 "pid" => {
428 writeln!(
429 &mut io::stdout(),
430 "PID: {}",
431 sysinfo::get_current_pid().expect("failed to get PID")
432 );
433 }
434 "system" => {
435 writeln!(
436 &mut io::stdout(),
437 "System name: {}\n\
438 System kernel version: {}\n\
439 System OS version: {}\n\
440 System OS (long) version: {}\n\
441 System host name: {}",
442 System::name().unwrap_or_else(|| "<unknown>".to_owned()),
443 System::kernel_version().unwrap_or_else(|| "<unknown>".to_owned()),
444 System::os_version().unwrap_or_else(|| "<unknown>".to_owned()),
445 System::long_os_version().unwrap_or_else(|| "<unknown>".to_owned()),
446 System::host_name().unwrap_or_else(|| "<unknown>".to_owned()),
447 );
448 }
449 e => {
450 writeln!(
451 &mut io::stdout(),
452 "\"{e}\": Unknown command. Enter 'help' if you want to get the commands' \
453 list.",
454 );
455 }
456 }
457 false
458}
459
460fn main() {
461 println!("Getting system information...");
462 let mut system = System::new_all();
463 let mut networks = Networks::new_with_refreshed_list();
464 let mut disks = Disks::new_with_refreshed_list();
465 let mut components = Components::new_with_refreshed_list();
466 let mut users = Users::new_with_refreshed_list();
467
468 println!("Done.");
469 let t_stin = io::stdin();
470 let mut stin = t_stin.lock();
471 let mut done = false;
472
473 println!("To get the commands' list, enter 'help'.");
474 while !done {
475 let mut input = String::new();
476 write!(&mut io::stdout(), "> ");
477 io::stdout().flush();
478
479 stin.read_line(&mut input);
480 if input.is_empty() {
481 println!("\nLeaving, bye!");
484 break;
485 }
486 if (&input as &str).ends_with('\n') {
487 input.pop();
488 }
489 done = interpret_input(
490 input.as_ref(),
491 &mut system,
492 &mut networks,
493 &mut disks,
494 &mut components,
495 &mut users,
496 );
497 }
498}