use std::process::exit;
use getopts::Options;
use lxcrond::config::{Config, Job, VERBOSE};
use lxcrond::cron::Cron;
use lxcrond::watcher::Watcher;
use lxcrond::watcher_cron::WatcherCron;
use std::sync::atomic::Ordering;
use std::time::Duration;
use std::io::Write;
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
fn main() {
let args: Vec<String> = std::env::args().collect();
let program = args[0].clone();
let mut opts = Options::new();
opts.optopt ("c", "config", "specify config file, default is /etc/lxcrontab", "[conf_file]");
opts.optflag("h", "help", "print this help menu");
opts.optflag("v", "verbose", "print debug information to stdout");
opts.optflag("V", "version", "print version number and exit");
opts.optflag("f", "filesystem-watch", "use filesystem polling every 60 seconds to handle file jobs instead of inotify");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => panic!(f.to_string())
};
if matches.opt_present("h") {
print_usage(&program, opts);
}
if matches.opt_present("V") {
print_version();
}
if matches.opt_present("v") {
VERBOSE.store(true, Ordering::Relaxed)
} else {
no_hup()
}
let mut cfg;
if let Some(conf_file) = matches.opt_str("c") {
cfg = Config::read_config(conf_file.as_str());
} else {
cfg = Config::read_config("/etc/lxcrontab");
}
if cfg.len() == 0 {
exit(2);
}
if matches.opt_defined("f") {
start_watcher_cron(cfg.take_file_jobs());
} else {
if let Err(jobs) = start_watcher_inotify(cfg.take_file_jobs()) {
start_watcher_cron(jobs);
}
}
let cron = Cron::new(cfg.take_cron_jobs());
std::thread::spawn(move|| {
cron.run();
});
create_pid_file();
std::thread::sleep(Duration::new(u64::max_value(), 0));
}
fn start_watcher_cron(jobs: Vec<Job>) {
let mut watcher_cron = WatcherCron::new(jobs);
std::thread::spawn(move || {
watcher_cron.run()
});
}
fn start_watcher_inotify(jobs: Vec<Job>) -> Result<(), Vec<Job>> {
match Watcher::new(jobs) {
(Ok(watcher), None) => std::thread::spawn(move || watcher.run()),
(Err(_), Some(jobs)) => return Err(jobs),
_ => {
panic!("watcher should take the jobs or error and return them");
}
};
Ok(())
}
fn print_usage(program: &str, opts: Options) {
let brief = format!("Usage: {} [options]", program);
print!("{}", opts.usage(&brief));
exit(0);
}
fn print_version() {
println!("lxcrond {}", VERSION);
exit(0);
}
fn no_hup() {
unsafe {
libc::signal(1, libc::SIG_IGN);
libc::signal(2, libc::SIG_IGN);
}
}
fn create_pid_file() {
let pid = std::process::id().to_string();
if let Ok(mut file) = std::fs::File::create("/run/lxcrond.pid") {
if let Ok(()) = file.write_all(pid.as_bytes()) {
return;
}
}
if VERBOSE.load(Ordering::Relaxed) {
println!("could not write /run/lxcrond.pid");
}
}