diff --git a/src/hive_system.rs b/src/hive_system.rs index 723e152..49ecbbd 100644 --- a/src/hive_system.rs +++ b/src/hive_system.rs @@ -22,7 +22,13 @@ use std::fs; use std::process::Command; use time_format; + const SNAPS_DIR: &str = "/bzz_snaps"; +const EFI_BOOT_MOUNT_POINT: &str = "/beefi"; +const EFI_PARTLABEL: &str = "bee-efi"; +const BOOT_MENU_LABEL: &str = "Kira OS"; +const UKI_IMAGE_NAME: &str = "\\EFI\\kira-linux-lts.efi"; + #[derive(Debug)] pub struct CommandFailed { @@ -268,3 +274,93 @@ pub fn sys_upgrade() -> Result { Err(ex) => Err(SysUpgradeError::PkgUpgradeErr((snap_time, ex))), } } + +/// 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> { + 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)) + })?; + + 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 +/// (basename $(readlink -f /sys/class/block/sda1/..)) +/// But lsblk approach looks more reasonable +/// NAME="/dev/nvme0n1p1" PARTLABEL="nyazefi" PARTN="1" PKNAME="/dev/nvme0n1" +/// lsblk -P -p -Q 'PARTLABEL=="nyazefi"' -o NAME,PARTLABEL,PARTN,PKNAME +/// Returns: touple of partition number and parent device as Strings (part_num, par_dev) +/// Returns Error if no efi partition was found +/// + +fn get_efi_part_info() -> Result<(String,String), ExecCommandError> { + use regex::Regex; + let re = Regex::new(r#"^PARTN="([0-9]+)" PKNAME="([0-9a-Z]+)"$"#).unwrap(); + + let lsblk_query = format!("PARTLABEL==\"{}\"", EFI_PARTLABEL); + let lsblk_args: Vec<&str> = vec!["-P", "-p", "-Q", &lsblk_query, "-o", "PARTN,PKNAME"]; + let lsblk_res = exec_command_out("lsblk", &lsblk_args)?; + + if let Some(captured) = re.captures(&lsblk_res) { + // let part_no = captured[1]; + // let parent_dev = captured[2]; + Ok((captured[1].to_string(), captured[2].to_string())) + } + else { + Err(ExecCommandError::Other(format!("No EFI partition (with PARTLABEL={}) was found!", EFI_PARTLABEL))) + } + +} + +/// +/// efibootmgr +/// Assuming boot partition has "bee-efi" PARTLABEL +/// +/// Generaly lets just add new record with date. Label modification not allways works? +/// May add deletion of old record latel +/// sudo efibootmgr --create --disk /dev/nvme0n1 --part 1 --label "Kira OS" --loader '\EFI\nyanlinux\kira-bzz.efi' --unicode 'initrd=\EFI\initrd.img' + +pub fn boot_record_update(maybe_kernel_cmd: Option<&str>) -> Result<(), ExecCommandError> { + + let (efi_partno, efi_parent_dev) = get_efi_part_info()?; + + let local_date = time_format::strftime_local("%Y-%m-%d", time_format::now().unwrap()).unwrap(); + let boot_label = format!("{} {}", BOOT_MENU_LABEL, local_date); + + let mut efibootmgr_args: Vec<&str> = vec!["--create", "--disk", &efi_parent_dev, "--part", &efi_partno, "--label", &boot_label, "--loader", UKI_IMAGE_NAME]; + if let Some(kernel_cmd) = maybe_kernel_cmd { + efibootmgr_args.push("--unicode"); + efibootmgr_args.push(kernel_cmd); + } + exec_command("efibootmgr", &efibootmgr_args)?; + + Ok(()) + +}