diff options
Diffstat (limited to 'init')
| -rw-r--r-- | init/Cargo.toml | 3 | ||||
| -rw-r--r-- | init/src/host/locale.rs | 21 | ||||
| -rw-r--r-- | init/src/host/set.rs | 2 | ||||
| -rw-r--r-- | init/src/host/timezone.rs | 2 | ||||
| -rw-r--r-- | init/src/main.rs | 15 | ||||
| -rw-r--r-- | init/src/mounts/fstab.rs | 5 | ||||
| -rw-r--r-- | init/src/mounts/rescue.rs | 22 | ||||
| -rw-r--r-- | init/src/services/unit_parser.rs | 159 | ||||
| -rw-r--r-- | init/src/signals/sigchld.rs | 22 |
9 files changed, 213 insertions, 38 deletions
diff --git a/init/Cargo.toml b/init/Cargo.toml index d68c550..2d5a303 100644 --- a/init/Cargo.toml +++ b/init/Cargo.toml @@ -7,4 +7,5 @@ description = "Lightweight and stable init system for Anthrill distro based on u [dependencies] libc = "0.2.178" liblmod = "0.2.0" -toml = { version = "0.9.11", features = ["display", "std"], default-features = false } +serde = { version = "1.0.228", default-features = false, features = ["derive"] } +toml = { version = "0.9.11", default-features = false, features = ["parse", "serde"] } diff --git a/init/src/host/locale.rs b/init/src/host/locale.rs index 6dc43b2..d955297 100644 --- a/init/src/host/locale.rs +++ b/init/src/host/locale.rs @@ -1,9 +1,22 @@ +// NOTE: Ts file contains setting localisation by environment variables +// Main logic implemented but how i think it can contain with broken logic or checks +// At least if check failed it set C.UTF8 (fallback locale) +// And why is std::env::set_var unsafe???? + use crate::host::timezone::set_timezone; use crate::log::{log_success, log_warning}; use std::fs; use std::io::Write; use std::process::Command; +/// Main function which setting system locale. +/// +/// Logic && Checks +/// 1. Reading /etc/default/locale to find needed language. +/// If it broken/has syntax errors skipping this step +/// 2. Checking for locale avalible (also switching `-` and `_`), +/// if not uses fallback locale. +/// pub fn set_locale(locale: Option<String>) -> Result<(), Box<dyn std::error::Error>> { let loc = match locale { Some(l) => l, @@ -23,10 +36,10 @@ pub fn set_locale(locale: Option<String>) -> Result<(), Box<dyn std::error::Erro } } - if let Ok(lang_env) = std::env::var("LANG") - && !lang_env.is_empty() { - return set_system_locale(&lang_env); - + if let Ok(lang_env) = std::env::var("LANG") + && !lang_env.is_empty() + { + return set_system_locale(&lang_env); } if locale_exists("C.UTF-8") { "C.UTF-8".to_string() diff --git a/init/src/host/set.rs b/init/src/host/set.rs index 9550b29..b161930 100644 --- a/init/src/host/set.rs +++ b/init/src/host/set.rs @@ -1,3 +1,5 @@ +// This file named `set.rs` because possibly here will be other functions, not only hn + use crate::log::log_warning; use libc::{c_char, sethostname, size_t}; use std::{ffi::CString, fs, io}; diff --git a/init/src/host/timezone.rs b/init/src/host/timezone.rs index 2da9e85..1062a8b 100644 --- a/init/src/host/timezone.rs +++ b/init/src/host/timezone.rs @@ -1,6 +1,6 @@ use crate::log::*; use std::fs; - + pub fn set_timezone(timezone: Option<String>) -> Result<(), Box<dyn std::error::Error>> { let tz = match timezone { Some(tz) => tz, diff --git a/init/src/main.rs b/init/src/main.rs index a727b42..40e47a4 100644 --- a/init/src/main.rs +++ b/init/src/main.rs @@ -4,7 +4,8 @@ mod log; mod mounts; mod pid_one; mod processes; -mod signals; +mod signals; +mod services; use crate::host::locale; use crate::host::set::set_hostname; @@ -14,11 +15,17 @@ use crate::mounts::fstab::FstabEntry; use crate::mounts::rescue; use crate::pid_one::check_pid; use crate::processes::udev::spawn_udev; +use crate::services::unit_parser::Runlevel; use crate::signals::sigchld; // RULE: I will not use .expect() and .unwrap() in this project. This causes panic, // which will affect stability. +use std::sync::Mutex; + +/// Variable which show current runlevel; +pub static mut RUNLEVEL_STATE: Mutex<Runlevel> = Mutex::new(Runlevel::Undefined); + fn main() -> Result<(), Box<dyn std::error::Error>> { println!("Initializing your system."); if let Err(e) = check_pid() { @@ -62,13 +69,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { Err(e) => log_critical_error(&format!("Something went wrong while spawning udev: {}", e)), } - // TODO: Locale & tz parsing + // TODO: Locale & tz parsing match locale::set_system_localization(None, None) { Ok(_) => log_success("Localization (timezone and locale) set successfully."), Err(e) => log_warning(&format!("Failed to set localization: {}", e)), } - let _ = sigchld::setup_sigchld_handler(); - + let _ = sigchld::setup_sigchld_handler(); + Ok(()) } diff --git a/init/src/mounts/fstab.rs b/init/src/mounts/fstab.rs index 4d9b474..7d71520 100644 --- a/init/src/mounts/fstab.rs +++ b/init/src/mounts/fstab.rs @@ -135,7 +135,10 @@ impl FstabEntry { pub fn mount(&self) -> Result<(), Box<dyn std::error::Error>> { if let Err(e) = Self::check_mount_point_permissions(&self.mountpoint) { - log_warning(&format!("Permission check failed for {}: {}", self.mountpoint, e)); + log_warning(&format!( + "Permission check failed for {}: {}", + self.mountpoint, e + )); } log_success(&format!( diff --git a/init/src/mounts/rescue.rs b/init/src/mounts/rescue.rs index 2238297..385f851 100644 --- a/init/src/mounts/rescue.rs +++ b/init/src/mounts/rescue.rs @@ -13,10 +13,10 @@ fn check_mount_point_permissions(path: &str) -> Result<(), Box<dyn std::error::E if !meta.is_dir() { return Err(format!("Mount point {} is not a directory", path).into()); } - + // TODO // let mode = meta.mode(); - + let uid = meta.uid(); if uid != 0 { log_warning(&format!("Warning: Mount point {} not owned by root", path)); @@ -45,15 +45,17 @@ pub fn mount_system() -> Result<(), Box<dyn std::error::Error>> { // let source_c = source.map(|s| CString::new(s).map_err(|e| )); let source_c = match source { Some(s) => match CString::new(s) { - Ok(c_string) => Some(c_string), + Ok(c_string) => Some(c_string), Err(null_err) => { - log_warning(&format!("Source string contains NULL bytes (\\0), skipping: {}", null_err)); - continue; - } - }, - None => None - }; - + log_warning(&format!( + "Source string contains NULL bytes (\\0), skipping: {}", + null_err + )); + continue; + } + }, + None => None, + }; let source_ptr = source_c.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()); diff --git a/init/src/services/unit_parser.rs b/init/src/services/unit_parser.rs index a9898c1..1e2bcc7 100644 --- a/init/src/services/unit_parser.rs +++ b/init/src/services/unit_parser.rs @@ -1,4 +1,4 @@ -// This module defines unit settings parsing logig +// This module defines unit settings parsing logig // // NOTE: ON UNIT PARSING LOGIC // when parsing a unit in /etc/vigil/units/ we shoul ignore @@ -6,10 +6,161 @@ // without "crashing" logic. // // NOTE: ON GENERAL SERVICE LOGGING -// when vigil starts service, it should send out logs to vigil? -// or logs in such init systems are just taking the stdout+stderr +// when vigil starts service, it should send out logs to vigil? +// or logs in such init systems are just taking the stdout+stderr // of service and showing its output? idk 4 now, look into how its supposed to be -use toml::display; +use crate::{log_warning, RUNLEVEL_STATE}; +use serde::Deserialize; +use std::fs::{read_dir, read_to_string}; +/* + [info] + name = "name" + description = "description" + version = "version" + [config] + exec = "path to exec" + runlevel = + restart=always|never + +*/ + +#[derive(Deserialize)] +enum Restart { + #[serde(alias = "always")] + Always, + #[serde(alias = "never")] + Never, +} + +#[derive(Deserialize, PartialEq, Eq)] +pub enum Runlevel { + /// The system is shutting down, runlevel int: 0 + Shutdown, + /// One-user system debug-mode, runlevel int: 1 + OneUser, + /// Multi-user CLI (TTY) with no network, runlevel int: 2 + MultiNoNetwork, + /// Multi-user CLI with network, runlevel int: 3 + MultiNetwork, + /// Multi-user mode with GUI, runlevel int: 5 + MultiUserGUINetwork, + /// Runlevel is not critical for running the service, runlevel int: 4 + Undefined, + /// System going too reboot, runlevel int: 6 + Reboot, +} + +#[allow(dead_code)] +#[derive(Deserialize)] +pub struct ServiceInfo { + /// Service name + name: String, + /// Service description + description: String, + /// Service version + version: String, +} + +#[allow(dead_code)] +#[derive(Deserialize)] +pub struct ServiceConfig { + /// Execution command, like ExecStart in sysd + exec: String, + /// Runlevel, like after=*.target + runlevel: Runlevel, + /// Restart service: Always|Never + restart: Restart, +} + +/// Main Unit-file struct +#[allow(dead_code)] +#[derive(Deserialize)] +pub struct Unit { + info: ServiceInfo, + config: ServiceConfig, +} + +#[allow(dead_code)] +impl Restart { + pub fn as_str(&self) -> &'static str { + match self { + Restart::Always => "always", + Restart::Never => "never", + } + } +} + +/// Function which starting services declared in `/etc/vigil/units/` +/// Based on the global runlevel variable, should be runned as second thread +pub fn execute_services() -> Result<(), Box<dyn std::error::Error>> { + let unit_list = parse_all_units()?; + + loop { + match *RUNLEVEL_STATE.try_lock()? { + Runlevel::Undefined => { + for unit in &unit_list { + if unit.config.runlevel == Runlevel::Undefined { + std::process::Command::new(unit.config.exec.clone()); + } else { + continue; + } + } + } + Runlevel::Reboot => { + todo!(); + } + + Runlevel::Shutdown => { + todo!(); + } + + Runlevel::OneUser => { + todo!(); + } + + Runlevel::MultiNoNetwork => { + todo!(); + } + + Runlevel::MultiNetwork => { + todo!(); + } + + Runlevel::MultiUserGUINetwork => { + todo!(); + } + } + } +} + +#[allow(dead_code)] +fn parse_all_units() -> Result<Vec<Unit>, Box<dyn std::error::Error>> { + let mut units: Vec<Unit> = Vec::new(); + + for unit in read_dir("/etc/vigil/units")? { + let unit_path = unit?.path(); + let unit_str: String = match read_to_string(unit_path) { + Ok(content) => content, + Err(e) => { + log_warning(&format!("Error while reading unit: {}", e)); + continue; + } + }; + + let deserialized: Result<Unit, _> = toml::from_str(&unit_str); + match deserialized { + Ok(unit) => { + units.push(unit); + } + Err(e) => { + log_warning(&format!("Error while parsing unit: {}", e)); + continue; + } + }; + } + + Ok(units) +} diff --git a/init/src/signals/sigchld.rs b/init/src/signals/sigchld.rs index a02b82f..79a40c9 100644 --- a/init/src/signals/sigchld.rs +++ b/init/src/signals/sigchld.rs @@ -1,14 +1,12 @@ -use libc::{c_int, sigaction, siginfo_t, sigset_t, waitpid, SA_RESTART, SA_SIGINFO, SIGCHLD, WNOHANG}; +use libc::{ + SA_RESTART, SA_SIGINFO, SIGCHLD, WNOHANG, c_int, sigaction, siginfo_t, sigset_t, waitpid, +}; use std::os::raw::c_void; -// extern "C" because: +// extern "C" because: // https://doc.rust-lang.org/reference/items/external-blocks.html?spm=a2ty_o01.29997173.0.0.63e251718NCvPc#abi // Doc comments needed... -extern "C" fn sigchld_handler( - _signal: c_int, - _info: *mut siginfo_t, - _context: *mut c_void, -) { +extern "C" fn sigchld_handler(_signal: c_int, _info: *mut siginfo_t, _context: *mut c_void) { let saved_errno = unsafe { *libc::__errno_location() }; loop { @@ -16,16 +14,14 @@ extern "C" fn sigchld_handler( let pid = unsafe { waitpid(-1, &mut status as *mut c_int, WNOHANG) }; match pid { - 0 => break, + 0 => break, -1 => { let errno = unsafe { *libc::__errno_location() }; if errno == libc::ECHILD { break; } } - _ => { - /* If it doesnt work, ill add the logging here */ - } + _ => { /* If it doesnt work, ill add the logging here */ } } } @@ -35,10 +31,10 @@ extern "C" fn sigchld_handler( pub fn setup_sigchld_handler() -> Result<(), Box<dyn std::error::Error>> { unsafe { let mut sigact: sigaction = std::mem::zeroed(); - + sigact.sa_sigaction = sigchld_handler as usize; sigact.sa_flags = SA_RESTART | SA_SIGINFO; - + libc::sigemptyset(&mut sigact.sa_mask as *mut sigset_t); libc::sigaddset(&mut sigact.sa_mask as *mut sigset_t, SIGCHLD); |
