use crate::log::log_warning; use libc::{ SA_RESTART, SA_SIGINFO, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, 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> { 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> { 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(()) }