From f388a879ea75bd8b37f89effd52489bca2e991d497f4baf77beec642bba24c82 Mon Sep 17 00:00:00 2001 From: kira Date: Tue, 22 Sep 2026 17:25:02 +0200 Subject: [PATCH] Adding ability to handle non bcachefs as root filesystem --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/main.rs | 63 ++++++++++++++++++++++++++++------------------ src/nyan_system.rs | 52 +++++++++++++++++++++++++++++--------- 4 files changed, 80 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 918717f..ae1eddc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -284,7 +284,7 @@ checksum = "6aa2c4e539b869820a2b82e1aef6ff40aa85e65decdd5185e83fb4b1249cd00f" [[package]] name = "nyanit" -version = "0.2.2" +version = "0.2.3" dependencies = [ "nix", "ratatui", diff --git a/Cargo.toml b/Cargo.toml index 68a80e1..9b74c97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nyanit" -version = "0.2.2" +version = "0.2.3" edition = "2024" [dependencies] diff --git a/src/main.rs b/src/main.rs index fff5918..fe1de84 100644 --- a/src/main.rs +++ b/src/main.rs @@ -106,6 +106,9 @@ enum NyanitState { HandOff, } +/// +/// Generates confirm dialog paragraph +/// fn gen_conf_par<'a>(snap_dt: String) -> Paragraph<'a> { let first_line = Line::from(vec![Span::raw(CONFIRM_TEXT1), Span::raw(snap_dt).bold()]); let confirm_line = Line::from(vec![ @@ -132,7 +135,7 @@ fn gen_conf_par<'a>(snap_dt: String) -> Paragraph<'a> { struct NyanitTUI<'a> { exit: bool, state: NyanitState, - bee_root_dev: String, + bee_root_dev: nyan_system::BlkIdRes, list_state: ListState, /// time counter manly for F2 waiting in mills time_counter: u64, @@ -148,7 +151,10 @@ impl NyanitTUI<'_> { Ok(Self { exit: false, state: NyanitState::Init, - bee_root_dev: String::new(), + bee_root_dev: nyan_system::BlkIdRes { + fs_type: String::new(), + dev_node: String::new(), + }, list_state: ListState::default().with_selected(Some(0)), time_counter: 0, time_counter_sec: 0, @@ -166,24 +172,28 @@ impl NyanitTUI<'_> { // let root_list = nyan_system::list_dir(TMP_ROOT)?; // return Err(ExecCommandError::Other(root_list)); - // list snaps if any - self.snaps_list = nyan_system::list_bzzpss_snaps(TMP_ROOT_SNAPS)?; + if self.bee_root_dev.is_bcachefs() { + // list snaps if any + self.snaps_list = nyan_system::list_bzzpss_snaps(TMP_ROOT_SNAPS)?; - // if any snaps detected check hive DB update_status - if self.snaps_list.len() > 0 { - // if pac_lock accessible and exist - rolling back - if let Ok(Some(snap_date_time)) = nyan_system::check_pac_lock() - && self.snaps_list.contains(&snap_date_time) - { - Ok(NyanitState::ConfirmRollback(snap_date_time)) + // if any snaps detected check hive DB update_status + if self.snaps_list.len() > 0 { + // if pac_lock accessible and exist - rolling back + if let Ok(Some(snap_date_time)) = nyan_system::check_pac_lock() + && self.snaps_list.contains(&snap_date_time) + { + Ok(NyanitState::ConfirmRollback(snap_date_time)) + } + // else user choose what to do + else { + Ok(NyanitState::WaitForF2) + } } - // else user choose what to do + // else tell to finish boot else { - Ok(NyanitState::WaitForF2) + Ok(NyanitState::HandOff) } - } - // else tell to finish boot - else { + } else { Ok(NyanitState::HandOff) } } @@ -194,17 +204,17 @@ impl NyanitTUI<'_> { // get bee-root device name aka /dev/sda1 // trying for max 3 sec - self.bee_root_dev = nyan_system::try_find_partlabel(ROOT_PARTLABEL, 3) .ok_or_else(|| "Timed out trying to find dev by partlabel.".to_string())?; - // works until this point!!!! - // check if device is encrypted - if nyan_system::bzzpss_dev_encrypted(&self.bee_root_dev) - .map_err(|ex| format!("Error checking if device is encrypted: {}", ex))? - { - // if encrypted return EnterPassword so user get promted for pass - return Ok(NyanitState::EnterPassword); + if self.bee_root_dev.is_bcachefs() { + // check if device is encrypted + if nyan_system::bzzpss_dev_encrypted(&self.bee_root_dev.dev_node) + .map_err(|ex| format!("Error checking if device is encrypted: {}", ex))? + { + // if encrypted return EnterPassword so user get promted for pass + return Ok(NyanitState::EnterPassword); + } } // if unencrypted @@ -453,7 +463,10 @@ impl NyanitTUI<'_> { // try to unlock if enter pressed Key::Char('\n') => { let password = self.textarea.as_ref().unwrap().lines()[0].clone(); - match nyan_system::bcachefs_unlock(password, &self.bee_root_dev) { + match nyan_system::bcachefs_unlock( + password, + &self.bee_root_dev.dev_node, + ) { Ok(unlocked) => { if unlocked { // need to check for subvolumes and stuff diff --git a/src/nyan_system.rs b/src/nyan_system.rs index b71aa67..502bbcc 100644 --- a/src/nyan_system.rs +++ b/src/nyan_system.rs @@ -21,6 +21,7 @@ use nix; use std::fs; use std::process::Command; +use regex_lite::Regex; /// timeout for block deices population @@ -137,7 +138,28 @@ pub fn exec_command(cmd: &str, args: &Vec<&str>) -> Result<(), ExecCommandError> } } -pub fn try_find_partlabel(partlabel: &str, timeout_secs: u64) -> Option { + +#[derive(PartialEq)] +pub struct BlkIdRes { + pub fs_type: String, + pub dev_node: String, +} + +impl BlkIdRes { + pub fn is_bcachefs(&self) -> bool { + if self.fs_type == "bcachefs" { + true + } + else { + false + } + } +} + +/// +/// Will block up to timeout_secs +/// +pub fn try_find_partlabel(partlabel: &str, timeout_secs: u64) -> Option { use std::{thread, time::Duration}; let start = std::time::Instant::now(); @@ -152,9 +174,11 @@ pub fn try_find_partlabel(partlabel: &str, timeout_secs: u64) -> Option /// Gets device node aka /dev/sda1 from gpr partition label /// blkid -s PARTLABEL --match-token PARTLABEL="bzz-primary" -pub fn find_partlabel(partlabel: &str) -> Result, ExecCommandError> { +pub fn find_partlabel(partlabel: &str) -> Result, ExecCommandError> { let out = Command::new("/usr/bin/blkid") .args([ + "-s", + "TYPE", "-s", "PARTLABEL", "-t", @@ -162,13 +186,18 @@ pub fn find_partlabel(partlabel: &str) -> Result, ExecCommandErro ]) .output()?; if out.status.success() { + let re = Regex::new(r#"^(/dev/[a-z0-9-]+): TYPE="([a-z]+)" PARTLABEL="[a-z]+"$"#) + .unwrap(); let out_text = String::from_utf8(out.stdout)?; - let split_res = out_text.split_once(':').ok_or_else(|| { - ExecCommandError::Other(format!("Unexpected blkid output format: \"{}\"", out_text)) - })?; - - Ok(Some(split_res.0.to_string())) + if let Some(captured) = re.captures(&out_text) { + // let part_no = captured[1]; + // let parent_dev = captured[2]; + let res = BlkIdRes{ fs_type: captured[2].to_string(), dev_node: captured[1].to_string()}; + Ok(Some(res)) + } else { + Err(ExecCommandError::Other(format!("Unexpected blkid output format: \"{}\"", out_text))) + } } else { if let Some(code) = out.status.code() && code == 2 @@ -272,7 +301,6 @@ pub fn bzzpss_dev_encrypted(dev_name: &str) -> Result { /// And return list of date-time part of filename if both snapshots exists /// pub fn list_bzzpss_snaps(snaps_dir: &str) -> Result, ExecCommandError> { - use regex_lite::Regex; use std::path::Path; // usr or var snapshoot in a form of bzz-usr|var-yyyy-mm-ddTHH-MM-SS @@ -741,22 +769,22 @@ pub fn prepare_env() -> Result<(), ExecCommandError> { // } // # Mount the real root filesystem -pub fn mount_bee_root(dev_name: &str, mount_point: &str) -> Result<(), ExecCommandError> { +pub fn mount_bee_root(device: &BlkIdRes, mount_point: &str) -> Result<(), ExecCommandError> { use nix::mount::{MsFlags, mount}; use std::path::Path; let root_mount_flags = MsFlags::MS_RDONLY | MsFlags::MS_RELATIME; mount( - Some(dev_name), + Some(device.dev_node.as_str()), Path::new(mount_point), - Some("bcachefs"), + Some(device.fs_type.as_str()), root_mount_flags, None::<&str>, ) .map_err(|ex| { format!( "Error mounting root {} to {} :\n{}", - dev_name, + &device.dev_node, mount_point, ex.to_string() )