Skip to content

Commit f57f247

Browse files
committed
Add package-mode copy-to-boot functionality
This is part of Fedora BootLoaderUpdatesPhase1: https://fedoraproject.org/wiki/Changes/BootLoaderUpdatesPhase1
1 parent 5e94f83 commit f57f247

File tree

4 files changed

+103
-0
lines changed

4 files changed

+103
-0
lines changed

src/bootupd.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,23 @@ pub(crate) fn client_run_migrate_static_grub_config() -> Result<()> {
683683
Ok(())
684684
}
685685

686+
/// Copy bootloader files from /usr/lib/efi to boot/ESP for package mode installations.
687+
pub(crate) fn copy_to_boot() -> Result<()> {
688+
let all_components = get_components_impl(false);
689+
if all_components.is_empty() {
690+
println!("No components available for this platform.");
691+
return Ok(());
692+
}
693+
694+
for component in all_components.values() {
695+
component.package_mode_copy_to_boot().with_context(|| {
696+
format!("Failed to copy component {} to boot", component.name())
697+
})?;
698+
}
699+
700+
Ok(())
701+
}
702+
686703
/// Writes a stripped GRUB config to `stripped_config_name`, removing lines between
687704
/// `### BEGIN /etc/grub.d/15_ostree ###` and `### END /etc/grub.d/15_ostree ###`.
688705
fn strip_grub_config_file(

src/cli/bootupd.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ pub enum DVerb {
3535
GenerateUpdateMetadata(GenerateOpts),
3636
#[clap(name = "install", about = "Install components")]
3737
Install(InstallOpts),
38+
#[clap(
39+
name = "copy-to-boot",
40+
about = "Copy bootloader files from /usr/lib/efi to boot/ESP (package mode)"
41+
)]
42+
CopyToBoot,
3843
}
3944

4045
#[derive(Debug, Parser)]
@@ -88,6 +93,7 @@ impl DCommand {
8893
match self.cmd {
8994
DVerb::Install(opts) => Self::run_install(opts),
9095
DVerb::GenerateUpdateMetadata(opts) => Self::run_generate_meta(opts),
96+
DVerb::CopyToBoot => Self::run_copy_to_boot(),
9197
}
9298
}
9399

@@ -122,4 +128,9 @@ impl DCommand {
122128
.context("boot data installation failed")?;
123129
Ok(())
124130
}
131+
132+
pub(crate) fn run_copy_to_boot() -> Result<()> {
133+
bootupd::copy_to_boot().context("copying to boot failed")?;
134+
Ok(())
135+
}
125136
}

src/component.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ pub(crate) trait Component {
7979

8080
/// Locating efi vendor dir
8181
fn get_efi_vendor(&self, sysroot: &Path) -> Result<Option<String>>;
82+
83+
/// Package mode copy: Simple copy from /usr/lib/efi to boot/ESP.
84+
fn package_mode_copy_to_boot(&self) -> Result<()> {
85+
Ok(())
86+
}
8287
}
8388

8489
/// Given a component name, create an implementation.

src/efi.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,71 @@ impl Efi {
183183
clear_efi_target(&product_name)?;
184184
create_efi_boot_entry(device, esp_part_num.trim(), &loader, &product_name)
185185
}
186+
187+
/// Package mode copy: Simple copy from /usr/lib/efi to boot/ESP.
188+
fn package_mode_copy_to_boot_impl(&self) -> Result<()> {
189+
let sysroot = Path::new("/");
190+
let sysroot_path = Utf8Path::from_path(sysroot)
191+
.context("Sysroot path is not valid UTF-8")?;
192+
193+
// Find components in /usr/lib/efi
194+
let efi_comps = match get_efi_component_from_usr(sysroot_path, EFILIB)? {
195+
Some(comps) if !comps.is_empty() => comps,
196+
_ => {
197+
log::debug!("No EFI components found in /usr/lib/efi");
198+
return Ok(());
199+
}
200+
};
201+
202+
// Find the ESP
203+
let esp_path = match self.get_mounted_esp(sysroot)? {
204+
Some(path) => path,
205+
None => {
206+
let devices = blockdev::get_devices(sysroot)?;
207+
let esp_devices = blockdev::find_colocated_esps(&devices)?;
208+
let Some(esp_devices) = esp_devices else {
209+
anyhow::bail!("No ESP found");
210+
};
211+
let esp_device = esp_devices
212+
.first()
213+
.context("No ESP devices found")?;
214+
self.ensure_mounted_esp(sysroot, Path::new(esp_device))?
215+
}
216+
};
217+
218+
let esp_dir = openat::Dir::open(&esp_path)
219+
.with_context(|| format!("Opening ESP at {}", esp_path.display()))?;
220+
validate_esp_fstype(&esp_dir)?;
221+
222+
let sysroot_dir = openat::Dir::open(sysroot)
223+
.context("Opening sysroot for reading")?;
224+
225+
// Copy each component
226+
for efi_comp in &efi_comps {
227+
log::info!(
228+
"Copying EFI component {} version {} to ESP",
229+
efi_comp.name,
230+
efi_comp.version
231+
);
232+
233+
let dest_str = esp_path.to_str().context("ESP path contains invalid UTF-8")?;
234+
filetree::copy_dir_with_args(&sysroot_dir, efi_comp.path.as_str(), dest_str, OPTIONS)
235+
.with_context(|| {
236+
format!(
237+
"Failed to copy {} from {} to {}",
238+
efi_comp.name, efi_comp.path, dest_str
239+
)
240+
})?;
241+
}
242+
243+
// Sync filesystem
244+
let efidir = openat::Dir::open(&esp_path.join("EFI"))
245+
.context("Opening EFI directory for sync")?;
246+
fsfreeze_thaw_cycle(efidir.open_file(".")?)?;
247+
248+
log::info!("Successfully copied {} EFI component(s) to ESP", efi_comps.len());
249+
Ok(())
250+
}
186251
}
187252

188253
#[context("Get product name")]
@@ -622,6 +687,11 @@ impl Component for Efi {
622687
anyhow::bail!("Failed to find {SHIM} in the image")
623688
}
624689
}
690+
691+
/// Package mode copy: Simple copy from /usr/lib/efi to boot/ESP.
692+
fn package_mode_copy_to_boot(&self) -> Result<()> {
693+
self.package_mode_copy_to_boot_impl()
694+
}
625695
}
626696

627697
impl Drop for Efi {

0 commit comments

Comments
 (0)