From 3d1d5c8857f852903434488036ccf5036893f881 Mon Sep 17 00:00:00 2001 From: namilsk Date: Fri, 2 Jan 2026 18:20:45 +0300 Subject: Refactored code and implemented it in main() --- init/src/main.rs | 26 ++++++++ init/src/mounts/fstab.rs | 164 +++++++++++++++++++++++++++++++++------------- init/src/rescue/initrd.rs | 0 3 files changed, 145 insertions(+), 45 deletions(-) create mode 100644 init/src/rescue/initrd.rs (limited to 'init') diff --git a/init/src/main.rs b/init/src/main.rs index 1138ccf..e944424 100644 --- a/init/src/main.rs +++ b/init/src/main.rs @@ -1,10 +1,36 @@ mod mounts; mod pid_one; +use crate::mounts::fstab::FstabEntry; +use crate::mounts::rescue; use crate::pid_one::check_pid; +// RULE: I will not use .expect() and .unwrap() in this project. This causes panic, +// which will affect stability. + fn main() -> Result<(), Box> { println!("Initializing your system."); check_pid().expect("\x1b[31m * \x1b[0m Runned not as first process. init/src/pid_one.rs:8:8"); + + match FstabEntry::parse_fstab("/etc/fstab") { + Ok(entries) => { + println!("\x1b[32m * \x1b[0m Sucessfully parsed /etc/fstab."); + for entry in &entries { + let _ = entry.mount(); + } + }, + Err(error) => { + println!("\x1b[33m * \x1b[0m Looks like fstab broken. Mounting all without reading /etc/fstab."); + println!("\x1b[33m * \x1b[0m Error:\n {}", error); + let _ = rescue::mount_system(); + + // Minimal mounts without fstab, because /etc/fstab needs fixes :) + // Btw it should be used if fstab broken or has syntax-errors + // TODO: If fstab contains syntax errors, mount everything else that does not contain them through it anyway. + } + } + + + Ok(()) } diff --git a/init/src/mounts/fstab.rs b/init/src/mounts/fstab.rs index 0765cfd..919607c 100644 --- a/init/src/mounts/fstab.rs +++ b/init/src/mounts/fstab.rs @@ -1,5 +1,6 @@ use libc::{self}; use std::ffi::CString; +use std::{fs, fmt}; #[derive(Debug)] pub struct FstabEntry { @@ -11,62 +12,128 @@ pub struct FstabEntry { pub pass: u32, } -fn parse_mount_options( - options: &str, -) -> Result<(libc::c_ulong, Option), Box> { - let mut flags = 0; - let mut data_parts = Vec::new(); - - for opt in options.split(',') { - match opt { - "defaults" => { /* handled by not setting any restrictive flags */ } - "ro" => flags |= libc::MS_RDONLY, - "rw" => flags &= !libc::MS_RDONLY, - "noexec" => flags |= libc::MS_NOEXEC, - "nosuid" => flags |= libc::MS_NOSUID, - "nodev" => flags |= libc::MS_NODEV, - "sync" => flags |= libc::MS_SYNCHRONOUS, - "dirsync" => flags |= libc::MS_DIRSYNC, - "bind" => flags |= libc::MS_BIND, - "rbind" => flags |= libc::MS_BIND | libc::MS_REC, - "remount" => flags |= libc::MS_REMOUNT, - _ => { - if !opt.is_empty() { - data_parts.push(opt); +impl fmt::Display for FstabEntry { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{} {} {} {} {} {}", + self.source, self.mountpoint, self.fstype, self.options, self.dump, self.pass + ) + } +} + +impl FstabEntry { + fn parse_line(line: &str) -> Result> { + let line = line.trim(); + + if line.is_empty() || line.starts_with('#') { + return Err("Empty line or comment".into()); + } + + let parts: Vec<&str> = line.split_whitespace().collect(); + + if parts.len() != 6 { + return Err(format!("Invalid number of fields in fstab entry: {}", line).into()); + } + + let source = parts[0].to_string(); + let mountpoint = parts[1].to_string(); + let fstype = parts[2].to_string(); + let options = parts[3].to_string(); + + let dump = parts[4].parse::().map_err(|e| { + format!("Failed to parse dump field '{}': {}", parts[4], e) + })?; + + let pass = parts[5].parse::().map_err(|e| { + format!("Failed to parse pass field '{}': {}", parts[5], e) + })?; + + Ok(FstabEntry { + source, + mountpoint, + fstype, + options, + dump, + pass, + }) + } + + pub fn parse_fstab(path: &str) -> Result, Box> { + let content = fs::read_to_string(path)?; + + let mut entries = Vec::new(); + for line in content.lines() { + match Self::parse_line(line) { + Ok(entry) => entries.push(entry), + Err(_) => { + println!("\x1b[32m * \x1b[0m Warning: Skipping invalid fstab line: {}", line); + continue; } } } + + Ok(entries) } - let data = if data_parts.is_empty() { - None - } else { - Some(data_parts.join(",")) - }; + pub fn parse_mount_options( + &self, + ) -> Result<(libc::c_ulong, Option), Box> { + let mut flags = 0; + let mut data_parts = Vec::new(); + let options = &self.options; - Ok((flags, data)) -} + for opt in options.split(',') { + match opt { + "defaults" => { /* handled by not setting any restrictive flags */ } + "ro" => flags |= libc::MS_RDONLY, + "rw" => flags &= !libc::MS_RDONLY, + "noexec" => flags |= libc::MS_NOEXEC, + "nosuid" => flags |= libc::MS_NOSUID, + "nodev" => flags |= libc::MS_NODEV, + "sync" => flags |= libc::MS_SYNCHRONOUS, + "dirsync" => flags |= libc::MS_DIRSYNC, + "bind" => flags |= libc::MS_BIND, + "rbind" => flags |= libc::MS_BIND | libc::MS_REC, + "remount" => flags |= libc::MS_REMOUNT, + _ => { + if !opt.is_empty() { + data_parts.push(opt); + } + } + } + } + + let data = if data_parts.is_empty() { + None + } else { + Some(data_parts.join(",")) + }; + + Ok((flags, data)) + } -pub fn mount_from_fstab(entries: &[FstabEntry]) -> Result<(), Box> { - for entry in entries { - if entry.fstype == "swap" { - println!("Skipping swap: {}", entry.source); - continue; + pub fn mount(&self) -> Result<(), Box> { + println!("\x1b[32m * \x1b[0m Started mounting {} from {}", self.mountpoint, self.source); + + if self.fstype == "swap" { + println!("\x1b[30m * \x1b[0m Skipping swap: {}", self.source); + return Ok(()); } - if entry.mountpoint == "none" { - continue; + if self.mountpoint == "none" { + return Ok(()); } - if entry.options.contains("noauto") { - continue; + if self.options.contains("noauto") { + return Ok(()); } - let (flags, data) = parse_mount_options(&entry.options)?; + let (flags, data) = self.parse_mount_options()?; - let source_c = CString::new(&*entry.source)?; - let target_c = CString::new(&*entry.mountpoint)?; - let fstype_c = CString::new(&*entry.fstype)?; + let source_c = CString::new(&*self.source)?; + let target_c = CString::new(&*self.mountpoint)?; + let fstype_c = CString::new(&*self.fstype)?; let data_c = data.map(|s| CString::new(s).expect("\x1b[31m * \x1b[0m Something went wrong while mounting partitions. You are going to rescue mode...")); let data_ptr = data_c @@ -87,12 +154,19 @@ pub fn mount_from_fstab(entries: &[FstabEntry]) -> Result<(), Box Result<(), Box> { + for entry in entries { + entry.mount()?; } + Ok(()) } - Ok(()) } \ No newline at end of file diff --git a/init/src/rescue/initrd.rs b/init/src/rescue/initrd.rs new file mode 100644 index 0000000..e69de29 -- cgit v1.2.3