Skip to content

Commit 3c4026b

Browse files
committed
feat(efi::install)install from extend-payload-path
Added additional flow in efi::install to read from the path created by extend_payload_to_esp command and install to /boot/efi
1 parent 4b4f9f3 commit 3c4026b

File tree

4 files changed

+103
-32
lines changed

4 files changed

+103
-32
lines changed

src/bios.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use camino::Utf8PathBuf;
33
use openat_ext::OpenatDirExt;
44
#[cfg(target_arch = "powerpc64")]
55
use std::borrow::Cow;
6+
use std::collections::BTreeMap;
67
use std::io::prelude::*;
78
use std::path::Path;
89
use std::process::Command;
@@ -121,6 +122,7 @@ impl Component for Bios {
121122
meta,
122123
filetree: None,
123124
adopted_from: None,
125+
firmware: BTreeMap::new(),
124126
})
125127
}
126128

@@ -235,6 +237,7 @@ impl Component for Bios {
235237
meta: update.clone(),
236238
filetree: None,
237239
adopted_from: Some(meta.version),
240+
firmware: BTreeMap::new(),
238241
}))
239242
}
240243

@@ -257,6 +260,7 @@ impl Component for Bios {
257260
meta: updatemeta,
258261
filetree: None,
259262
adopted_from,
263+
firmware: BTreeMap::new(),
260264
})
261265
}
262266

src/efi.rs

Lines changed: 89 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
use std::cell::RefCell;
8+
use std::collections::BTreeMap;
89
use std::os::unix::io::AsRawFd;
910
use std::path::{Path, PathBuf};
1011
use std::process::Command;
@@ -328,6 +329,7 @@ impl Component for Efi {
328329
meta: updatemeta.clone(),
329330
filetree: Some(updatef),
330331
adopted_from: Some(meta.version),
332+
firmware: BTreeMap::new(),
331333
}))
332334
}
333335

@@ -372,15 +374,70 @@ impl Component for Efi {
372374
.arg(destpath)
373375
.current_dir(format!("/proc/self/fd/{}", src_root.as_raw_fd()))
374376
.run()?;
377+
378+
let mut found_firmware = BTreeMap::new();
379+
// Scan and install supplemental firmware
380+
let firmware_base_dir_path = Path::new("usr/lib/efi/firmware");
381+
if src_root.exists(firmware_base_dir_path)? {
382+
let firmware_base_dir = src_root.sub_dir(firmware_base_dir_path)?;
383+
for pkg_entry in firmware_base_dir.list_dir(".")?.flatten() {
384+
if firmware_base_dir.get_file_type(&pkg_entry)? != openat::SimpleType::Dir {
385+
continue;
386+
}
387+
let pkg_name = pkg_entry.file_name().to_string_lossy().to_string();
388+
let pkg_dir = firmware_base_dir.sub_dir(pkg_entry.file_name())?;
389+
390+
let mut versions: Vec<_> = pkg_dir.list_dir(".")?.filter_map(Result::ok).collect();
391+
versions.sort_by_key(|e| e.file_name().to_owned());
392+
393+
if let Some(ver_entry) = versions.pop() {
394+
let ver_dir = pkg_dir.sub_dir(ver_entry.file_name())?;
395+
let meta_path = Path::new("EFI.json");
396+
397+
if ver_dir.exists(meta_path)? {
398+
log::debug!(
399+
"Found supplemental firmware: {}/{}",
400+
pkg_name,
401+
ver_entry.file_name().to_string_lossy()
402+
);
403+
let firmware_meta: ContentMetadata =
404+
serde_json::from_reader(ver_dir.open_file(meta_path)?)?;
405+
let payload_src_dir = ver_dir.sub_dir("EFI")?;
406+
let firmware_filetree =
407+
crate::filetree::FileTree::new_from_dir(&payload_src_dir)?;
408+
// copy all by applying a diff with a empty filetree
409+
let empty_filetree = filetree::FileTree {
410+
children: Default::default(),
411+
};
412+
let diff = empty_filetree.diff(&firmware_filetree)?;
413+
filetree::apply_diff(&payload_src_dir, destd, &diff, None)
414+
.context("applying supplemental firmware")?;
415+
416+
found_firmware.insert(
417+
pkg_name.clone(),
418+
Box::new(InstalledContent {
419+
meta: firmware_meta,
420+
filetree: Some(firmware_filetree),
421+
adopted_from: None,
422+
firmware: BTreeMap::new(),
423+
}),
424+
);
425+
}
426+
}
427+
}
428+
}
429+
375430
if update_firmware {
376-
if let Some(vendordir) = self.get_efi_vendor(&src_root)? {
431+
if let Some(vendordir) = self.get_efi_vendor(src_root)? {
377432
self.update_firmware(device, destd, &vendordir)?
378433
}
379434
}
435+
380436
Ok(InstalledContent {
381437
meta,
382438
filetree: Some(ft),
383439
adopted_from: None,
440+
firmware: found_firmware,
384441
})
385442
}
386443

@@ -424,6 +481,7 @@ impl Component for Efi {
424481
meta: updatemeta,
425482
filetree: Some(updatef),
426483
adopted_from,
484+
firmware: BTreeMap::new(),
427485
})
428486
}
429487

