512 lines
16 KiB
Rust
512 lines
16 KiB
Rust
// 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(true);
|
|
writeln!(&mut io::stdout(), "Done.");
|
|
}
|
|
"refresh_users" => {
|
|
writeln!(&mut io::stdout(), "Refreshing user list...");
|
|
users.refresh();
|
|
writeln!(&mut io::stdout(), "Done.");
|
|
}
|
|
"refresh_networks" => {
|
|
writeln!(&mut io::stdout(), "Refreshing network list...");
|
|
networks.refresh(true);
|
|
writeln!(&mut io::stdout(), "Done.");
|
|
}
|
|
"refresh_components" => {
|
|
writeln!(&mut io::stdout(), "Refreshing component list...");
|
|
components.refresh(true);
|
|
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: {}",
|
|
System::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(' ').filter(|s| !s.is_empty()).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);
|
|
writeln!(
|
|
&mut io::stdout(),
|
|
"Files open/limit: {:?}/{:?}",
|
|
p.open_files(),
|
|
p.open_files_limit(),
|
|
);
|
|
}
|
|
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: {}\n\
|
|
System kernel: {}",
|
|
System::name().unwrap_or_else(|| "<unknown>".to_owned()),
|
|
System::kernel_version().unwrap_or_else(|| "<unknown>".to_owned()),
|
|
System::os_version().unwrap_or_else(|| "<unknown>".to_owned()),
|
|
System::long_os_version().unwrap_or_else(|| "<unknown>".to_owned()),
|
|
System::host_name().unwrap_or_else(|| "<unknown>".to_owned()),
|
|
System::kernel_long_version(),
|
|
);
|
|
}
|
|
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,
|
|
);
|
|
}
|
|
}
|