Skip to content

Commit 0e5fe60

Browse files
efi: Handle compatibility for systems with no usr/lib/efi
In #995 changes were made to move files from `usr/lib/ostree-boot/EFI` to `usr/lib/efi` which caused issues with older bootupd failing to understand the new layout created by newer version of bootupd. To make the change backwards compatible, we now check for the existence of `usr/lib/efi`, and only use the new layout if we find it. Else, default back to the older layout at `usr/lib/bootupd` Signed-off-by: Pragyan Poudyal <pragyanpoudyal41999@gmail.com>
1 parent ab0d9a1 commit 0e5fe60

1 file changed

Lines changed: 104 additions & 43 deletions

File tree

src/efi.rs

Lines changed: 104 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -568,50 +568,44 @@ impl Component for Efi {
568568
}
569569

570570
fn generate_update_metadata(&self, sysroot: &str) -> Result<Option<ContentMetadata>> {
571-
let sysroot_path = Path::new(sysroot);
571+
let sysroot_path = Utf8Path::new(sysroot);
572572
let sysroot_dir = Dir::open_ambient_dir(sysroot_path, cap_std::ambient_authority())?;
573573

574-
if let Some(ostreeboot) = sysroot_dir
574+
let ostreeboot = sysroot_dir
575575
.open_dir_optional(ostreeutil::BOOT_PREFIX)
576-
.context("Opening usr/lib/ostree-boot")?
577-
{
578-
let cruft = ["loader", "grub2"];
579-
for p in cruft.iter() {
580-
ostreeboot.remove_all_optional(p)?;
581-
}
582-
// Transfer ostree-boot EFI files to usr/lib/efi
583-
transfer_ostree_boot_to_usr(sysroot_path)?;
576+
.context("Opening usr/lib/ostree-boot")?;
577+
578+
// Newer images >= F44 have boot entries in /usr/lib/efi, but older images
579+
// have them in /usr/lib/ostree-boot, which we move to /usr/lib/bootupd/updates/EFI
580+
let metadata = match ostreeboot {
581+
Some(ostreeboot) => {
582+
let cruft = ["loader", "grub2"];
583+
for p in cruft.iter() {
584+
ostreeboot.remove_all_optional(p)?;
585+
}
584586

585-
// Remove usr/lib/ostree-boot/efi/EFI dir (after transfer) or if it is empty
586-
ostreeboot.remove_all_optional("efi/EFI")?;
587-
}
587+
let meta = if sysroot_path.join(EFILIB).exists() {
588+
// Transfer usr/lib/ostree-boot/EFI files to usr/lib/efi
589+
transfer_ostree_boot_to_usr(sysroot_path)?;
590+
generate_meta_from_usr_efi(sysroot_path)?
591+
} else {
592+
// Transfer usr/lib/ostree-boot/EFI files to usr/lib/bootupd/updates/EFI
593+
transfer_ostree_boot_to_bootupd_updates(sysroot_path, self)?
594+
};
588595

589-
if let Some(efi_components) =
590-
get_efi_component_from_usr(Utf8Path::from_path(sysroot_path).unwrap(), EFILIB)?
591-
{
592-
let mut packages = Vec::new();
593-
let mut modules_vec: Vec<Module> = vec![];
594-
for efi in efi_components {
595-
packages.push(format!("{}-{}", efi.name, efi.version));
596-
modules_vec.push(Module {
597-
name: efi.name,
598-
rpm_evr: efi.version,
599-
});
596+
// Remove usr/lib/ostree-boot/efi/EFI dir (after transfer) or if it is empty
597+
ostreeboot.remove_all_optional("efi/EFI")?;
598+
599+
meta
600600
}
601-
modules_vec.sort_unstable();
602-
603-
// change to now to workaround https://github.com/coreos/bootupd/issues/933
604-
let timestamp = std::time::SystemTime::now();
605-
let meta = ContentMetadata {
606-
timestamp: chrono::DateTime::<Utc>::from(timestamp),
607-
version: packages.join(","),
608-
versions: Some(modules_vec),
609-
};
610-
write_update_metadata(sysroot, self, &meta)?;
611-
Ok(Some(meta))
612-
} else {
613-
anyhow::bail!("Failed to find EFI components");
614-
}
601+
602+
// If /usr/lib/ostree-boot doesn't exist, assume /usr/lib/efi will
603+
None => generate_meta_from_usr_efi(sysroot_path)?,
604+
};
605+
606+
write_update_metadata(sysroot_path.as_str(), self, &metadata)?;
607+
608+
Ok(Some(metadata))
615609
}
616610

617611
fn query_update(&self, sysroot: &openat::Dir) -> Result<Option<ContentMetadata>> {
@@ -801,6 +795,34 @@ fn find_file_recursive<P: AsRef<Path>>(dir: P, target_file: &str) -> Result<Vec<
801795
Ok(result)
802796
}
803797

798+
#[context("Generating metadata from usr/lib/efi")]
799+
fn generate_meta_from_usr_efi(sysroot_path: &Utf8Path) -> Result<ContentMetadata> {
800+
let Some(efi_components) = get_efi_component_from_usr(sysroot_path, EFILIB)? else {
801+
anyhow::bail!("Failed to find EFI components");
802+
};
803+
804+
let mut packages = Vec::new();
805+
let mut modules_vec: Vec<Module> = vec![];
806+
for efi in efi_components {
807+
packages.push(format!("{}-{}", efi.name, efi.version));
808+
modules_vec.push(Module {
809+
name: efi.name,
810+
rpm_evr: efi.version,
811+
});
812+
}
813+
modules_vec.sort_unstable();
814+
815+
// change to now to workaround https://github.com/coreos/bootupd/issues/933
816+
let timestamp = std::time::SystemTime::now();
817+
let meta = ContentMetadata {
818+
timestamp: chrono::DateTime::<Utc>::from(timestamp),
819+
version: packages.join(","),
820+
versions: Some(modules_vec),
821+
};
822+
823+
Ok(meta)
824+
}
825+
804826
#[derive(Debug, PartialEq, Eq)]
805827
pub struct EFIComponent {
806828
pub name: String,
@@ -851,9 +873,48 @@ fn get_efi_component_from_usr<'a>(
851873
Ok(Some(components))
852874
}
853875

876+
/// Copies usr/lib/ostree-boot/EFI to usr/lib/bootupd/updates
877+
fn transfer_ostree_boot_to_bootupd_updates(
878+
sysroot: &Utf8Path,
879+
component: &Efi,
880+
) -> Result<ContentMetadata> {
881+
let ostreebootdir = sysroot.join(ostreeutil::BOOT_PREFIX);
882+
883+
// move EFI files to updates dir from /usr/lib/ostree-boot
884+
if !ostreebootdir.exists() {
885+
anyhow::bail!("Failed to find {ostreebootdir}");
886+
}
887+
888+
let efisrc = ostreebootdir.join("efi/EFI");
889+
if !efisrc.exists() {
890+
bail!("Failed to find {:?}", &efisrc);
891+
}
892+
893+
let dest_efidir = component_updatedir(sysroot.as_str(), component);
894+
let dest_efidir = Utf8PathBuf::from_path_buf(dest_efidir).expect("Path is invalid UTF-8");
895+
896+
// Fork off mv() because on overlayfs one can't rename() a lower level
897+
// directory today, and this will handle the copy fallback.
898+
Command::new("mv")
899+
.args([&efisrc, &dest_efidir])
900+
.run_capture_stderr()?;
901+
902+
let efidir = openat::Dir::open(dest_efidir.as_std_path())
903+
.with_context(|| format!("Opening {}", dest_efidir))?;
904+
905+
let files = crate::util::filenames(&efidir)?.into_iter().map(|mut f| {
906+
f.insert_str(0, "/boot/efi/EFI");
907+
f
908+
});
909+
910+
let files = files.collect::<Vec<_>>();
911+
912+
query_files(sysroot.as_str(), files)
913+
}
914+
854915
/// Copy files from usr/lib/ostree-boot/efi/EFI to /usr/lib/efi/<component>/<evr>/
855-
fn transfer_ostree_boot_to_usr(sysroot: &Path) -> Result<()> {
856-
let ostreeboot_efi = Path::new(ostreeutil::BOOT_PREFIX).join("efi");
916+
fn transfer_ostree_boot_to_usr(sysroot: &Utf8Path) -> Result<()> {
917+
let ostreeboot_efi = Utf8Path::new(ostreeutil::BOOT_PREFIX).join("efi");
857918
let ostreeboot_efi_path = sysroot.join(&ostreeboot_efi);
858919

859920
let efi = ostreeboot_efi_path.join("EFI");
@@ -873,7 +934,7 @@ fn transfer_ostree_boot_to_usr(sysroot: &Path) -> Result<()> {
873934

874935
// Run `rpm -qf <filepath>`
875936
let pkg = crate::packagesystem::query_file(
876-
sysroot.to_str().unwrap(),
937+
sysroot.as_str(),
877938
boot_filepath.to_str().unwrap(),
878939
)?;
879940

@@ -882,15 +943,15 @@ fn transfer_ostree_boot_to_usr(sysroot: &Path) -> Result<()> {
882943
// get path usr/lib/efi/<component>/<evr>
883944
let efilib_path = Path::new(EFILIB).join(component).join(evr);
884945

885-
let sysroot_dir = openat::Dir::open(sysroot)?;
946+
let sysroot_dir = openat::Dir::open(sysroot.as_str())?;
886947
// Ensure dest parent directory exists
887948
if let Some(parent) = efilib_path.join(filepath).parent() {
888949
sysroot_dir.ensure_dir_all(parent, 0o755)?;
889950
}
890951

891952
// Source dir is usr/lib/ostree-boot/efi
892953
let src = sysroot_dir
893-
.sub_dir(&ostreeboot_efi)
954+
.sub_dir(ostreeboot_efi.as_str())
894955
.context("Opening ostree-boot dir")?;
895956
// Dest dir is usr/lib/efi/<component>/<evr>
896957
let dest = sysroot_dir

0 commit comments

Comments
 (0)