// Take a look at the license at the top of the repository in the LICENSE file. #![crate_type = "bin"] #![allow(unused_must_use, non_upper_case_globals)] #![allow(clippy::manual_range_contains)] use std::io::{self, BufRead, Write}; use std::str::FromStr; use sysinfo::{Components, Disks, Networks, Pid, Signal, System, Users}; const signals: &[Signal] = &[ Signal::Hangup, Signal::Interrupt, Signal::Quit, Signal::Illegal, Signal::Trap, Signal::Abort, Signal::Bus, Signal::FloatingPointException, Signal::Kill, Signal::User1, Signal::Segv, Signal::User2, Signal::Pipe, Signal::Alarm, Signal::Term, Signal::Child, Signal::Continue, Signal::Stop, Signal::TSTP, Signal::TTIN, Signal::TTOU, Signal::Urgent, Signal::XCPU, Signal::XFSZ, Signal::VirtualAlarm, Signal::Profiling, Signal::Winch, Signal::IO, Signal::Power, Signal::Sys, ]; fn print_help() { writeln!(&mut io::stdout(), "== Help menu =="); writeln!(&mut io::stdout(), "help : show this menu"); writeln!( &mut io::stdout(), "signals : show the available signals" ); writeln!( &mut io::stdout(), "refresh : reloads all processes information" ); writeln!( &mut io::stdout(), "refresh [pid] : reloads corresponding process information" ); writeln!( &mut io::stdout(), "refresh_components : reloads components information" ); writeln!( &mut io::stdout(), "refresh_cpu : reloads CPU information" ); writeln!( &mut io::stdout(), "refresh_disks : reloads disks information" ); writeln!( &mut io::stdout(), "refresh_users : reloads users information" ); writeln!( &mut io::stdout(), "refresh_networks : reloads networks information" ); writeln!( &mut io::stdout(), "show [pid | name] : show information of the given process \ corresponding to [pid | name]" ); writeln!( &mut io::stdout(), "kill [pid] [signal]: send [signal] to the process with this \ [pid]. 0 < [signal] < 32" ); writeln!( &mut io::stdout(), "cpus : Displays CPUs state" ); writeln!( &mut io::stdout(), "memory : Displays memory state" ); writeln!( &mut io::stdout(), "temperature : Displays components' temperature" ); writeln!( &mut io::stdout(), "disks : Displays disks' information" ); writeln!( &mut io::stdout(), "network : Displays network' information" ); writeln!( &mut io::stdout(), "all : Displays all process name and pid" ); writeln!( &mut io::stdout(), "uptime : Displays system uptime" ); writeln!( &mut io::stdout(), "boot_time : Displays system boot time" ); writeln!( &mut io::stdout(), "vendor_id : Displays CPU vendor id" ); writeln!(&mut io::stdout(), "brand : Displays CPU brand"); writeln!( &mut io::stdout(), "load_avg : Displays system load average" ); writeln!( &mut io::stdout(), "frequency : Displays CPU frequency" ); writeln!( &mut io::stdout(), "users : Displays all users and their groups" ); writeln!( &mut io::stdout(), "system : Displays system information (such as name, version and hostname)" ); writeln!( &mut io::stdout(), "pid : Display this example's PID" ); writeln!(&mut io::stdout(), "quit : Exit the program"); } fn interpret_input( input: &str, sys: &mut System, networks: &mut Networks, disks: &mut Disks, components: &mut Components, users: &mut Users, ) -> bool { match input.trim() { "help" => print_help(), "refresh_disks" => { writeln!(&mut io::stdout(), "Refreshing disk list..."); disks.refresh_list(); writeln!(&mut io::stdout(), "Done."); } "refresh_users" => { writeln!(&mut io::stdout(), "Refreshing user list..."); users.refresh_list(); writeln!(&mut io::stdout(), "Done."); } "refresh_networks" => { writeln!(&mut io::stdout(), "Refreshing network list..."); networks.refresh_list(); writeln!(&mut io::stdout(), "Done."); } "refresh_components" => { writeln!(&mut io::stdout(), "Refreshing component list..."); components.refresh_list(); writeln!(&mut io::stdout(), "Done."); } "refresh_cpu" => { writeln!(&mut io::stdout(), "Refreshing CPUs..."); sys.refresh_cpu_all(); writeln!(&mut io::stdout(), "Done."); } "signals" => { let mut nb = 1i32; for sig in signals { writeln!(&mut io::stdout(), "{nb:2}:{sig:?}"); nb += 1; } } "cpus" => { // Note: you should refresh a few times before using this, so that usage statistics // can be ascertained writeln!( &mut io::stdout(), "number of physical cores: {}", sys.physical_core_count() .map(|c| c.to_string()) .unwrap_or_else(|| "Unknown".to_owned()), ); writeln!( &mut io::stdout(), "total CPU usage: {}%", sys.global_cpu_usage(), ); for cpu in sys.cpus() { writeln!(&mut io::stdout(), "{cpu:?}"); } } "memory" => { writeln!( &mut io::stdout(), "total memory: {: >10} KB", sys.total_memory() / 1_000 ); writeln!( &mut io::stdout(), "available memory: {: >10} KB", sys.available_memory() / 1_000 ); writeln!( &mut io::stdout(), "used memory: {: >10} KB", sys.used_memory() / 1_000 ); writeln!( &mut io::stdout(), "total swap: {: >10} KB", sys.total_swap() / 1_000 ); writeln!( &mut io::stdout(), "used swap: {: >10} KB", sys.used_swap() / 1_000 ); } "quit" | "exit" => return true, "all" => { for (pid, proc_) in sys.processes() { writeln!( &mut io::stdout(), "{}:{} status={:?}", pid, proc_.name().to_string_lossy(), proc_.status() ); } } "frequency" => { for cpu in sys.cpus() { writeln!( &mut io::stdout(), "[{}] {} MHz", cpu.name(), cpu.frequency(), ); } } "vendor_id" => { writeln!( &mut io::stdout(), "vendor ID: {}", sys.cpus()[0].vendor_id() ); } "brand" => { writeln!(&mut io::stdout(), "brand: {}", sys.cpus()[0].brand()); } "load_avg" => { let load_avg = System::load_average(); writeln!(&mut io::stdout(), "one minute : {}%", load_avg.one); writeln!(&mut io::stdout(), "five minutes : {}%", load_avg.five); writeln!(&mut io::stdout(), "fifteen minutes: {}%", load_avg.fifteen); } e if e.starts_with("show ") => { let tmp: Vec<&str> = e.split(' ').collect(); if tmp.len() != 2 { writeln!( &mut io::stdout(), "show command takes a pid or a name in parameter!" ); writeln!(&mut io::stdout(), "example: show 1254"); } else if let Ok(pid) = Pid::from_str(tmp[1]) { match sys.process(pid) { Some(p) => writeln!(&mut io::stdout(), "{:?}", *p), None => writeln!(&mut io::stdout(), "pid \"{pid:?}\" not found"), }; } else { let proc_name = tmp[1]; for proc_ in sys.processes_by_name(proc_name.as_ref()) { writeln!( &mut io::stdout(), "==== {} ====", proc_.name().to_string_lossy() ); writeln!(&mut io::stdout(), "{proc_:?}"); } } } "temperature" => { for component in components.iter() { writeln!(&mut io::stdout(), "{component:?}"); } } "network" => { for (interface_name, data) in networks.iter() { writeln!( &mut io::stdout(), "{}:\n ether {}\n input data (new / total): {} / {} B\n output data (new / total): {} / {} B", interface_name, data.mac_address(), data.received(), data.total_received(), data.transmitted(), data.total_transmitted(), ); } } "show" => { writeln!( &mut io::stdout(), "'show' command expects a pid number or a process name" ); } e if e.starts_with("kill ") => { let tmp: Vec<&str> = e.split(' ').collect(); if tmp.len() != 3 { writeln!( &mut io::stdout(), "kill command takes the pid and a signal number in parameter!" ); writeln!(&mut io::stdout(), "example: kill 1254 9"); } else { let pid = Pid::from_str(tmp[1]).unwrap(); let signal = i32::from_str(tmp[2]).unwrap(); if signal < 1 || signal > 31 { writeln!( &mut io::stdout(), "Signal must be between 0 and 32 ! See the signals list with the \ signals command" ); } else { match sys.process(pid) { Some(p) => { if let Some(res) = p.kill_with(*signals.get(signal as usize - 1).unwrap()) { writeln!(&mut io::stdout(), "kill: {res}"); } else { writeln!( &mut io::stdout(), "kill: signal not supported on this platform" ); } } None => { writeln!(&mut io::stdout(), "pid not found"); } }; } } } "disks" => { for disk in disks { writeln!(&mut io::stdout(), "{disk:?}"); } } "users" => { for user in users { writeln!( &mut io::stdout(), "{:?} => {:?}", user.name(), user.groups() ); } } "boot_time" => { writeln!(&mut io::stdout(), "{} seconds", System::boot_time()); } "uptime" => { let up = System::uptime(); let mut uptime = up; let days = uptime / 86400; uptime -= days * 86400; let hours = uptime / 3600; uptime -= hours * 3600; let minutes = uptime / 60; writeln!( &mut io::stdout(), "{days} days {hours} hours {minutes} minutes ({up} seconds in total)", ); } x if x.starts_with("refresh") => { if x == "refresh" { writeln!(&mut io::stdout(), "Getting processes' information..."); sys.refresh_all(); writeln!(&mut io::stdout(), "Done."); } else if x.starts_with("refresh ") { writeln!(&mut io::stdout(), "Getting process' information..."); if let Some(pid) = x .split(' ') .filter_map(|pid| pid.parse().ok()) .take(1) .next() { if sys.refresh_processes(sysinfo::ProcessesToUpdate::Some(&[pid]), true) != 0 { writeln!(&mut io::stdout(), "Process `{pid}` updated successfully"); } else { writeln!(&mut io::stdout(), "Process `{pid}` couldn't be updated..."); } } else { writeln!(&mut io::stdout(), "Invalid [pid] received..."); } } else { writeln!( &mut io::stdout(), "\"{x}\": Unknown command. Enter 'help' if you want to get the commands' \ list.", ); } } "pid" => { writeln!( &mut io::stdout(), "PID: {}", sysinfo::get_current_pid().expect("failed to get PID") ); } "system" => { writeln!( &mut io::stdout(), "System name: {}\n\ System kernel version: {}\n\ System OS version: {}\n\ System OS (long) version: {}\n\ System host name: {}", System::name().unwrap_or_else(|| "".to_owned()), System::kernel_version().unwrap_or_else(|| "".to_owned()), System::os_version().unwrap_or_else(|| "".to_owned()), System::long_os_version().unwrap_or_else(|| "".to_owned()), System::host_name().unwrap_or_else(|| "".to_owned()), ); } e => { writeln!( &mut io::stdout(), "\"{e}\": Unknown command. Enter 'help' if you want to get the commands' \ list.", ); } } false } fn main() { println!("Getting system information..."); let mut system = System::new_all(); let mut networks = Networks::new_with_refreshed_list(); let mut disks = Disks::new_with_refreshed_list(); let mut components = Components::new_with_refreshed_list(); let mut users = Users::new_with_refreshed_list(); println!("Done."); let t_stin = io::stdin(); let mut stin = t_stin.lock(); let mut done = false; println!("To get the commands' list, enter 'help'."); while !done { let mut input = String::new(); write!(&mut io::stdout(), "> "); io::stdout().flush(); stin.read_line(&mut input); if input.is_empty() { // The string is empty, meaning there is no '\n', meaning // that the user used CTRL+D so we can just quit! println!("\nLeaving, bye!"); break; } if (&input as &str).ends_with('\n') { input.pop(); } done = interpret_input( input.as_ref(), &mut system, &mut networks, &mut disks, &mut components, &mut users, ); } }