summaryrefslogtreecommitdiff
path: root/init/src
diff options
context:
space:
mode:
Diffstat (limited to 'init/src')
-rw-r--r--init/src/log.rs35
-rw-r--r--init/src/main.rs39
-rw-r--r--init/src/signals/mod.rs1
-rw-r--r--init/src/signals/sigterm.rs108
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(())
+}