Skip to content

Commit 95d5e55

Browse files
composefs/status: Read UKI entries to check for queued rollback
Parse the Grub menuentry file, `boot/grub2/user.cfg` to get a list of bootable UKIs and figure out if a rollback is currently queued. Signed-off-by: Johan-Liebert1 <[email protected]>
1 parent 0ff4cf6 commit 95d5e55

File tree

2 files changed

+55
-8
lines changed

2 files changed

+55
-8
lines changed

crates/lib/src/deploy.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -783,8 +783,16 @@ const CURRENT_ENTRIES: &str = "entries";
783783
const STAGED_ENTRIES: &str = "entries.staged";
784784
const ROLLBACK_ENTRIES: &str = STAGED_ENTRIES;
785785

786+
// Need str to store lifetime
787+
pub(crate) fn get_sorted_uki_boot_entries<'a>(str: &'a mut String) -> Result<Vec<MenuEntry<'a>>> {
788+
let mut file = std::fs::File::open("/sysroot/boot/grub2/user.cfg")?;
789+
file.read_to_string(str)?;
790+
parse_grub_menuentry_file(str)
791+
}
792+
793+
786794
#[context("Getting boot entries")]
787-
pub(crate) fn get_sorted_boot_entries(ascending: bool) -> Result<Vec<BLSConfig>> {
795+
pub(crate) fn get_sorted_bls_boot_entries(ascending: bool) -> Result<Vec<BLSConfig>> {
788796
let mut all_configs = vec![];
789797

790798
for entry in std::fs::read_dir(format!("/sysroot/boot/loader/{CURRENT_ENTRIES}"))? {
@@ -819,7 +827,7 @@ pub(crate) fn rollback_composefs_bls() -> Result<()> {
819827
// After this:
820828
// all_configs[0] -> booted depl
821829
// all_configs[1] -> rollback depl
822-
let mut all_configs = get_sorted_boot_entries(false)?;
830+
let mut all_configs = get_sorted_bls_boot_entries(false)?;
823831

824832
// Update the indicies so that they're swapped
825833
for (idx, cfg) in all_configs.iter_mut().enumerate() {

crates/lib/src/status.rs

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ use ostree_ext::ostree;
2424
use tokio::io::AsyncReadExt;
2525

2626
use crate::cli::OutputFormat;
27-
use crate::deploy::get_sorted_boot_entries;
27+
use crate::deploy::get_sorted_bls_boot_entries;
28+
use crate::deploy::get_sorted_uki_boot_entries;
2829
use crate::install::BootType;
2930
use crate::install::ORIGIN_KEY_BOOT;
3031
use crate::install::ORIGIN_KEY_BOOT_TYPE;
@@ -422,6 +423,9 @@ pub(crate) async fn composefs_deployment_status() -> Result<Host> {
422423
Err(e) => Err(e),
423424
}?;
424425

426+
// NOTE: This cannot work if we support both BLS and UKI at the same time
427+
let mut boot_type: Option<BootType> = None;
428+
425429
for depl in deployments {
426430
let depl = depl?;
427431

@@ -441,6 +445,21 @@ pub(crate) async fn composefs_deployment_status() -> Result<Host> {
441445
let boot_entry =
442446
boot_entry_from_composefs_deployment(ini, depl_file_name.to_string()).await?;
443447

448+
// SAFETY: boot_entry.composefs will always be present
449+
let boot_type_from_origin = boot_entry.composefs.as_ref().unwrap().boot_type;
450+
451+
match boot_type {
452+
Some(current_type) => {
453+
if current_type != boot_type_from_origin {
454+
anyhow::bail!("Conflicting boot types")
455+
}
456+
}
457+
458+
None => {
459+
boot_type = Some(boot_type_from_origin);
460+
}
461+
};
462+
444463
if depl.file_name() == booted_image_verity {
445464
host.spec.image = boot_entry.image.as_ref().map(|x| x.image.clone());
446465
host.status.booted = Some(boot_entry);
@@ -457,11 +476,31 @@ pub(crate) async fn composefs_deployment_status() -> Result<Host> {
457476
host.status.rollback = Some(boot_entry);
458477
}
459478

460-
host.status.rollback_queued = !get_sorted_boot_entries(false)?
461-
.first()
462-
.ok_or(anyhow::anyhow!("First boot entry not found"))?
463-
.options
464-
.contains(booted_image_verity);
479+
// Shouldn't really happen, but for sanity nonetheless
480+
let Some(boot_type) = boot_type else {
481+
anyhow::bail!("Could not determine boot type");
482+
};
483+
484+
match boot_type {
485+
BootType::Bls => {
486+
host.status.rollback_queued = !get_sorted_bls_boot_entries(false)?
487+
.first()
488+
.ok_or(anyhow::anyhow!("First boot entry not found"))?
489+
.options
490+
.contains(booted_image_verity);
491+
}
492+
493+
BootType::Uki => {
494+
let mut s = String::new();
495+
496+
host.status.rollback_queued = !get_sorted_uki_boot_entries(&mut s)?
497+
.first()
498+
.ok_or(anyhow::anyhow!("First boot entry not found"))?
499+
.body
500+
.chainloader
501+
.contains(booted_image_verity);
502+
}
503+
};
465504

466505
if host.status.rollback_queued {
467506
host.spec.boot_order = BootOrder::Rollback

0 commit comments

Comments
 (0)