summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--init/Cargo.toml2
-rw-r--r--init/src/host/locale.rs133
-rw-r--r--init/src/host/mod.rs4
-rw-r--r--init/src/host/set.rs53
-rw-r--r--init/src/host/sethn.rs37
-rw-r--r--init/src/host/timezone.rs67
-rw-r--r--init/src/kmods/load.rs24
-rw-r--r--init/src/kmods/mod.rs1
-rw-r--r--init/src/log.rs1
-rw-r--r--init/src/main.rs63
-rw-r--r--init/src/mounts/fstab.rs17
-rw-r--r--init/src/mounts/rescue.rs3
-rw-r--r--init/src/processes/mod.rs1
-rw-r--r--init/src/processes/udev.rs29
14 files changed, 351 insertions, 84 deletions
diff --git a/init/Cargo.toml b/init/Cargo.toml
index a63ffb7..9ff5782 100644
--- a/init/Cargo.toml
+++ b/init/Cargo.toml
@@ -5,5 +5,5 @@ edition = "2024"
description = "Lightweight and stable init system for Anthrill distro based on unix-phylosophy."
[dependencies]
-errno = "0.3.14"
libc = "0.2.178"
+liblmod = "0.2.0"
diff --git a/init/src/host/locale.rs b/init/src/host/locale.rs
new file mode 100644
index 0000000..6dc43b2
--- /dev/null
+++ b/init/src/host/locale.rs
@@ -0,0 +1,133 @@
+use crate::host::timezone::set_timezone;
+use crate::log::{log_success, log_warning};
+use std::fs;
+use std::io::Write;
+use std::process::Command;
+
+pub fn set_locale(locale: Option<String>) -> Result<(), Box<dyn std::error::Error>> {
+ let loc = match locale {
+ Some(l) => l,
+ None => {
+ if let Ok(content) = fs::read_to_string("/etc/default/locale") {
+ for line in content.lines() {
+ if line.starts_with("LANG=") {
+ let parts: Vec<&str> = line.split('=').collect();
+ if parts.len() >= 2 {
+ let lang_val = parts[1];
+ let clean_lang = lang_val.trim_matches('"').trim_matches('\'');
+ if !clean_lang.is_empty() {
+ return set_system_locale(clean_lang);
+ }
+ }
+ }
+ }
+ }
+
+ 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()
+ } else if locale_exists("en_US.UTF-8") {
+ "en_US.UTF-8".to_string()
+ } else {
+ "C".to_string()
+ }
+ }
+ };
+
+ set_system_locale(&loc)
+}
+fn set_system_locale(locale: &str) -> Result<(), Box<dyn std::error::Error>> {
+ if !locale_exists(locale) {
+ log_warning(&format!(
+ "Locale '{}' not found in system, trying alternatives",
+ locale
+ ));
+
+ let variants = vec![
+ format!("{}.UTF-8", locale),
+ locale.replace('_', "-"), // Sometimes locales are in form en-US
+ format!("{}.UTF-8", locale.replace('_', "-")),
+ ];
+
+ for variant in variants {
+ if locale_exists(&variant) {
+ log_success(&format!("Using alternative locale: {}", variant));
+ return set_system_locale_impl(&variant);
+ }
+ }
+
+ log_warning("No matching locale found, using C.UTF-8 as fallback");
+ return set_system_locale_impl("C.UTF-8");
+ }
+
+ set_system_locale_impl(locale)
+}
+
+fn set_system_locale_impl(locale: &str) -> Result<(), Box<dyn std::error::Error>> {
+ unsafe {
+ std::env::set_var("LANG", locale);
+ std::env::set_var("LC_ALL", locale);
+
+ std::env::set_var("LC_CTYPE", locale);
+ std::env::set_var("LC_NUMERIC", locale);
+ std::env::set_var("LC_TIME", locale);
+ std::env::set_var("LC_COLLATE", locale);
+ std::env::set_var("LC_MONETARY", locale);
+ std::env::set_var("LC_MESSAGES", locale);
+ std::env::set_var("LC_PAPER", locale);
+ std::env::set_var("LC_NAME", locale);
+ std::env::set_var("LC_ADDRESS", locale);
+ std::env::set_var("LC_TELEPHONE", locale);
+ std::env::set_var("LC_MEASUREMENT", locale);
+ std::env::set_var("LC_IDENTIFICATION", locale);
+ }
+
+ if let Ok(mut file) = std::fs::OpenOptions::new()
+ .create(true)
+ .write(true)
+ .truncate(true)
+ .open("/etc/default/locale")
+ {
+ writeln!(file, "# Generated by Vigil init system")?;
+ writeln!(file, "LANG=\"{}\"", locale)?;
+ writeln!(file, "LC_ALL=\"{}\"", locale)?;
+ file.flush()?;
+ } else {
+ log_warning("Could not write to /etc/default/locale, locale settings may not persist");
+ }
+
+ log_success(&format!("Locale set to {}", locale));
+ Ok(())
+}
+
+fn locale_exists(locale: &str) -> bool {
+ if let Ok(output) = Command::new("locale").arg("-a").output() {
+ let output_str = String::from_utf8_lossy(&output.stdout);
+ output_str.lines().any(|line| line.trim() == locale)
+ } else {
+ let locale_archive_path = "/usr/lib/locale/locale-archive".to_string();
+ let locale_dir_path = "/usr/lib/locale/".to_string();
+
+ std::path::Path::new(&locale_archive_path).exists()
+ || std::path::Path::new(&locale_dir_path).exists()
+ }
+}
+
+pub fn set_system_localization(
+ timezone: Option<String>,
+ locale: Option<String>,
+) -> Result<(), Box<dyn std::error::Error>> {
+ if let Err(e) = set_timezone(timezone) {
+ log_warning(&format!("Failed to set timezone: {}", e));
+ }
+
+ if let Err(e) = set_locale(locale) {
+ log_warning(&format!("Failed to set locale: {}", e));
+ }
+
+ Ok(())
+}
diff --git a/init/src/host/mod.rs b/init/src/host/mod.rs
index 4a3de53..604c9a7 100644
--- a/init/src/host/mod.rs
+++ b/init/src/host/mod.rs
@@ -1 +1,3 @@
-pub mod sethn; \ No newline at end of file
+pub mod locale;
+pub mod set;
+pub mod timezone;
diff --git a/init/src/host/set.rs b/init/src/host/set.rs
new file mode 100644
index 0000000..9550b29
--- /dev/null
+++ b/init/src/host/set.rs
@@ -0,0 +1,53 @@
+use crate::log::log_warning;
+use libc::{c_char, sethostname, size_t};
+use std::{ffi::CString, fs, io};
+
+pub fn set_hostname() -> Result<(), Box<dyn std::error::Error>> {
+ let content = fs::read_to_string("/etc/hostname")
+ .map(|s| s.trim().to_string())
+ .unwrap_or_else(|_| "localhost".to_string());
+
+ if let Err(e) = perform_set_hostname(&content) {
+ match perform_set_hostname("localhost") {
+ Ok(_) => Err(format!(
+ "Failed to set hostname: \"{}\": {}. Fell back to localhost successfully.",
+ content, e
+ )
+ .into()),
+
+ Err(fallback_error) => {
+ log_warning(&format!(
+ "Failed to set hostname to '{}': {}. Also failed to set localhost: {}.",
+ content, e, fallback_error
+ ));
+ Err(format!(
+ "Failed to set hostname '{}' and failed to fall back to localhost: {}.",
+ content, e
+ )
+ .into())
+ }
+ }
+ } else {
+ Ok(())
+ }
+}
+
+fn perform_set_hostname(name: &str) -> io::Result<()> {
+ if name.len() > 64 {
+ return Err(io::Error::new(
+ io::ErrorKind::InvalidInput,
+ "Hostname too long",
+ ));
+ }
+
+ let c_str = CString::new(name)
+ .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "Hostname contains null byte"))?;
+
+ let res = unsafe { sethostname(c_str.as_ptr() as *const c_char, name.len() as size_t) };
+
+ if res != 0 {
+ return Err(io::Error::last_os_error());
+ }
+
+ Ok(())
+}
diff --git a/init/src/host/sethn.rs b/init/src/host/sethn.rs
deleted file mode 100644
index 1857297..0000000
--- a/init/src/host/sethn.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-use std::{ffi::CString, fs, io};
-use libc::{sethostname, c_char, size_t};
-use crate::log::{log_warning};
-
-pub fn try_set_hostname() {
- let content = fs::read_to_string("/etc/hostname")
- .map(|s| s.trim().to_string())
- .unwrap_or_else(|_| "localhost".to_string());
-
- if let Err(e) = perform_set_hostname(&content) {
- log_warning(&format!("Failed to set hostname to '{}': {}. Falling back to localhost.", content, e));
- let _ = perform_set_hostname("localhost");
- }
-}
-
-fn perform_set_hostname(name: &str) -> io::Result<()> {
- if name.len() > 64 {
- return Err(io::Error::new(io::ErrorKind::InvalidInput, "Hostname too long"));
- }
-
- let c_str = CString::new(name).map_err(|_| {
- io::Error::new(io::ErrorKind::InvalidInput, "Hostname contains null byte")
- })?;
-
- let res = unsafe {
- sethostname(
- c_str.as_ptr() as *const c_char,
- name.len() as size_t,
- )
- };
-
- if res != 0 {
- return Err(io::Error::last_os_error());
- }
-
- Ok(())
-} \ No newline at end of file
diff --git a/init/src/host/timezone.rs b/init/src/host/timezone.rs
new file mode 100644
index 0000000..2da9e85
--- /dev/null
+++ b/init/src/host/timezone.rs
@@ -0,0 +1,67 @@
+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,
+ None => {
+ if let Ok(content) = fs::read_to_string("/etc/timezone") {
+ content.trim().to_string()
+ } else if let Ok(link_info) = fs::read_link("/etc/localtime") {
+ let path_str = link_info.to_string_lossy();
+ if path_str.starts_with("/usr/share/zoneinfo/") {
+ let tz_part = path_str.strip_prefix("/usr/share/zoneinfo/").unwrap_or("");
+ tz_part.to_string()
+ } else {
+ "UTC".to_string()
+ }
+ } else {
+ "UTC".to_string()
+ }
+ }
+ };
+
+ let tz_file_path = format!("/usr/share/zoneinfo/{}", tz);
+
+ if !std::path::Path::new(&tz_file_path).exists() {
+ log_warning(&format!(
+ "Timezone '{}' not found in zoneinfo, using UTC",
+ tz
+ ));
+ let result = set_system_timezone_to_utc();
+ if let Err(e) = result {
+ log_critical_error(&format!("Failed to set timezone to UTC: {}", e));
+ return Err(e);
+ }
+ return Ok(());
+ }
+
+ if std::path::Path::new("/etc/localtime").exists() {
+ std::fs::remove_file("/etc/localtime")?;
+ }
+
+ std::os::unix::fs::symlink(&tz_file_path, "/etc/localtime")?;
+
+ log_success(&format!("Timezone set to {}", tz));
+
+ unsafe {
+ std::env::set_var("TZ", &tz);
+ }
+
+ Ok(())
+}
+
+fn set_system_timezone_to_utc() -> Result<(), Box<dyn std::error::Error>> {
+ let utc_tz_path = "/usr/share/zoneinfo/Etc/UTC";
+ if std::path::Path::new("/etc/localtime").exists() {
+ std::fs::remove_file("/etc/localtime")?;
+ }
+
+ std::os::unix::fs::symlink(utc_tz_path, "/etc/localtime")?;
+ log_success("Timezone set to UTC");
+ unsafe {
+ std::env::set_var("TZ", "UTC");
+ }
+
+ Ok(())
+}
diff --git a/init/src/kmods/load.rs b/init/src/kmods/load.rs
new file mode 100644
index 0000000..374ce36
--- /dev/null
+++ b/init/src/kmods/load.rs
@@ -0,0 +1,24 @@
+use liblmod::Selection;
+use liblmod::modprobe;
+use std::fs;
+
+fn parse_modules() -> Result<Vec<String>, Box<dyn std::error::Error>> {
+ let raw_mods = fs::read_to_string("/etc/modules")?
+ .split(',')
+ .map(|s| s.trim().to_string())
+ .collect();
+
+ Ok(raw_mods)
+}
+
+pub fn load_modules() -> Result<(), Box<dyn std::error::Error>> {
+ let modules = parse_modules()?;
+
+ for i in 0..modules.len() {
+ modprobe(modules[i].to_string(), "".to_string(), Selection::Current)?;
+ }
+
+ Ok(())
+}
+
+// TODO: Think, is `rmmod` needed?
diff --git a/init/src/kmods/mod.rs b/init/src/kmods/mod.rs
new file mode 100644
index 0000000..f5f538c
--- /dev/null
+++ b/init/src/kmods/mod.rs
@@ -0,0 +1 @@
+pub mod load;
diff --git a/init/src/log.rs b/init/src/log.rs
index 23f644f..4c89dd1 100644
--- a/init/src/log.rs
+++ b/init/src/log.rs
@@ -9,4 +9,3 @@ pub fn log_warning(message: &str) {
pub fn log_success(message: &str) {
println!("\x1b[32m * \x1b[0m {}", message);
}
-
diff --git a/init/src/main.rs b/init/src/main.rs
index feea052..7a77e31 100644
--- a/init/src/main.rs
+++ b/init/src/main.rs
@@ -1,51 +1,29 @@
+mod host;
+mod kmods;
mod log;
mod mounts;
mod pid_one;
-mod host;
+mod processes;
-use crate::log::{log_critical_error, log_warning, log_success};
+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::mounts::fstab::FstabEntry;
use crate::mounts::rescue;
use crate::pid_one::check_pid;
-use crate::host::sethn::try_set_hostname;
-
-use std::process::Command;
+use crate::processes::udev::spawn_udev;
// RULE: I will not use .expect() and .unwrap() in this project. This causes panic,
// which will affect stability.
-fn spawn_udev() -> Result<(), Box<dyn std::error::Error>> {
- log_success("Spawning udev daemon.");
-
- let udevd_paths = [
- "/sbin/udevd",
- "/usr/sbin/udevd",
- "/bin/udevd",
- "/usr/bin/udevd",
- ];
- let udevd_path = udevd_paths
- .iter()
- .find(|path| std::path::Path::new(path).exists())
- .ok_or("udevd not found in standard locations")?;
-
- let child = Command::new(udevd_path)
- .arg("--daemon")
- .spawn()
- .map_err(|e| format!("Failed to spawn udevd: {}", e))?;
-
- log_success(&format!("udevd started with PID: {}", child.id()));
- Command::new(udevd_path)
- .arg("--trigger")
- .output()
- .map_err(|e| format!("Failed to trigger udev: {}", e))?;
-
- Ok(())
-}
-
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Initializing your system.");
if let Err(e) = check_pid() {
- log_critical_error(&format!("Runned not as first process. init/src/pid_one.rs:8:8 - {}", e));
+ log_critical_error(&format!(
+ "Runned not as first process. init/src/pid_one.rs:8:8 - {}",
+ e
+ ));
return Err(e);
}
@@ -67,11 +45,24 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}
}
- let _ = try_set_hostname();
+ match set_hostname() {
+ Ok(_) => log_success("Hostname setted successfully."),
+ Err(e) => log_warning(&format!("Failed to set hostname: {}", e)),
+ }
+
+ match load_modules() {
+ Ok(_) => log_success("Kernel modules loaded successfully."),
+ Err(e) => log_warning(&format!("Error while loading kernel modules: {}", e)),
+ }
match spawn_udev() {
Ok(_) => log_success("Successfully started udev daemon."),
- Err(e) => log_critical_error(&format!("Failed to start udev daemon: {}", e)),
+ Err(e) => log_critical_error(&format!("Something went wrong while spawning udev: {}", e)),
+ }
+
+ 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)),
}
Ok(())
diff --git a/init/src/mounts/fstab.rs b/init/src/mounts/fstab.rs
index c0cfd58..b8708e2 100644
--- a/init/src/mounts/fstab.rs
+++ b/init/src/mounts/fstab.rs
@@ -1,7 +1,7 @@
-use crate::log::{log_critical_error, log_warning, log_success};
+use crate::log::{log_critical_error, log_success, log_warning};
+use libc::syscall;
use std::ffi::CString;
use std::{fmt, fs};
-use libc::syscall;
#[derive(Debug)]
pub struct FstabEntry {
@@ -114,15 +114,20 @@ impl FstabEntry {
Ok((flags, data))
}
-
pub fn mount(&self) -> Result<(), Box<dyn std::error::Error>> {
- log_success(&format!("Started mounting {} from {}", self.mountpoint, self.source));
+ log_success(&format!(
+ "Started mounting {} from {}",
+ self.mountpoint, self.source
+ ));
if self.fstype == "swap" {
- log_success(&format!("Filesystem type contains swap, upping it: {}", self.source));
+ log_success(&format!(
+ "Filesystem type contains swap, upping it: {}",
+ self.source
+ ));
unsafe {
- syscall(libc::SYS_swapon, &self.source, 0);
+ syscall(libc::SYS_swapon, &self.source, 0);
}
return Ok(());
diff --git a/init/src/mounts/rescue.rs b/init/src/mounts/rescue.rs
index ad80a84..078984d 100644
--- a/init/src/mounts/rescue.rs
+++ b/init/src/mounts/rescue.rs
@@ -31,11 +31,10 @@ pub fn mount_system() -> Result<(), Box<dyn std::error::Error>> {
);
if ret != 0 {
- let errno = errno::errno().0;
return Err(format!(
"Failed to mount {}: {}",
target,
- std::io::Error::from_raw_os_error(errno)
+ std::io::Error::last_os_error()
)
.into());
}
diff --git a/init/src/processes/mod.rs b/init/src/processes/mod.rs
new file mode 100644
index 0000000..73b363e
--- /dev/null
+++ b/init/src/processes/mod.rs
@@ -0,0 +1 @@
+pub mod udev;
diff --git a/init/src/processes/udev.rs b/init/src/processes/udev.rs
new file mode 100644
index 0000000..7cb6a5d
--- /dev/null
+++ b/init/src/processes/udev.rs
@@ -0,0 +1,29 @@
+use std::process::Command;
+
+// TODO: Rewrite this bad fn
+pub fn spawn_udev() -> Result<(), Box<dyn std::error::Error>> {
+ let udevd_paths = [
+ "/sbin/udevd",
+ "/usr/sbin/udevd",
+ "/bin/udevd",
+ "/usr/bin/udevd",
+ ];
+ let udevd_path = udevd_paths
+ .iter()
+ .find(|path| std::path::Path::new(path).exists())
+ .ok_or_else(|| -> Box<dyn std::error::Error> {
+ "udevd not found in standard locations".into()
+ })?;
+
+ let mut child = Command::new(udevd_path).arg("--daemon").spawn().map_err(
+ |e| -> Box<dyn std::error::Error> { format!("Failed to spawn udevd: {}", e).into() },
+ )?;
+
+ child.wait()?;
+
+ Command::new(udevd_path).arg("--trigger").output().map_err(
+ |e| -> Box<dyn std::error::Error> { format!("Failed to trigger udev: {}", e).into() },
+ )?;
+
+ Ok(())
+}