Changes to snapshot /usr and /var subvolumes instead of root, regex-lite adoption, and initial documentation

This commit is contained in:
2026-09-10 00:17:19 +02:00
parent 17cea4b89e
commit 20bdd217c4
6 changed files with 157 additions and 121 deletions
+2 -12
View File
@@ -62,7 +62,8 @@ pub struct HiveDb {
pub update_check_timestamp: u64,
/// non zero if there is updates that can bee applied, showing numbers of packages that can be updated
pub updates_available: u32,
/// true if last update fas successful
/// true if last update was successful
/// if it is false - nyanit need to roll back snapshots
pub update_status: bool,
/// datetime of last snapshot in format "%Y-%m-%dT%H:%M:%S"
pub last_snapshot_time: String,
@@ -101,15 +102,4 @@ pub fn write_db(db: &HiveDb) -> Result<(), DBError> {
Ok(())
}
///
/// writes new last update check time to db
/// and returns old db value on success
///
pub fn update_last_check_update_time(new_timestamp: u64) -> Result<u64, DBError> {
let mut db = read_db()?;
let old_value = db.update_check_timestamp;
db.update_check_timestamp = new_timestamp;
write_db(&db)?;
Ok(old_value)
}
+81 -63
View File
@@ -184,12 +184,31 @@ pub fn pkg_upgrade() -> Result<(), ExecCommandError> {
exec_command("pacman", &vec!["-Su", "--noconfirm", "--noprogressbar"])
}
///
/// bcachefs subvolume snapshot -r / /snap1
/// creates read only snapshoy of "subvolume" and places it into "target"]
/// bcachefs subvolume snapshot -r /subvolume /target
/// -r creates read only snapshot
/// returns snapshot time on sucess
///
pub fn snapshot_root() -> Result<String, ExecCommandError> {
pub fn snapshot(subvolume: &str, target: &str) -> Result<(), ExecCommandError> {
exec_command(
"bcachefs",
&vec!["subvolume", "snapshot", "-r", subvolume, target],
)?;
Ok(())
}
///
///
/// bcachefs subvolume snapshot -r /target /SNAPS_DIR/bzz-target-yyyy-mm-ddTHH-MM-SS
/// Creates read only snapshots of /usr and /var subvolumes
/// And places them to /SNAPS_DIR/bzz-usr-yyyy-mm-ddTHH-MM-SS and /SNAPS_DIR/bzz-var-yyyy-mm-ddTHH-MM-SS
/// returns snapshot time on sucess
///
pub fn snapshot_system() -> Result<String, ExecCommandError> {
use std::path::Path;
// if snaps dir path do not exist - create it
let snaps_path = Path::new(SNAPS_DIR);
@@ -199,43 +218,42 @@ pub fn snapshot_root() -> Result<String, ExecCommandError> {
let ts = time_format::now().unwrap();
let local_time = time_format::strftime_local("%Y-%m-%dT%H:%M:%S", ts).unwrap();
let snapshot_name = format!("{}/bzz-{}", SNAPS_DIR, local_time);
let usr_snapshot_name = format!("{}/bzz-usr-{}", SNAPS_DIR, local_time);
let var_snapshot_name = format!("{}/bzz-var-{}", SNAPS_DIR, local_time);
exec_command(
"bcachefs",
&vec!["subvolume", "snapshot", "-r", "/", &snapshot_name],
)?;
snapshot("/usr", &usr_snapshot_name)?;
snapshot("/var", &var_snapshot_name)?;
Ok(local_time)
}
//const TMP_ROOT: &str = "/mnt/bee-root";
pub fn list_bzzpss_snaps() -> Result<Vec<String>, ExecCommandError> {
use regex::Regex;
use std::path::Path;
// pub fn list_bzzpss_snaps() -> Result<Vec<String>, ExecCommandError> {
// use regex::Regex;
// use std::path::Path;
// root snapshoot in a form of bzz-yyyy-mm-ddTHH-MM-SS
let re = Regex::new(r"^bzz-[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}-[0-9]{2}-[0-9]{2}$").unwrap();
// // root snapshoot in a form of bzz-yyyy-mm-ddTHH-MM-SS
// let re = Regex::new(r"^bzz-[a-z]+-[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}-[0-9]{2}-[0-9]{2}$").unwrap();
let mut res: Vec<String> = Vec::new();
// if snaps dir path do not exist return empty list
if !Path::new(SNAPS_DIR).exists() {
return Ok(res);
}
// let mut res: Vec<String> = Vec::new();
// // if snaps dir path do not exist return empty list
// if !Path::new(SNAPS_DIR).exists() {
// return Ok(res);
// }
for maybe_entry in fs::read_dir(SNAPS_DIR)? {
let entry = maybe_entry?;
if entry.file_type()?.is_dir() {
if let Some(dir_name) = entry.file_name().to_str()
&& re.is_match(dir_name)
{
res.push(dir_name.to_string());
}
}
}
res.sort();
Ok(res)
}
// for maybe_entry in fs::read_dir(SNAPS_DIR)? {
// let entry = maybe_entry?;
// if entry.file_type()?.is_dir() {
// if let Some(dir_name) = entry.file_name().to_str()
// && re.is_match(dir_name)
// {
// res.push(dir_name.to_string());
// }
// }
// }
// res.sort();
// Ok(res)
// }
pub fn check_if_run_as_root() -> bool {
use nix::unistd::Uid;
@@ -271,7 +289,7 @@ impl std::error::Error for SysUpgradeError {}
///
pub fn sys_upgrade() -> Result<String, SysUpgradeError> {
// snapshooting root
let snap_time = snapshot_root().map_err(SysUpgradeError::SnapshotError)?;
let snap_time = snapshot_system().map_err(SysUpgradeError::SnapshotError)?;
// try to perform packages upgrade
match pkg_upgrade() {
Ok(_) => Ok(snap_time),
@@ -281,37 +299,37 @@ pub fn sys_upgrade() -> Result<String, SysUpgradeError> {
/// 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<Option<String>, ExecCommandError> {
let out = Command::new("/usr/bin/blkid")
.args([
"-s",
"PARTLABEL",
"-t",
format!("PARTLABEL=\"{}\"", partlabel).as_str(),
])
.output()?;
if out.status.success() {
let out_text = String::from_utf8(out.stdout)?;
// pub fn find_partlabel(partlabel: &str) -> Result<Option<String>, ExecCommandError> {
// let out = Command::new("/usr/bin/blkid")
// .args([
// "-s",
// "PARTLABEL",
// "-t",
// format!("PARTLABEL=\"{}\"", partlabel).as_str(),
// ])
// .output()?;
// if out.status.success() {
// 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))
})?;
// 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()))
} else {
if let Some(code) = out.status.code()
&& code == 2
{
Ok(None)
} else {
Err(ExecCommandError::Other(format!(
"Error while looking for partlabel={}: \"{}\"",
partlabel,
String::from_utf8(out.stderr).unwrap_or_else(|ex| ex.to_string())
)))
}
}
}
// Ok(Some(split_res.0.to_string()))
// } else {
// if let Some(code) = out.status.code()
// && code == 2
// {
// Ok(None)
// } else {
// Err(ExecCommandError::Other(format!(
// "Error while looking for partlabel={}: \"{}\"",
// partlabel,
// String::from_utf8(out.stderr).unwrap_or_else(|ex| ex.to_string())
// )))
// }
// }
// }
///
/// We need to use lsblk to find out parent device, or read topology from sysfs
@@ -327,7 +345,7 @@ pub fn find_partlabel(partlabel: &str) -> Result<Option<String>, ExecCommandErro
///
///
fn get_efi_part_info() -> Result<(String, String), ExecCommandError> {
use regex::Regex;
use regex_lite::Regex;
let re = Regex::new(r#"^PARTN="([0-9]+)" PKNAME="([0-9a-Z]+)"$"#).unwrap();
let lsblk_query = format!("PARTLABEL==\"{}\"", EFI_PARTLABEL);
@@ -351,7 +369,7 @@ fn get_efi_part_info() -> Result<(String, String), ExecCommandError> {
/// Boot0000* Nyan
///
fn list_efi_bootnums() -> Result<Vec<String>, ExecCommandError> {
use regex::Regex;
use regex_lite::Regex;
let re = Regex::new(r#"^Boot([0-9A-F]{4})\* "#).unwrap();
let str_res = exec_command_out("efibootmgr", &vec![])?;
@@ -444,7 +462,7 @@ pub fn init_efi_boot_record(maybe_kernel_cmd: &Option<String>) -> Result<(), Exe
/// Result is a sorted vector of string
///
fn list_installed_kernels() -> Result<Vec<String>, ExecCommandError> {
use regex::Regex;
use regex_lite::Regex;
let re = Regex::new(r#"^[0-9]+\.[0-9]+\.[0-9]+-[0-9]-kira-lts"#).unwrap();
let mut kernel_dirs: Vec<String> = Vec::new();
+4 -1
View File
@@ -163,8 +163,11 @@ struct Cli {
fn cli_upgrade(bzz_config: HiveConfig) -> Result<(), HiveUpError> {
let mut bzz_db = hive_db::read_db()?;
if bzz_db.update_on_reboot || bzz_config.update.auto_update {
if (bzz_db.updates_available !=0) && (bzz_db.update_on_reboot || bzz_config.update.auto_update) {
println!("Starting full system upgrade");
bzz_db.update_status = false;
hive_db::write_db(&bzz_db)?;
match hive_system::sys_upgrade() {
Ok(snap_time) => {
bzz_db.update_status = true;