summaryrefslogtreecommitdiff
path: root/init/src/signals/sigterm.rs
blob: 0cf65eea42f675320ac6df77c749bee263d2017e (plain)
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
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(())
}