1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
use crate::log::log_warning;
use crate::services::units::stop_all_services;
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<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...");
// Stop all services first
let _ = stop_all_services();
// 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(())
}
|