diff --git a/src/bootupd.rs b/src/bootupd.rs index 285adfec..2c9ba7c6 100644 --- a/src/bootupd.rs +++ b/src/bootupd.rs @@ -30,6 +30,7 @@ pub(crate) fn install( source_root: &str, dest_root: &str, device: Option<&str>, + with_static_configs: bool, target_components: Option<&[String]>, ) -> Result<()> { // TODO: Change this to an Option<&str>; though this probably balloons into having @@ -62,6 +63,7 @@ pub(crate) fn install( } let mut state = SavedState::default(); + let mut installed_efi = false; for component in target_components { // skip for BIOS if device is empty if component.name() == "BIOS" && device.is_empty() { @@ -77,10 +79,18 @@ pub(crate) fn install( .with_context(|| format!("installing component {}", component.name()))?; log::info!("Installed {} {}", component.name(), meta.meta.version); state.installed.insert(component.name().into(), meta); + if component.name() == "EFI" { + installed_efi = true; + } + } + let sysroot = &openat::Dir::open(dest_root)?; + + if with_static_configs { + crate::grubconfigs::install(sysroot, installed_efi)?; } - let sysroot = openat::Dir::open(dest_root)?; - let mut state_guard = SavedState::unlocked(sysroot).context("failed to acquire write lock")?; + let mut state_guard = + SavedState::unlocked(sysroot.try_clone()?).context("failed to acquire write lock")?; state_guard .update_state(&state) .context("failed to update state")?; diff --git a/src/cli/bootupd.rs b/src/cli/bootupd.rs index 1e5384f7..f7b08678 100644 --- a/src/cli/bootupd.rs +++ b/src/cli/bootupd.rs @@ -52,6 +52,10 @@ pub struct InstallOpts { #[clap(long)] device: Option, + /// Enable installation of the built-in static config files + #[clap(long)] + with_static_configs: bool, + #[clap(long = "component")] /// Only install these components components: Option>, @@ -90,6 +94,7 @@ impl DCommand { &opts.src_root, &opts.dest_root, opts.device.as_deref(), + opts.with_static_configs, opts.components.as_deref(), ) .context("boot data installation failed")?; diff --git a/src/grubconfigs.rs b/src/grubconfigs.rs new file mode 100644 index 00000000..ae15567a --- /dev/null +++ b/src/grubconfigs.rs @@ -0,0 +1,51 @@ +use std::{ + os::unix::prelude::OsStrExt, + path::{Path, PathBuf}, +}; + +use anyhow::{Context, Result}; +use openat_ext::OpenatDirExt; + +const CONFIGDIR: &str = "/usr/lib/bootupd/grub2-static"; + +pub(crate) fn find_efi_vendordir(efidir: &openat::Dir) -> Result { + for d in efidir.list_self()? { + let d = d?; + if d.file_name().as_bytes() == b"BOOT" { + continue; + } + let meta = efidir.metadata(d.file_name())?; + if !meta.is_dir() { + continue; + } + return Ok(d.file_name().into()); + } + anyhow::bail!("Failed to find EFI vendor dir") +} + +/// Install the static GRUB config files. +pub(crate) fn install(target_root: &openat::Dir, efi: bool) -> Result<()> { + let bootdir = &target_root.sub_dir("boot").context("Opening /boot")?; + + bootdir + .copy_file(&Path::new(CONFIGDIR).join("grub-static.cfg"), "grub.cfg") + .context("Copying grub-static.cfg")?; + println!("Installed: grub.cfg"); + + let efidir = efi + .then(|| { + target_root + .sub_dir_optional("boot/efi") + .context("Opening /boot/efi") + }) + .transpose()? + .flatten(); + if let Some(efidir) = efidir.as_ref() { + let vendordir = find_efi_vendordir(efidir)?; + let target = &vendordir.join("grub.cfg"); + efidir.copy_file(&Path::new(CONFIGDIR).join("grub-static-efi.cfg"), target)?; + println!("Installed: {target:?}"); + } + + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index 46d676a8..f29b360e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,6 +23,8 @@ mod coreos; mod daemon; #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] mod efi; +#[cfg(any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "powerpc64"))] +mod grubconfigs; mod filetree; mod ipc; mod model;