#![feature(getpid)]
extern crate clap;
extern crate console;
extern crate regex;
extern crate libc;
#[macro_use]
extern crate lazy_static;
mod checkbox;
use std::ffi::CStr;
use std::process::{self, Command};
use regex::Regex;
use checkbox::Checkbox;
const PS_PATTERN: &'static str = concat!(
r"(?P<user>\S+)\s+",
r"(?P<pid>\S+)\s+",
r"(?P<cpu>\S+)\s+",
r"(?P<mem>\S+)\s+",
r"(?P<vsz>\S+)\s+",
r"(?P<rss>\S+)\s+",
r"(?P<tt>\S+)\s+",
r"(?P<stat>\S+)\s+",
r"(?P<started>\S+)\s+",
r"(?P<time>\S+)\s+",
r"(?P<command>.+)",
);
lazy_static! {
static ref PS_REGEX: Regex = Regex::new(PS_PATTERN).unwrap();
}
fn main() {
let matches = clap::App::new("Easy kill processes")
.arg(clap::Arg::with_name("pattern")
.takes_value(true)
.required(false)
.index(1))
.arg(clap::Arg::with_name("selected")
.long("selected")
.short("s")
.takes_value(false))
.get_matches();
let pattern = matches.value_of("pattern");
let selected = matches.is_present("selected");
if let Some(pattern) = pattern {
let mut ps_child = Command::new("ps")
.arg("aux")
.stdout(process::Stdio::piped())
.spawn()
.expect("ERROR: run `ps aux` failed");
let ps_pid = ps_child.id();
let output = ps_child.wait_with_output().unwrap();
let output_string = String::from_utf8_lossy(&output.stdout);
let pattern = Regex::new(pattern).unwrap();
let stats = output_string
.lines()
.skip(1)
.filter_map(|line| {
if pattern.is_match(line) {
let caps = PS_REGEX.captures(line).unwrap();
let pid = caps
.name("pid")
.map_or(0, |m| m.as_str().parse::<u32>().unwrap());
if pid != ps_pid && pid != process::id() {
let command = caps
.name("command")
.map_or("", |m| m.as_str());
return Some((pid, command));
}
}
None
})
.collect::<Vec<(u32, &str)>>();
if stats.is_empty() {
println!("WARNING: no process found!");
} else {
let items = stats
.iter()
.map(|&(pid, command)| format!("[{}]: {}", pid, command))
.collect::<Vec<String>>();
let selections = Checkbox::new()
.default(selected)
.items(items
.iter()
.map(|s| s.as_ref())
.collect::<Vec<&str>>()
.as_slice())
.interact()
.unwrap();
if selections.is_empty() {
println!("You did not select anything :(");
} else {
println!("You selected these processes:");
for selection in selections {
match unsafe { libc::kill(stats[selection].0 as i32, 15) } {
0 => println!(" success {}", items[selection]),
code @ _ => {
let err_msg = (unsafe {
CStr::from_ptr(libc::strerror(-code))
}).to_str().unwrap();
println!(" failed({}: {}) {}", code, err_msg, items[selection]);
},
}
}
}
}
} else {
println!("no pattern given!");
}
}