@@ -465,72 +523,71 @@ impl Component for Efi {
465523
fn extend_payload(&self, sysroot_path: &str, src_input: &str) -> Result<Option<bool>> {
466524
let dest_efidir_base = Path::new(sysroot_path).join("usr/lib/efi").join("firmware");
467525

468-
// Fetch version and release from the source input using query_files
469526
let src_input_path = Path::new(src_input);
470-
let meta_from_src = packagesystem::query_files(sysroot_path, [src_input_path])
527+
let path_to_query = if src_input_path.is_dir() {
528+
WalkDir::new(src_input_path)
529+
.into_iter()
530+
.filter_map(|e| e.ok())
531+
.find(|e| e.file_type().is_file())
532+
.map(|e| e.path().to_path_buf())
533+
.ok_or_else(|| anyhow!("No file found in directory {}", src_input))?
534+
} else {
535+
src_input_path.to_path_buf()
536+
};
537+
538+
let meta_from_src = packagesystem::query_files(sysroot_path, [path_to_query])
471539
.context(format!("Querying RPM metadata for {:?}", src_input_path))?;
472540

473-
let version_string_part = meta_from_src.version.split( ',').next()
474-
.ok_or_else(|| anyhow!(
475-
"RPM query returned an empty or malformed version string (no package name found in '{}').",
476-
meta_from_src.version
477-
))?;
541+
let version_string_part =
542+
meta_from_src.version.split(',').next().ok_or_else(|| {
543+
anyhow!("RPM query returned an empty or malformed version string")
544+
})?;
478545

479546
let parts: Vec<&str> = version_string_part.split('-').collect();
480-
481547
let (pkg_name, version_release_str) = if parts.len() >= 3 {
482-
// Successfully extracted package name, version, and release
483-
let actual_pkg_name = parts[0];
484-
let version_part = parts[parts.len() - 2]; // version, e.g., "1.0"
485-
let release_part = parts[parts.len() - 1]
486-
.split('.')
487-
.next()
488-
.unwrap_or(parts[parts.len() - 1]); // release, e.g., "1" from "1.el8.noarch"
489548
(
490-
actual_pkg_name.to_string(),
491-
format!("{}-{}", version_part, release_part),
549+
parts[0].to_string(),
550+
format!(
551+
"{}-{}",
552+
parts[parts.len() - 2],
553+
parts[parts.len() - 1]
554+
.split('.')
555+
.next()
556+
.unwrap_or(parts[parts.len() - 1])
557+
),
492558
)
493559
} else {
494560
anyhow::bail!("Unexpected RPM version string format");
495561
};
496562

497563
// Use the flattened destination path
498-
let matadata_path = dest_efidir_base.join(&pkg_name).join(&version_release_str);
499-
std::fs::create_dir_all(&matadata_path)?;
500-
501-
let final_dest_path = matadata_path.join("EFI");
564+
let final_dest_path = dest_efidir_base.join(&pkg_name).join(&version_release_str);
502565
std::fs::create_dir_all(&final_dest_path)?;
503566

504567
// Copy the payload files
505568
let src_metadata = std::fs::metadata(src_input_path)?;
506569
if src_metadata.is_dir() {
507-
log::debug!(
508-
"Copying contents of directory {:?} to {:?}",
509-
src_input,
510-
&final_dest_efi_path
511-
);
512570
Command::new("cp")
513571
.args([
514572
"-rp",
515573
&format!("{}/.", src_input),
516-
final_dest_efi_path.to_str().unwrap(),
574+
final_dest_path.to_str().unwrap(),
517575
])
518576
.run()
519577
.with_context(|| {
520578
format!(
521579
"Failed to copy contents of {:?} to {:?}",
522-
src_input, &final_dest_efi_path
580+
src_input, &final_dest_path
523581
)
524582
})?;
525-
} else if src_metadata.is_file() {
526-
log::debug!("Copying file {:?} to {:?}", src_input, &final_dest_efi_path);
583+
} else {
527584
Command::new("cp")
528585
.args(["-p", src_input, final_dest_path.to_str().unwrap()])
529586
.run()?;
530587
}
531588

532589
// Create the metadata file for the firmware
533-
let firmware_meta_path = matadata_path.join("EFI.json");
590+
let firmware_meta_path = final_dest_path.join("EFI.json");
534591
let meta_file = std::fs::File::create(firmware_meta_path)?;
535592
serde_json::to_writer(meta_file, &meta_from_src)?;
536593
log::debug!("Wrote firmware metadata for {}", pkg_name);

src/model.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ pub(crate) struct InstalledContent {
3939
pub(crate) filetree: Option<crate::filetree::FileTree>,
4040
/// The version this was originally adopted from
4141
pub(crate) adopted_from: Option<ContentMetadata>,
42+
/// Nested map of supplemental firmware payloads.
43+
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
44+
pub(crate) firmware: BTreeMap<String, Box<InstalledContent>>,
4245
}
4346

4447
/// Will be serialized into /boot/bootupd-state.json

src/model_legacy.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ pub(crate) struct InstalledContent01 {
3030
pub(crate) meta: ContentMetadata01,
3131
/// File tree
3232
pub(crate) filetree: Option<crate::filetree::FileTree>,
33+
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
34+
pub(crate) firmware: BTreeMap<String, Box<InstalledContent01>>,
3335
}
3436

3537
/// Will be serialized into /boot/bootupd-state.json
@@ -59,6 +61,11 @@ impl InstalledContent01 {
5961
meta: self.meta.upconvert(),
6062
filetree: self.filetree,
6163
adopted_from: None,
64+
firmware: self
65+
.firmware
66+
.into_iter()
67+
.map(|(k, v)| (k, Box::new(v.upconvert())))
68+
.collect(),
6269
}
6370
}
6471
}

0 commit comments

Comments
 (0)