diff options
| author | namilsk <namilsk@namilsk.tech> | 2026-03-06 22:42:10 +0300 |
|---|---|---|
| committer | namilsk <namilsk@namilsk.tech> | 2026-03-06 22:42:10 +0300 |
| commit | 772093279e1dd162a47e2dfe50d9a9ae0192d750 (patch) | |
| tree | 49b10a7543cb43fe1c024f327bf7a55d791ccd0b | |
| parent | 733fa015a0499139a2dc171503fa48701fcba1d0 (diff) | |
implemented `SIGUSER/SIGINT/SIGTERM` handlers, graceful shutdown, logging to file
| -rw-r--r-- | init/src/log.rs | 35 | ||||
| -rw-r--r-- | init/src/main.rs | 39 | ||||
| -rw-r--r-- | init/src/signals/mod.rs | 1 | ||||
| -rw-r--r-- | init/src/signals/sigterm.rs | 108 |
4 files changed, 178 insertions, 5 deletions
diff --git a/init/src/log.rs b/init/src/log.rs index 4c89dd1..207394b 100644 --- a/init/src/log.rs +++ b/init/src/log.rs @@ -1,11 +1,46 @@ +use std::fs::OpenOptions; +use std::io::Write; +use std::sync::Mutex; + +const LOG_FILE_PATH: &str = "/var/log/vigil.log"; + +static LOG_FILE: Mutex<Option<std::fs::File>> = Mutex::new(None); + +/// Инициализирует файл логирования. Должен вызываться один раз при старте. +pub fn init_logging() -> Result<(), Box<dyn std::error::Error>> { + let file = OpenOptions::new() + .create(true) + .append(true) + .open(LOG_FILE_PATH)?; + + let mut guard = LOG_FILE.lock().map_err(|e| e.to_string())?; + *guard = Some(file); + Ok(()) +} + +fn write_to_log(message: &str) { + let mut guard = match LOG_FILE.lock() { + Ok(g) => g, + Err(poisoned) => poisoned.into_inner(), + }; + + if let Some(ref mut file) = *guard { + let _ = writeln!(file, "{}", message); + let _ = file.flush(); + } +} + pub fn log_critical_error(message: &str) { println!("\x1b[31m * \x1b[0m {}", message); + write_to_log(&format!("[CRITICAL] {}", message)); } pub fn log_warning(message: &str) { println!("\x1b[33m * \x1b[0m {}", message); + write_to_log(&format!("[WARNING] {}", message)); } pub fn log_success(message: &str) { println!("\x1b[32m * \x1b[0m {}", message); + write_to_log(&format!("[OK] {}", message)); } diff --git a/init/src/main.rs b/init/src/main.rs index 6821bd6..a3492d1 100644 --- a/init/src/main.rs +++ b/init/src/main.rs @@ -10,26 +10,31 @@ mod signals; use crate::host::locale; use crate::host::set::set_hostname; use crate::kmods::load::load_modules; -use crate::log::{log_critical_error, log_success, log_warning}; +use crate::log::{init_logging, log_critical_error, log_success, log_warning}; use crate::mounts::fstab::FstabEntry; use crate::mounts::rescue; use crate::pid_one::check_pid; use crate::processes::udev::spawn_udev; use crate::services::units::{Runlevel, services_mainloop}; use crate::signals::sigchld; +use crate::signals::sigterm::{self, RELOAD_REQUESTED, DEBUG_DUMP_REQUESTED}; // RULE: I will not use .expect() and .unwrap() in this project. This causes panic, // which will affect stability. use std::sync::Mutex; use std::thread; +use std::time::Duration; /// Variable which show current runlevel; pub static RUNLEVEL_STATE: Mutex<Runlevel> = Mutex::new(Runlevel::Undefined); // TODO: Add proper RUNLEVEL_STATE switching fn main() -> Result<(), Box<dyn std::error::Error>> { - println!("Initializing your system."); + if let Err(e) = init_logging() { + eprintln!("Failed to initialize logging: {}", e); + } + if let Err(e) = check_pid() { log_critical_error(&format!( "Runned not as first process. init/src/pid_one.rs:8:8 - {}", @@ -38,6 +43,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { return Err(e); } + sigchld::setup_sigchld_handler()?; + sigterm::setup_signal_handlers()?; + match FstabEntry::parse_fstab("/etc/fstab") { Ok(entries) => { log_success("Sucessfully parsed /etc/fstab."); @@ -77,9 +85,30 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { Err(e) => log_warning(&format!("Failed to set localization: {}", e)), } - let _ = sigchld::setup_sigchld_handler(); - thread::spawn(services_mainloop); - Ok(()) + log_success("System initialization complete. Entering main loop."); + + loop { + if sigterm::SHUTDOWN_REQUESTED.load(std::sync::atomic::Ordering::SeqCst) { + log_warning("Shutdown signal received."); + let _ = sigterm::graceful_shutdown(); + break Ok(()); + } + + if RELOAD_REQUESTED.swap(false, std::sync::atomic::Ordering::SeqCst) { + log_warning("SIGUSR1 received - config reload requested (not implemented yet)."); + // TODO: Configs reload + } + + // SIGUSR2 (debug dump) + if DEBUG_DUMP_REQUESTED.swap(false, std::sync::atomic::Ordering::SeqCst) { + log_warning("SIGUSR2 received - debug dump requested (not implemented yet)."); + // TODO: debug dump + } + + // Sleep to not disturb CPU + // TODO: io_uring / epolls + thread::sleep(Duration::from_secs(1)); + } } diff --git a/init/src/signals/mod.rs b/init/src/signals/mod.rs index 0e86476..5e10ee8 100644 --- a/init/src/signals/mod.rs +++ b/init/src/signals/mod.rs @@ -1 +1,2 @@ pub mod sigchld; +pub mod sigterm; 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(()) +} |
