Adding ability to handle non bcachefs as root filesystem

This commit is contained in:
2026-09-22 17:25:02 +02:00
parent 63cb87888b
commit f388a879ea
4 changed files with 80 additions and 39 deletions
Generated
+1 -1
View File
@@ -284,7 +284,7 @@ checksum = "6aa2c4e539b869820a2b82e1aef6ff40aa85e65decdd5185e83fb4b1249cd00f"
[[package]] [[package]]
name = "nyanit" name = "nyanit"
version = "0.2.2" version = "0.2.3"
dependencies = [ dependencies = [
"nix", "nix",
"ratatui", "ratatui",
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "nyanit" name = "nyanit"
version = "0.2.2" version = "0.2.3"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
+38 -25
View File
@@ -106,6 +106,9 @@ enum NyanitState {
HandOff, HandOff,
} }
///
/// Generates confirm dialog paragraph
///
fn gen_conf_par<'a>(snap_dt: String) -> Paragraph<'a> { 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 first_line = Line::from(vec![Span::raw(CONFIRM_TEXT1), Span::raw(snap_dt).bold()]);
let confirm_line = Line::from(vec![ let confirm_line = Line::from(vec![
@@ -132,7 +135,7 @@ fn gen_conf_par<'a>(snap_dt: String) -> Paragraph<'a> {
struct NyanitTUI<'a> { struct NyanitTUI<'a> {
exit: bool, exit: bool,
state: NyanitState, state: NyanitState,
bee_root_dev: String, bee_root_dev: nyan_system::BlkIdRes,
list_state: ListState, list_state: ListState,
/// time counter manly for F2 waiting in mills /// time counter manly for F2 waiting in mills
time_counter: u64, time_counter: u64,
@@ -148,7 +151,10 @@ impl NyanitTUI<'_> {
Ok(Self { Ok(Self {
exit: false, exit: false,
state: NyanitState::Init, 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)), list_state: ListState::default().with_selected(Some(0)),
time_counter: 0, time_counter: 0,
time_counter_sec: 0, time_counter_sec: 0,
@@ -166,24 +172,28 @@ impl NyanitTUI<'_> {
// let root_list = nyan_system::list_dir(TMP_ROOT)?; // let root_list = nyan_system::list_dir(TMP_ROOT)?;
// return Err(ExecCommandError::Other(root_list)); // return Err(ExecCommandError::Other(root_list));
// list snaps if any if self.bee_root_dev.is_bcachefs() {
self.snaps_list = nyan_system::list_bzzpss_snaps(TMP_ROOT_SNAPS)?; // 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 any snaps detected check hive DB update_status
if self.snaps_list.len() > 0 { if self.snaps_list.len() > 0 {
// if pac_lock accessible and exist - rolling back // if pac_lock accessible and exist - rolling back
if let Ok(Some(snap_date_time)) = nyan_system::check_pac_lock() if let Ok(Some(snap_date_time)) = nyan_system::check_pac_lock()
&& self.snaps_list.contains(&snap_date_time) && self.snaps_list.contains(&snap_date_time)
{ {
Ok(NyanitState::ConfirmRollback(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 { else {
Ok(NyanitState::WaitForF2) Ok(NyanitState::HandOff)
} }
} } else {
// else tell to finish boot
else {
Ok(NyanitState::HandOff) Ok(NyanitState::HandOff)
} }
} }
@@ -194,17 +204,17 @@ impl NyanitTUI<'_> {
// get bee-root device name aka /dev/sda1 // get bee-root device name aka /dev/sda1
// trying for max 3 sec // trying for max 3 sec
self.bee_root_dev = nyan_system::try_find_partlabel(ROOT_PARTLABEL, 3) 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())?; .ok_or_else(|| "Timed out trying to find dev by partlabel.".to_string())?;
// works until this point!!!! if self.bee_root_dev.is_bcachefs() {
// check if device is encrypted // check if device is encrypted
if nyan_system::bzzpss_dev_encrypted(&self.bee_root_dev) if nyan_system::bzzpss_dev_encrypted(&self.bee_root_dev.dev_node)
.map_err(|ex| format!("Error checking if device is encrypted: {}", ex))? .map_err(|ex| format!("Error checking if device is encrypted: {}", ex))?
{ {
// if encrypted return EnterPassword so user get promted for pass // if encrypted return EnterPassword so user get promted for pass
return Ok(NyanitState::EnterPassword); return Ok(NyanitState::EnterPassword);
}
} }
// if unencrypted // if unencrypted
@@ -453,7 +463,10 @@ impl NyanitTUI<'_> {
// try to unlock if enter pressed // try to unlock if enter pressed
Key::Char('\n') => { Key::Char('\n') => {
let password = self.textarea.as_ref().unwrap().lines()[0].clone(); 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) => { Ok(unlocked) => {
if unlocked { if unlocked {
// need to check for subvolumes and stuff // need to check for subvolumes and stuff
+40 -12
View File
@@ -21,6 +21,7 @@
use nix; use nix;
use std::fs; use std::fs;
use std::process::Command; use std::process::Command;
use regex_lite::Regex;
/// timeout for block deices population /// 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<String> {
#[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<BlkIdRes> {
use std::{thread, time::Duration}; use std::{thread, time::Duration};
let start = std::time::Instant::now(); let start = std::time::Instant::now();
@@ -152,9 +174,11 @@ pub fn try_find_partlabel(partlabel: &str, timeout_secs: u64) -> Option<String>
/// Gets device node aka /dev/sda1 from gpr partition label /// Gets device node aka /dev/sda1 from gpr partition label
/// blkid -s PARTLABEL --match-token PARTLABEL="bzz-primary" /// blkid -s PARTLABEL --match-token PARTLABEL="bzz-primary"
pub fn find_partlabel(partlabel: &str) -> Result<Option<String>, ExecCommandError> { pub fn find_partlabel(partlabel: &str) -> Result<Option<BlkIdRes>, ExecCommandError> {
let out = Command::new("/usr/bin/blkid") let out = Command::new("/usr/bin/blkid")
.args([ .args([
"-s",
"TYPE",
"-s", "-s",
"PARTLABEL", "PARTLABEL",
"-t", "-t",
@@ -162,13 +186,18 @@ pub fn find_partlabel(partlabel: &str) -> Result<Option<String>, ExecCommandErro
]) ])
.output()?; .output()?;
if out.status.success() { 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 out_text = String::from_utf8(out.stdout)?;
let split_res = out_text.split_once(':').ok_or_else(|| { if let Some(captured) = re.captures(&out_text) {
ExecCommandError::Other(format!("Unexpected blkid output format: \"{}\"", 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(split_res.0.to_string())) Ok(Some(res))
} else {
Err(ExecCommandError::Other(format!("Unexpected blkid output format: \"{}\"", out_text)))
}
} else { } else {
if let Some(code) = out.status.code() if let Some(code) = out.status.code()
&& code == 2 && code == 2
@@ -272,7 +301,6 @@ pub fn bzzpss_dev_encrypted(dev_name: &str) -> Result<bool, ExecCommandError> {
/// And return list of date-time part of filename if both snapshots exists /// And return list of date-time part of filename if both snapshots exists
/// ///
pub fn list_bzzpss_snaps(snaps_dir: &str) -> Result<Vec<String>, ExecCommandError> { pub fn list_bzzpss_snaps(snaps_dir: &str) -> Result<Vec<String>, ExecCommandError> {
use regex_lite::Regex;
use std::path::Path; use std::path::Path;
// usr or var snapshoot in a form of bzz-usr|var-yyyy-mm-ddTHH-MM-SS // 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 // # 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 nix::mount::{MsFlags, mount};
use std::path::Path; use std::path::Path;
let root_mount_flags = MsFlags::MS_RDONLY | MsFlags::MS_RELATIME; let root_mount_flags = MsFlags::MS_RDONLY | MsFlags::MS_RELATIME;
mount( mount(
Some(dev_name), Some(device.dev_node.as_str()),
Path::new(mount_point), Path::new(mount_point),
Some("bcachefs"), Some(device.fs_type.as_str()),
root_mount_flags, root_mount_flags,
None::<&str>, None::<&str>,
) )
.map_err(|ex| { .map_err(|ex| {
format!( format!(
"Error mounting root {} to {} :\n{}", "Error mounting root {} to {} :\n{}",
dev_name, &device.dev_node,
mount_point, mount_point,
ex.to_string() ex.to_string()
) )