Skip to content

Commit 6709ad9

Browse files
committed
bootupd update now reads from extended payload
1 parent 5db256c commit 6709ad9

File tree

1 file changed

+106
-4
lines changed

1 file changed

+106
-4
lines changed

src/efi.rs

Lines changed: 106 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -461,15 +461,117 @@ impl Component for Efi {
461461
anyhow::bail!("Failed to find all esp devices");
462462
};
463463

464-
for esp in esp_devices {
465-
let destpath = &self.ensure_mounted_esp(rootcxt.path.as_ref(), Path::new(&esp))?;
464+
for esp in esp_devices.iter() {
465+
let destpath = &self.ensure_mounted_esp(rootcxt.path.as_ref(), Path::new(esp))?;
466466
let destdir = openat::Dir::open(&destpath.join("EFI")).context("opening EFI dir")?;
467467
validate_esp_fstype(&destdir)?;
468468
log::trace!("applying diff: {}", &diff);
469469
filetree::apply_diff(&updated, &destdir, &diff, None)
470470
.context("applying filesystem changes")?;
471+
}
471472

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

0 commit comments

Comments
 (0)