#[macro_use] extern crate clap;
#[macro_use] extern crate prettytable;
extern crate igniter;
extern crate ctrlc;
use igniter::os;
use igniter::monitor;
use igniter::monitor::Process;
use igniter::settings::Settings;
use clap::{Arg, App, SubCommand};
use std::process::{Command};
use prettytable::Table;
use prettytable::row::Row;
use prettytable::cell::Cell;
fn start_processes() {
println!("Starting processes found in .igniterc");
let settings = Settings::read();
let processes = settings.list_procs();
for p in processes {
let data = p.serialize().unwrap();
println!("Name: {}", p.data.name);
println!("Command: {}", p.data.cmd);
let child = Command::new(std::env::current_exe().unwrap())
.args(&[String::from("monitor"), data.clone()])
.spawn()
.expect("Error while starting command");
println!("Manager process started with PID: {}", child.id());
}
}
fn register_sigterm_handler(name: String) {
println!("Registering sigterm handler.");
ctrlc::set_handler(move || {
println!("SIGTERM arrived!");
let process = monitor::file::read(monitor::file::path_from_name(name.clone())).unwrap();
if let Ok(_) = os::kill(process.data.child_pid) {
println!("Child closed");
} else {
println!("error closing child");
}
}).expect("Error setting Ctrl-C handler");
}
fn monitor(data: &str) {
let mut process = Process::from(data);
register_sigterm_handler(process.data.name.clone());
monitor::start(&mut process);
monitor::file::delete(monitor::file::path_from_name(process.data.name)).unwrap();
}
fn list() {
let processes = monitor::active_processes();
let mut table = Table::new();
table.add_row(row!["MONITOR PID", "CHILD PID", "NAME", "COMMAND", "ARGS", "RETRIES", "MAX RETRIES"]);
for process in processes {
table.add_row(Row::new(vec![
Cell::new(format!("{}", process.data.monitor_pid).as_str()),
Cell::new(format!("{}", process.data.child_pid).as_str()),
Cell::new(process.data.name.as_str()),
Cell::new(process.data.cmd.as_str()),
Cell::new(format!("{:?}", process.data.args).as_str()),
Cell::new(format!("{:?}", process.data.retries).as_str()),
Cell::new(format!("{:?}", process.data.max_retries).as_str()),
]));
}
table.printstd();
}
fn stop(process_name: &str) {
if let Some(searched_process) = monitor::active_processes().iter().find(|p| { p.data.name == String::from(process_name)}) {
println!("Killing process {} with Monitor PID: {}", process_name, searched_process.data.monitor_pid.clone());
searched_process.kill().unwrap();
} else {
println!("Process {} not found", process_name);
}
}
fn main() {
let matches = App::new(crate_name!())
.version(crate_version!())
.author(crate_authors!("\n"))
.about("A simple process manager")
.subcommand(SubCommand::with_name("monitor")
.about("[INTERNAL] Monitors the provided command data as JSON")
.arg(Arg::with_name("data")
.help("Data needed to start the monitoring process.")
.index(1)
.required(true)
)
)
.subcommand(SubCommand::with_name("list")
.about("list active processes")
)
.subcommand(SubCommand::with_name("stop")
.about("Stops an already running process given its name")
.arg(Arg::with_name("process")
.help("The process to stop")
.index(1)
.required(true)
)
).get_matches();
match matches.subcommand() {
("monitor", Some(monitor_matches)) => monitor(monitor_matches.value_of("data").unwrap()),
("stop", Some(stop_matches)) => stop(stop_matches.value_of("process").unwrap()),
("list", Some(_)) => list(),
("", None) => start_processes(),
_ => unreachable!(),
}
}