Skip to content

Commit 3c31f36

Browse files
committed
efi: transfer usr/lib/ostree-boot to usr/lib/efi
1 parent 3dd909e commit 3c31f36

4 files changed

Lines changed: 99 additions & 49 deletions

File tree

src/component.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ pub(crate) fn component_updatedirname(component: &dyn Component) -> PathBuf {
117117
target_arch = "aarch64",
118118
target_arch = "riscv64"
119119
))]
120+
#[allow(dead_code)]
120121
pub(crate) fn component_updatedir(sysroot: &str, component: &dyn Component) -> PathBuf {
121122
Path::new(sysroot).join(component_updatedirname(component))
122123
}

src/efi.rs

Lines changed: 76 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use bootc_internal_utils::CommandRunExt;
1414
use camino::{Utf8Path, Utf8PathBuf};
1515
use cap_std::fs::Dir;
1616
use cap_std_ext::cap_std;
17+
use cap_std_ext::dirext::CapStdExtDirExt;
1718
use chrono::prelude::*;
1819
use fn_error_context::context;
1920
use openat_ext::OpenatDirExt;
@@ -447,20 +448,42 @@ impl Component for Efi {
447448
}
448449

449450
fn generate_update_metadata(&self, sysroot: &str) -> Result<ContentMetadata> {
450-
let sysroot_path = Utf8Path::new(sysroot);
451+
let sysroot_path = Path::new(sysroot);
451452

452-
let efilib_path = sysroot_path.join(EFILIB);
453-
let efi_comps = if efilib_path.exists() {
454-
get_efi_component_from_usr(&sysroot_path, EFILIB)?
455-
} else {
456-
None
457-
};
453+
let sysroot_dir = Dir::open_ambient_dir(sysroot_path, cap_std::ambient_authority())?;
454+
455+
if let Some(ostreeboot) = sysroot_dir
456+
.open_dir_optional(ostreeutil::BOOT_PREFIX)
457+
.context("Opening usr/lib/ostree-boot")?
458+
{
459+
let cruft = ["loader", "grub2"];
460+
for p in cruft.iter() {
461+
ostreeboot.remove_all_optional(p)?;
462+
}
463+
464+
let efisrc = sysroot_path.join(ostreeutil::BOOT_PREFIX).join("efi/EFI");
465+
if efisrc.exists() {
466+
let files = WalkDir::new(&efisrc)
467+
.into_iter()
468+
.filter_map(Result::ok)
469+
.filter(|e| e.file_type().is_file())
470+
.map(|e| e.path().to_path_buf())
471+
.collect::<Vec<_>>();
472+
473+
if !files.is_empty() {
474+
transfter_ostree_boot_to_usr(sysroot_path, &files)?;
475+
}
476+
// Remove usr/lib/ostree-boot/efi/EFI dir (after transfer) or if it is empty
477+
ostreeboot.remove_all_optional("efi/EFI")?;
478+
}
479+
}
458480

459481
// copy EFI files to updates dir from usr/lib/efi
460-
let meta = if let Some(efi_components) = efi_comps {
482+
if let Some(efi_components) =
483+
get_efi_component_from_usr(Utf8Path::from_path(sysroot_path).unwrap(), EFILIB)?
484+
{
461485
let mut packages = Vec::new();
462486
let mut modules_vec: Vec<Module> = vec![];
463-
let sysroot_dir = Dir::open_ambient_dir(sysroot_path, cap_std::ambient_authority())?;
464487
for efi in efi_components {
465488
util::copy_in_fd(&sysroot_dir, &efi.path, crate::model::BOOTUPD_UPDATES_DIR)?;
466489
packages.push(format!("{}-{}", efi.name, efi.version));
@@ -473,50 +496,16 @@ impl Component for Efi {
473496

474497
// change to now to workaround https://github.com/coreos/bootupd/issues/933
475498
let timestamp = std::time::SystemTime::now();
476-
ContentMetadata {
499+
let meta = ContentMetadata {
477500
timestamp: chrono::DateTime::<Utc>::from(timestamp),
478501
version: packages.join(","),
479502
versions: Some(modules_vec),
480-
}
503+
};
504+
write_update_metadata(sysroot, self, &meta)?;
505+
Ok(meta)
481506
} else {
482-
let ostreebootdir = sysroot_path.join(ostreeutil::BOOT_PREFIX);
483-
484-
// move EFI files to updates dir from /usr/lib/ostree-boot
485-
if ostreebootdir.exists() {
486-
let cruft = ["loader", "grub2"];
487-
for p in cruft.iter() {
488-
let p = ostreebootdir.join(p);
489-
if p.exists() {
490-
std::fs::remove_dir_all(&p)?;
491-
}
492-
}
493-
494-
let efisrc = ostreebootdir.join("efi/EFI");
495-
if !efisrc.exists() {
496-
bail!("Failed to find {:?}", &efisrc);
497-
}
498-
499-
let dest_efidir = component_updatedir(sysroot, self);
500-
let dest_efidir =
501-
Utf8PathBuf::from_path_buf(dest_efidir).expect("Path is invalid UTF-8");
502-
// Fork off mv() because on overlayfs one can't rename() a lower level
503-
// directory today, and this will handle the copy fallback.
504-
Command::new("mv").args([&efisrc, &dest_efidir]).run()?;
505-
506-
let efidir = openat::Dir::open(dest_efidir.as_std_path())
507-
.with_context(|| format!("Opening {}", dest_efidir))?;
508-
let files = crate::util::filenames(&efidir)?.into_iter().map(|mut f| {
509-
f.insert_str(0, "/boot/efi/EFI/");
510-
f
511-
});
512-
query_files(sysroot, files)?
513-
} else {
514-
anyhow::bail!("Failed to find {ostreebootdir}");
515-
}
516-
};
517-
518-
write_update_metadata(sysroot, self, &meta)?;
519-
Ok(meta)
507+
anyhow::bail!("Failed to find EFI components");
508+
}
520509
}
521510

522511
fn query_update(&self, sysroot: &openat::Dir) -> Result<Option<ContentMetadata>> {
@@ -766,6 +755,44 @@ fn get_efi_component_from_usr<'a>(
766755
Ok(Some(components))
767756
}
768757

758+
fn transfter_ostree_boot_to_usr(sysroot: &Path, ostreeboot_files: &Vec<PathBuf>) -> Result<()> {
759+
let ostreeboot = sysroot.join(ostreeutil::BOOT_PREFIX).join("efi");
760+
for entry in ostreeboot_files {
761+
// get path: EFI/{BOOT,<vendor>}/<file>
762+
let filepath = entry.strip_prefix(&ostreeboot)?;
763+
// get path: /boot/efi/EFI/{BOOT,<vendor>}/<file>
764+
let boot_filepath = Path::new("/boot/efi").join(filepath);
765+
766+
// Run `rpm -qf <filepath>`
767+
let pkg = crate::packagesystem::query_file(
768+
sysroot.to_str().unwrap(),
769+
boot_filepath.to_str().unwrap(),
770+
)?;
771+
772+
if let Some((name, evr)) = pkg.split_once('/') {
773+
let component = name.splitn(2, '-').next().unwrap_or("");
774+
let version = evr.strip_prefix("(none):").unwrap_or(evr);
775+
let dest = Path::new(EFILIB)
776+
.join(component)
777+
.join(version)
778+
.join(filepath);
779+
780+
let sysroot_dir = openat::Dir::open(sysroot)?;
781+
// Ensure parent directory exists
782+
if let Some(parent) = sysroot.join(&dest).parent() {
783+
sysroot_dir.ensure_dir_all(parent, 0o755)?;
784+
}
785+
let src = entry.strip_prefix(sysroot)?;
786+
sysroot_dir.copy_file(src, &dest)?;
787+
788+
println!("Copied {:?} -> {:?}", src, dest);
789+
} else {
790+
bail!("Could not find split charater in {pkg}");
791+
}
792+
}
793+
Ok(())
794+
}
795+
769796
#[cfg(test)]
770797
mod tests {
771798
use cap_std_ext::dirext::CapStdExtDirExt;

src/packagesystem.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,27 @@ where
101101
rpm_parse_metadata(&rpmout.stdout)
102102
}
103103

104+
/// Query the rpm database and get package <name>/<epoch>:<version>-<release>.
105+
pub(crate) fn query_file(sysroot_path: &str, path: &str) -> Result<String> {
106+
let mut c = ostreeutil::rpm_cmd(sysroot_path)?;
107+
c.args([
108+
"-q",
109+
"--queryformat",
110+
"%{NAME}/%{EPOCH}:%{VERSION}-%{RELEASE}",
111+
"-f",
112+
path,
113+
]);
114+
115+
let rpmout = c.output()?;
116+
if !rpmout.status.success() {
117+
std::io::stderr().write_all(&rpmout.stderr)?;
118+
bail!("Failed to invoke rpm -qf");
119+
}
120+
121+
let output = String::from_utf8(rpmout.stdout)?;
122+
Ok(output.trim().to_string())
123+
}
124+
104125
fn parse_evr(pkg: &str) -> Module {
105126
// assume it is "grub2-1:2.12-28.fc42" (from usr/lib/efi)
106127
if !pkg.ends_with(std::env::consts::ARCH) {

src/util.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub(crate) fn getenv_utf8(n: &str) -> Result<Option<String>> {
2121
}
2222
}
2323

24+
#[allow(dead_code)]
2425
pub(crate) fn filenames(dir: &openat::Dir) -> Result<HashSet<String>> {
2526
let mut ret = HashSet::new();
2627
for entry in dir.list_dir(".")? {

0 commit comments

Comments
 (0)