Skip to content

Commit b97ea7f

Browse files
committed
feat(efi::update)update extended payload path
efi::update is updated to read from path created by extend_payload_to_esp and update the firmware.
1 parent 8f47aa1 commit b97ea7f

File tree

1 file changed

+99
-5
lines changed

1 file changed

+99
-5
lines changed

src/efi.rs

Lines changed: 99 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ use std::path::{Path, PathBuf};
1111
use std::process::Command;
1212

1313
use anyhow::{anyhow, bail, Context, Result};
14-
use bootc_utils::CommandRunExt;
14+
use bootc_internal_utils::CommandRunExt;
15+
use camino::{Utf8Path, Utf8PathBuf};
1516
use cap_std::fs::Dir;
1617
use cap_std_ext::cap_std;
1718
use chrono::prelude::*;
@@ -465,14 +466,106 @@ impl Component for Efi {
465466
let Some(esp_devices) = blockdev::find_colocated_esps(&rootcxt.devices)? else {
466467
anyhow::bail!("Failed to find all esp devices");
467468
};
469+
let mut updated_firmware = BTreeMap::new();
468470

469-
for esp in esp_devices {
470-
let destpath = &self.ensure_mounted_esp(rootcxt.path.as_ref(), Path::new(&esp))?;
471+
for esp in esp_devices.iter() {
472+
let destpath = &self.ensure_mounted_esp(rootcxt.path.as_ref(), Path::new(esp))?;
471473
let destdir = openat::Dir::open(&destpath.join("EFI")).context("opening EFI dir")?;
472474
validate_esp_fstype(&destdir)?;
473475
log::trace!("applying diff: {}", &diff);
474476
filetree::apply_diff(&updated, &destdir, &diff, None)
475477
.context("applying filesystem changes")?;
478+
// update firmware
479+
let firmware_base_dir_path = Path::new("usr/lib/efi/firmware");
480+
481+
let available_payloads = {
482+
let mut payloads = BTreeMap::new();
483+
if rootcxt.sysroot.exists(firmware_base_dir_path)? {
484+
let firmware_base_dir = rootcxt.sysroot.sub_dir(firmware_base_dir_path)?;
485+
for pkg_entry in firmware_base_dir.list_dir(".")?.flatten() {
486+
if firmware_base_dir.get_file_type(&pkg_entry)? == openat::SimpleType::Dir {
487+
let pkg_name = pkg_entry.file_name().to_string_lossy().to_string();
488+
payloads.insert(pkg_name, pkg_entry.file_name().to_owned());
489+
}
490+
}
491+
}
492+
payloads
493+
};
494+
495+
let old_keys: std::collections::HashSet<_> = current.firmware.keys().collect();
496+
let new_keys: std::collections::HashSet<_> = available_payloads.keys().collect();
497+
let all_keys: std::collections::HashSet<_> = old_keys.union(&new_keys).collect();
498+
499+
// determine if it should be added, updated, or removed.
500+
for pkg_name in all_keys {
501+
let old_payload = current.firmware.get(*pkg_name);
502+
let new_payload_path = available_payloads.get(*pkg_name);
503+
504+
let (diff, src_dir, new_content) = match (old_payload, new_payload_path) {
505+
// Payload exists in both old state and new source.
506+
(Some(old), Some(new_path)) => {
507+
let new_ver_dir = rootcxt
508+
.sysroot
509+
.sub_dir(firmware_base_dir_path)?
510+
.sub_dir(new_path.as_os_str())?;
511+
let new_payload_dir = new_ver_dir.sub_dir("EFI")?;
512+
let new_ft = crate::filetree::FileTree::new_from_dir(&new_payload_dir)?;
513+
let old_ft = old.filetree.as_ref().unwrap_or(&new_ft);
514+
let diff = old_ft.diff(&new_ft)?;
515+
516+
let meta: ContentMetadata =
517+
serde_json::from_reader(new_ver_dir.open_file("EFI.json")?)?;
518+
let content = Box::new(InstalledContent {
519+
meta,
520+
filetree: Some(new_ft),
521+
adopted_from: None,
522+
firmware: BTreeMap::new(),
523+
});
524+
(diff, Some(new_payload_dir), Some(content))
525+
}
526+
// add as old payload is none
527+
(None, Some(new_path)) => {
528+
let new_ver_dir = rootcxt
529+
.sysroot
530+
.sub_dir(firmware_base_dir_path)?
531+
.sub_dir(new_path.as_os_str())?;
532+
let new_payload_dir = new_ver_dir.sub_dir("EFI")?;
533+
let new_ft = crate::filetree::FileTree::new_from_dir(&new_payload_dir)?;
534+
let empty_ft = crate::filetree::FileTree {
535+
children: BTreeMap::new(),
536+
};
537+
let diff = empty_ft.diff(&new_ft)?;
538+
539+
let meta: ContentMetadata =
540+
serde_json::from_reader(new_ver_dir.open_file("EFI.json")?)?;
541+
let content = Box::new(InstalledContent {
542+
meta,
543+
filetree: Some(new_ft),
544+
adopted_from: None,
545+
firmware: BTreeMap::new(),
546+
});
547+
(diff, Some(new_payload_dir), Some(content))
548+
}
549+
// continue with old firmware
550+
(Some(_old), None) => continue,
551+
// Should not happen.
552+
(None, None) => continue,
553+
};
554+
555+
//apply the above diffs
556+
for esp in esp_devices.iter() {
557+
let destpath =
558+
&self.ensure_mounted_esp(rootcxt.path.as_ref(), Path::new(esp))?;
559+
let destdir = openat::Dir::open(destpath)?;
560+
let src_dir = src_dir.as_ref().unwrap_or(&destdir);
561+
filetree::apply_diff(src_dir, &destdir, &diff, None)
562+
.context(format!("applying firmware diff for {}", pkg_name))?;
563+
}
564+
565+
if let Some(content) = new_content {
566+
updated_firmware.insert(pkg_name.to_string(), content);
567+
}
568+
}
476569

477570
// Do the sync before unmount
478571
fsfreeze_thaw_cycle(destdir.open_file(".")?)?;
@@ -485,7 +578,7 @@ impl Component for Efi {
485578
meta: updatemeta,
486579
filetree: Some(updatef),
487580
adopted_from,
488-
firmware: BTreeMap::new(),
581+
firmware: updated_firmware,
489582
})
490583
}
491584

@@ -993,7 +1086,9 @@ Boot0003* test";
9931086
paths,
9941087
["usr/lib/efi/FOO/1.1/EFI", "usr/lib/efi/BAR/1.1/EFI"]
9951088
);
1089+
Ok(())
9961090
}
1091+
9971092
#[test]
9981093
fn test_extend_payload() -> Result<()> {
9991094
use std::fs;
@@ -1159,4 +1254,3 @@ exit 1
11591254
Ok(())
11601255
}
11611256
}
1162-

0 commit comments

Comments
 (0)