Compare commits

...
2 Commits
Author SHA256 Message Date
kira c61d283177 Working on EFI boot records update 2026-09-01 01:32:58 +02:00
kira eb6ef2a19f Changing how we parsing CMD arguments 2026-09-01 01:32:18 +02:00
2 changed files with 164 additions and 40 deletions
+96
View File
@@ -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<String, SysUpgradeError> {
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<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))
})?;
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(())
}
+64 -36
View File
@@ -14,16 +14,17 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use clap::{Args, Parser};
use clap::{Args, Parser, Subcommand};
use signal_hook::{consts::SIGINT, iterator::Signals};
use std;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std;
mod hive_system;
mod hive_config;
use crate::hive_config::HiveConfig;
use crate::hive_system::SysUpgradeError;
mod daemon;
@@ -108,34 +109,72 @@ impl std::error::Error for HiveUpError {}
// Define the mutually exclusive group
#[derive(Args, Debug)]
#[group(required = true, multiple = false)] // 'multiple = false' enforces exclusivity
struct HiveUpMode {
/// Check for updates, prints number of updates available
#[group(required = true, multiple = false)]
struct RemoteArgs {
/// Ask daemon to chack for updates
#[arg(long)]
check_updates: bool,
/// Check for available updates, prints number of updates available
/// Ask daemon if there is any updates available
#[arg(long)]
updates_available: bool,
updates_avail: bool,
}
#[derive(Args, Debug)]
#[group(required = true, multiple = false)]
struct CliArgs {
/// Perform system upgrade
#[arg(long)]
upgrade: bool,
/// Run hive-up in daemon mode
/// Install new kernel into boot partition
#[arg(long)]
daemon: bool,
update_boot: bool,
}
#[derive(Subcommand, Debug)]
#[group(required = true)] // 'multiple = false' enforces exclusivity
enum HiveUpMode {
/// Perform local operations
Cli(CliArgs),
/// Ask hive-up daemon something
Remote(RemoteArgs),
/// Run hive-up in daemon mode
Daemon,
}
/// Update program fot Kira Linux :3
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
#[command(author, version, about)]
struct Cli {
/// hive-up operation mode
#[command(flatten)]
#[command(subcommand)]
mode: HiveUpMode,
}
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 {
println!("Starting full system upgrade");
match hive_system::sys_upgrade() {
Ok(snap_time) => {
bzz_db.update_status = true;
bzz_db.update_on_reboot = false;
bzz_db.last_snapshot_time = snap_time;
hive_db::write_db(&bzz_db)?;
}
Err(SysUpgradeError::PkgUpgradeErr((snap_time, ex))) => {
bzz_db.update_status = false;
bzz_db.update_on_reboot = false;
bzz_db.last_snapshot_time = snap_time;
hive_db::write_db(&bzz_db)?;
return Err(ex.into());
}
Err(ex) => return Err(ex.to_string().into()),
}
}
Ok(())
}
fn main() -> Result<(), HiveUpError> {
// registering signals handling
let term_flag: Arc<AtomicBool> = Arc::new(AtomicBool::new(false));
@@ -153,36 +192,25 @@ fn main() -> Result<(), HiveUpError> {
// read config
let bzz_config = hive_config::read_config()?;
// Check CMD flags
if args.mode.check_updates {
match args.mode {
HiveUpMode::Daemon => daemon::run(bzz_config, term_flag.clone(), reload_flag.clone())?,
HiveUpMode::Cli(cli_args) => {
if cli_args.upgrade {
cli_upgrade(bzz_config)?;
} else if cli_args.update_boot {
}
}
HiveUpMode::Remote(remote_args) => {
if remote_args.check_updates {
let up_num = hive_intercom::client_check_for_updates()?;
println!("Updates awailable: {}", up_num);
} else if args.mode.updates_available {
} else if remote_args.updates_avail {
let up_num = hive_intercom::client_updates_available()?;
println!("Updates awailable: {}", up_num);
} else if args.mode.upgrade {
let mut bzz_db = hive_db::read_db()?;
if bzz_db.update_on_reboot {
println!("Starting full system upgrade");
match hive_system::sys_upgrade() {
Ok(snap_time) => {
bzz_db.update_status = true;
bzz_db.update_on_reboot = false;
bzz_db.last_snapshot_time = snap_time;
hive_db::write_db(&bzz_db)?;
}
Err(SysUpgradeError::PkgUpgradeErr((snap_time, ex))) => {
bzz_db.update_status = false;
bzz_db.update_on_reboot = false;
bzz_db.last_snapshot_time = snap_time;
hive_db::write_db(&bzz_db)?;
return Err(ex.into());
}
Err(ex) => return Err(ex.to_string().into()),
}
}
} else if args.mode.daemon {
daemon::run(bzz_config, term_flag.clone(), reload_flag.clone())?;
}
Ok(())
}