#![deny(missing_docs)]
#![deny(warnings)]
use log::warn;
use nix::sys::signal::{SigSet, Signal};
use nix::sys::signal::{SIGHUP, SIGINT, SIGQUIT, SIGTERM};
use std::os::unix::io::RawFd;
use std::thread;
use crate::common::{NitroCliErrorEnum, NitroCliFailure, NitroCliResult};
use crate::new_nitro_cli_failure;
pub struct SignalHandler {
sig_set: Option<SigSet>,
}
impl SignalHandler {
pub fn new(signals: &[Signal]) -> Self {
let mut sig_set = SigSet::empty();
for signal in signals.iter() {
sig_set.add(*signal);
}
SignalHandler {
sig_set: Some(sig_set),
}
}
pub fn new_with_defaults() -> Self {
SignalHandler::new(&[SIGINT, SIGQUIT, SIGTERM, SIGHUP])
}
pub fn mask_all(self) -> NitroCliResult<Self> {
if let Some(set) = self.sig_set {
set.thread_block().map_err(|e| {
new_nitro_cli_failure!(
&format!("Masking signals covered by handler failed: {e:?}"),
NitroCliErrorEnum::SignalMaskingError
)
})?;
}
Ok(self)
}
pub fn unmask_all(self) -> NitroCliResult<Self> {
if let Some(set) = self.sig_set {
set.thread_unblock().map_err(|e| {
new_nitro_cli_failure!(
&format!("Unmasking signals covered by handler failed: {e:?}"),
NitroCliErrorEnum::SignalUnmaskingError
)
})?;
}
Ok(self)
}
pub fn start_handler(&mut self, fd: RawFd, handler: fn(RawFd, Signal) -> bool) {
if self.sig_set.is_none() {
return;
}
let thread_sig_set = self.sig_set.take().unwrap();
thread::spawn(move || {
let mut stop = false;
while !stop {
stop = match thread_sig_set.wait() {
Ok(signal) => handler(fd, signal),
Err(e) => {
warn!("Error listening for signals: {}", e);
true
}
};
}
});
}
}