tool: split esp paths

To access paths on the ESP before or after installing generations, split
EspPaths into general EspPaths that only depend on the path to the ESP
and EspGenerationPaths which additionally depend on generation specific
information (e.g. version number and initrd filename).
This commit is contained in:
nikstur 2023-01-18 23:52:13 +01:00
parent 6e452b50df
commit db75203e31
2 changed files with 61 additions and 40 deletions

View File

@ -5,14 +5,12 @@ use anyhow::{Context, Result};
use crate::generation::Generation; use crate::generation::Generation;
/// Paths to the boot files that are not specific to a generation.
pub struct EspPaths { pub struct EspPaths {
pub esp: PathBuf, pub esp: PathBuf,
pub efi: PathBuf, pub efi: PathBuf,
pub nixos: PathBuf, pub nixos: PathBuf,
pub kernel: PathBuf,
pub initrd: PathBuf,
pub linux: PathBuf, pub linux: PathBuf,
pub lanzaboote_image: PathBuf,
pub efi_fallback_dir: PathBuf, pub efi_fallback_dir: PathBuf,
pub efi_fallback: PathBuf, pub efi_fallback: PathBuf,
pub systemd: PathBuf, pub systemd: PathBuf,
@ -20,7 +18,7 @@ pub struct EspPaths {
} }
impl EspPaths { impl EspPaths {
pub fn new(esp: impl AsRef<Path>, generation: &Generation) -> Result<Self> { pub fn new(esp: impl AsRef<Path>) -> Self {
let esp = esp.as_ref(); let esp = esp.as_ref();
let efi = esp.join("EFI"); let efi = esp.join("EFI");
let efi_nixos = efi.join("nixos"); let efi_nixos = efi.join("nixos");
@ -28,39 +26,25 @@ impl EspPaths {
let efi_systemd = efi.join("systemd"); let efi_systemd = efi.join("systemd");
let efi_efi_fallback_dir = efi.join("BOOT"); let efi_efi_fallback_dir = efi.join("BOOT");
let bootspec = &generation.spec.bootspec; Self {
Ok(Self {
esp: esp.to_path_buf(), esp: esp.to_path_buf(),
efi, efi,
nixos: efi_nixos.clone(), nixos: efi_nixos,
kernel: efi_nixos.join(nixos_path(&bootspec.kernel, "bzImage")?), linux: efi_linux,
initrd: efi_nixos.join(nixos_path(
bootspec
.initrd
.as_ref()
.context("Lanzaboote does not support missing initrd yet")?,
"initrd",
)?),
linux: efi_linux.clone(),
lanzaboote_image: efi_linux.join(generation_path(generation)),
efi_fallback_dir: efi_efi_fallback_dir.clone(), efi_fallback_dir: efi_efi_fallback_dir.clone(),
efi_fallback: efi_efi_fallback_dir.join("BOOTX64.EFI"), efi_fallback: efi_efi_fallback_dir.join("BOOTX64.EFI"),
systemd: efi_systemd.clone(), systemd: efi_systemd.clone(),
systemd_boot: efi_systemd.join("systemd-bootx64.efi"), systemd_boot: efi_systemd.join("systemd-bootx64.efi"),
}) }
} }
/// Return the used file paths to store as garbage collection roots. /// Return the used file paths to store as garbage collection roots.
pub fn to_iter(&self) -> IntoIter<&PathBuf, 11> { pub fn to_iter(&self) -> IntoIter<&PathBuf, 8> {
[ [
&self.esp, &self.esp,
&self.efi, &self.efi,
&self.nixos, &self.nixos,
&self.kernel,
&self.initrd,
&self.linux, &self.linux,
&self.lanzaboote_image,
&self.efi_fallback_dir, &self.efi_fallback_dir,
&self.efi_fallback, &self.efi_fallback,
&self.systemd, &self.systemd,
@ -70,6 +54,38 @@ impl EspPaths {
} }
} }
/// Paths to the boot files of a specific generation.
pub struct EspGenerationPaths {
pub kernel: PathBuf,
pub initrd: PathBuf,
pub lanzaboote_image: PathBuf,
}
impl EspGenerationPaths {
pub fn new(esp_paths: &EspPaths, generation: &Generation) -> Result<Self> {
let bootspec = &generation.spec.bootspec;
Ok(Self {
kernel: esp_paths
.nixos
.join(nixos_path(&bootspec.kernel, "bzImage")?),
initrd: esp_paths.nixos.join(nixos_path(
bootspec
.initrd
.as_ref()
.context("Lanzaboote does not support missing initrd yet")?,
"initrd",
)?),
lanzaboote_image: esp_paths.linux.join(generation_path(generation)),
})
}
/// Return the used file paths to store as garbage collection roots.
pub fn to_iter(&self) -> IntoIter<&PathBuf, 3> {
[&self.kernel, &self.initrd, &self.lanzaboote_image].into_iter()
}
}
fn nixos_path(path: impl AsRef<Path>, name: &str) -> Result<PathBuf> { fn nixos_path(path: impl AsRef<Path>, name: &str) -> Result<PathBuf> {
let resolved = path let resolved = path
.as_ref() .as_ref()

View File

@ -6,7 +6,7 @@ use std::process::Command;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use nix::unistd::sync; use nix::unistd::sync;
use crate::esp::EspPaths; use crate::esp::{EspGenerationPaths, EspPaths};
use crate::gc::Roots; use crate::gc::Roots;
use crate::generation::{Generation, GenerationLink}; use crate::generation::{Generation, GenerationLink};
use crate::os_release::OsRelease; use crate::os_release::OsRelease;
@ -19,7 +19,7 @@ pub struct Installer {
lanzaboote_stub: PathBuf, lanzaboote_stub: PathBuf,
key_pair: KeyPair, key_pair: KeyPair,
configuration_limit: usize, configuration_limit: usize,
esp: PathBuf, esp_paths: EspPaths,
generation_links: Vec<PathBuf>, generation_links: Vec<PathBuf>,
} }
@ -31,12 +31,16 @@ impl Installer {
esp: PathBuf, esp: PathBuf,
generation_links: Vec<PathBuf>, generation_links: Vec<PathBuf>,
) -> Self { ) -> Self {
let mut gc_roots = Roots::new();
let esp_paths = EspPaths::new(esp);
gc_roots.extend(esp_paths.to_iter());
Self { Self {
gc_roots: Roots::new(), gc_roots,
lanzaboote_stub, lanzaboote_stub,
key_pair, key_pair,
configuration_limit, configuration_limit,
esp, esp_paths,
generation_links, generation_links,
} }
} }
@ -66,12 +70,12 @@ impl Installer {
// the NixOS installation are deleted. Lanzatool takes full control over the esp/EFI/nixos // the NixOS installation are deleted. Lanzatool takes full control over the esp/EFI/nixos
// directory and deletes ALL files that it doesn't know about. Dual- or multiboot setups // directory and deletes ALL files that it doesn't know about. Dual- or multiboot setups
// that need files in this directory will NOT work. // that need files in this directory will NOT work.
self.gc_roots.collect_garbage(self.esp.join("EFI/nixos"))?; self.gc_roots.collect_garbage(&self.esp_paths.nixos)?;
// The esp/EFI/Linux directory is assumed to be potentially shared with other distros. // The esp/EFI/Linux directory is assumed to be potentially shared with other distros.
// Thus, only files that start with "nixos-" are garbage collected (i.e. potentially // Thus, only files that start with "nixos-" are garbage collected (i.e. potentially
// deleted). // deleted).
self.gc_roots self.gc_roots
.collect_garbage_with_filter(self.esp.join("EFI/Linux"), |p| { .collect_garbage_with_filter(&self.esp_paths.linux, |p| {
p.file_name() p.file_name()
.and_then(|n| n.to_str()) .and_then(|n| n.to_str())
.map_or(false, |n| n.starts_with("nixos-")) .map_or(false, |n| n.starts_with("nixos-"))
@ -115,8 +119,8 @@ impl Installer {
fn install_generation(&mut self, generation: &Generation) -> Result<()> { fn install_generation(&mut self, generation: &Generation) -> Result<()> {
let bootspec = &generation.spec.bootspec; let bootspec = &generation.spec.bootspec;
let esp_paths = EspPaths::new(&self.esp, generation)?; let esp_gen_paths = EspGenerationPaths::new(&self.esp_paths, generation)?;
self.gc_roots.extend(esp_paths.to_iter()); self.gc_roots.extend(esp_gen_paths.to_iter());
let kernel_cmdline = let kernel_cmdline =
assemble_kernel_cmdline(&bootspec.init, bootspec.kernel_params.clone()); assemble_kernel_cmdline(&bootspec.init, bootspec.kernel_params.clone());
@ -150,9 +154,9 @@ impl Installer {
.join("systemd/lib/systemd/boot/efi/systemd-bootx64.efi"); .join("systemd/lib/systemd/boot/efi/systemd-bootx64.efi");
[ [
(&systemd_boot, &esp_paths.efi_fallback), (&systemd_boot, &self.esp_paths.efi_fallback),
(&systemd_boot, &esp_paths.systemd_boot), (&systemd_boot, &self.esp_paths.systemd_boot),
(&bootspec.kernel, &esp_paths.kernel), (&bootspec.kernel, &esp_gen_paths.kernel),
] ]
.into_iter() .into_iter()
.try_for_each(|(from, to)| install_signed(&self.key_pair, from, to))?; .try_for_each(|(from, to)| install_signed(&self.key_pair, from, to))?;
@ -160,23 +164,24 @@ impl Installer {
// The initrd doesn't need to be signed. Lanzaboote has its // The initrd doesn't need to be signed. Lanzaboote has its
// hash embedded and will refuse loading it when the hash // hash embedded and will refuse loading it when the hash
// mismatches. // mismatches.
install(&initrd_location, &esp_paths.initrd).context("Failed to install initrd to ESP")?; install(&initrd_location, &esp_gen_paths.initrd)
.context("Failed to install initrd to ESP")?;
let lanzaboote_image = pe::lanzaboote_image( let lanzaboote_image = pe::lanzaboote_image(
&tempdir, &tempdir,
&self.lanzaboote_stub, &self.lanzaboote_stub,
&os_release_path, &os_release_path,
&kernel_cmdline, &kernel_cmdline,
&esp_paths.kernel, &esp_gen_paths.kernel,
&esp_paths.initrd, &esp_gen_paths.initrd,
&esp_paths.esp, &self.esp_paths.esp,
) )
.context("Failed to assemble stub")?; .context("Failed to assemble stub")?;
install_signed( install_signed(
&self.key_pair, &self.key_pair,
&lanzaboote_image, &lanzaboote_image,
&esp_paths.lanzaboote_image, &esp_gen_paths.lanzaboote_image,
) )
.context("Failed to install lanzaboote")?; .context("Failed to install lanzaboote")?;
@ -187,7 +192,7 @@ impl Installer {
println!( println!(
"Successfully installed lanzaboote to '{}'", "Successfully installed lanzaboote to '{}'",
esp_paths.esp.display() self.esp_paths.esp.display()
); );
Ok(()) Ok(())