diff options
Diffstat (limited to 'init/src/signals/sigterm.rs')
| -rw-r--r-- | init/src/signals/sigterm.rs | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/init/src/signals/sigterm.rs b/init/src/signals/sigterm.rs new file mode 100644 index 0000000..0cf65ee --- /dev/null +++ b/init/src/signals/sigterm.rs @@ -0,0 +1,108 @@ +use crate::log::log_warning; + +use libc::{ + SA_RESTART, SA_SIGINFO, SIGINT, SIGUSR1, SIGUSR2, SIGTERM, WNOHANG, c_int, sigaction, siginfo_t, + sigset_t, waitpid, +}; +use std::os::raw::c_void; +use std::sync::atomic::{AtomicBool, Ordering}; + +// Shutdown handler +pub static SHUTDOWN_REQUESTED: AtomicBool = AtomicBool::new(false); + +/// reload config (SIGUSR1) +pub static RELOAD_REQUESTED: AtomicBool = AtomicBool::new(false); + +/// debug dump (SIGUSR2) +pub static DEBUG_DUMP_REQUESTED: AtomicBool = AtomicBool::new(false); + +extern "C" fn shutdown_handler(_signal: c_int, _info: *mut siginfo_t, _context: *mut c_void) { + let saved_errno = unsafe { *libc::__errno_location() }; + SHUTDOWN_REQUESTED.store(true, Ordering::SeqCst); + unsafe { *libc::__errno_location() = saved_errno }; +} + +extern "C" fn sigusr1_handler(_signal: c_int, _info: *mut siginfo_t, _context: *mut c_void) { + let saved_errno = unsafe { *libc::__errno_location() }; + RELOAD_REQUESTED.store(true, Ordering::SeqCst); + unsafe { *libc::__errno_location() = saved_errno }; +} + +extern "C" fn sigusr2_handler(_signal: c_int, _info: *mut siginfo_t, _context: *mut c_void) { + let saved_errno = unsafe { *libc::__errno_location() }; + DEBUG_DUMP_REQUESTED.store(true, Ordering::SeqCst); + unsafe { *libc::__errno_location() = saved_errno }; +} + +/// SIGTERM, SIGINT, SIGUSR1, SIGUSR2 +pub fn setup_signal_handlers() -> Result<(), Box<dyn std::error::Error>> { + unsafe { + // SIGTERM handler + let mut sigact_term: sigaction = std::mem::zeroed(); + sigact_term.sa_sigaction = shutdown_handler as *const () as usize; + sigact_term.sa_flags = SA_RESTART | SA_SIGINFO; + libc::sigemptyset(&mut sigact_term.sa_mask as *mut sigset_t); + libc::sigaddset(&mut sigact_term.sa_mask as *mut sigset_t, SIGTERM); + + if libc::sigaction(SIGTERM, &sigact_term, std::ptr::null_mut()) == -1 { + return Err("Failed to set SIGTERM handler".into()); + } + + // SIGINT handler + let mut sigact_int: sigaction = std::mem::zeroed(); + sigact_int.sa_sigaction = shutdown_handler as *const () as usize; + sigact_int.sa_flags = SA_RESTART | SA_SIGINFO; + libc::sigemptyset(&mut sigact_int.sa_mask as *mut sigset_t); + libc::sigaddset(&mut sigact_int.sa_mask as *mut sigset_t, SIGINT); + + if libc::sigaction(SIGINT, &sigact_int, std::ptr::null_mut()) == -1 { + return Err("Failed to set SIGINT handler".into()); + } + + // SIGUSR1 handler (reload config) + let mut sigact_usr1: sigaction = std::mem::zeroed(); + sigact_usr1.sa_sigaction = sigusr1_handler as *const () as usize; + sigact_usr1.sa_flags = SA_RESTART | SA_SIGINFO; + libc::sigemptyset(&mut sigact_usr1.sa_mask as *mut sigset_t); + libc::sigaddset(&mut sigact_usr1.sa_mask as *mut sigset_t, SIGUSR1); + + if libc::sigaction(SIGUSR1, &sigact_usr1, std::ptr::null_mut()) == -1 { + return Err("Failed to set SIGUSR1 handler".into()); + } + + // SIGUSR2 handler (debug dump) + let mut sigact_usr2: sigaction = std::mem::zeroed(); + sigact_usr2.sa_sigaction = sigusr2_handler as *const () as usize; + sigact_usr2.sa_flags = SA_RESTART | SA_SIGINFO; + libc::sigemptyset(&mut sigact_usr2.sa_mask as *mut sigset_t); + libc::sigaddset(&mut sigact_usr2.sa_mask as *mut sigset_t, SIGUSR2); + + if libc::sigaction(SIGUSR2, &sigact_usr2, std::ptr::null_mut()) == -1 { + return Err("Failed to set SIGUSR2 handler".into()); + } + } + + Ok(()) +} + +/// Graceful shutdown +pub fn graceful_shutdown() -> Result<(), Box<dyn std::error::Error>> { + log_warning("Graceful shutdown initiated..."); + + // Reap all remaining children + loop { + let mut status: c_int = 0; + let pid = unsafe { waitpid(-1, &mut status as *mut c_int, WNOHANG) }; + if pid <= 0 { + break; + } + } + + // Sync filesystems + unsafe { + libc::sync(); + } + + log_warning("All services stopped. Filesystems synced."); + Ok(()) +} |
