use std::sync::atomic::AtomicBool;
use netpulse::errors::RunError;
use netpulse::records::display_group;
use netpulse::DAEMON_PID_FILE;
use nix::sys::signal::{self, SigHandler, Signal};
use netpulse::store::Store;
use tracing::{error, info};
use crate::USES_DAEMON_SYSTEM;
static TERMINATE: AtomicBool = AtomicBool::new(false);
static RESTART: AtomicBool = AtomicBool::new(false);
pub(crate) fn daemon() {
signal_hook();
info!("starting daemon...");
let mut store = load_store();
info!("store loaded, entering main loop");
loop {
if TERMINATE.load(std::sync::atomic::Ordering::Relaxed) {
info!("terminating the daemon");
if let Err(e) = cleanup(&store) {
error!("could not clean up before terminating: {e:#?}");
}
std::process::exit(1);
}
if RESTART.load(std::sync::atomic::Ordering::Relaxed) {
info!("restarting the daemon");
store = load_store();
}
if chrono::Utc::now().timestamp() % store.period_seconds() == 0 {
if let Err(err) = wakeup(&mut store) {
error!("error in the wakeup turn: {err}");
}
}
std::thread::sleep(std::time::Duration::from_secs(1));
}
}
fn load_store() -> Store {
match Store::load_or_create() {
Err(e) => {
error!("{e}");
if let Err(e) = cleanup_without_store() {
error!("error while trying to cleanup: {e}");
}
std::process::exit(1)
}
Ok(s) => s,
}
}
fn wakeup(store: &mut Store) -> Result<(), RunError> {
info!("waking up!");
let mut buf = String::new();
display_group(&store.make_checks(), &mut buf)?;
info!("Made checks\n{buf}");
if let Err(err) = store.save() {
error!("error while saving to file: {err:}");
}
info!("done!");
Ok(())
}
fn signal_hook() {
unsafe {
signal::signal(Signal::SIGTERM, SigHandler::Handler(handle_signal))
.expect("failed to set up signal handler");
}
}
fn cleanup(store: &Store) -> Result<(), RunError> {
if let Err(err) = store.save() {
error!("error while saving to file: {err:#?}");
return Err(err.into());
}
cleanup_without_store()?;
Ok(())
}
fn cleanup_without_store() -> Result<(), RunError> {
if USES_DAEMON_SYSTEM.load(std::sync::atomic::Ordering::Relaxed) {
if let Err(err) = std::fs::remove_file(DAEMON_PID_FILE) {
if matches!(err.kind(), std::io::ErrorKind::NotFound) {
} else {
error!("Failed to remove PID file: {}", err);
return Err(err.into());
}
}
}
Ok(())
}
extern "C" fn handle_signal(signal: i32) {
let signal: nix::sys::signal::Signal =
nix::sys::signal::Signal::try_from(signal).expect("got an undefined SIGNAL");
match signal {
Signal::SIGTERM => {
TERMINATE.store(true, std::sync::atomic::Ordering::Relaxed);
}
Signal::SIGHUP => {
RESTART.store(true, std::sync::atomic::Ordering::Relaxed);
}
_ => {
TERMINATE.store(true, std::sync::atomic::Ordering::Relaxed);
}
}
}