summaryrefslogtreecommitdiff
path: root/init/src/signals/sigterm.rs
diff options
context:
space:
mode:
authornamilsk <namilsk@namilsk.tech>2026-03-06 22:42:10 +0300
committernamilsk <namilsk@namilsk.tech>2026-03-06 22:42:10 +0300
commit772093279e1dd162a47e2dfe50d9a9ae0192d750 (patch)
tree49b10a7543cb43fe1c024f327bf7a55d791ccd0b /init/src/signals/sigterm.rs
parent733fa015a0499139a2dc171503fa48701fcba1d0 (diff)
implemented `SIGUSER/SIGINT/SIGTERM` handlers, graceful shutdown, logging to file
Diffstat (limited to 'init/src/signals/sigterm.rs')
-rw-r--r--init/src/signals/sigterm.rs108
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(())
+}