lzbt: abstraction for multiple backends

This generates `lzbt-systemd` binary instead of `lzbt`
which is using a special systemd-specific entrypoint.

This is part of the effort to enable multiple backends.
This commit is contained in:
Raito Bezarius 2023-07-08 20:54:42 +02:00
parent 7ef2b13780
commit efe7b40f5c
16 changed files with 134 additions and 99 deletions

View File

@ -4,8 +4,8 @@ version = "0.3.0"
edition = "2021"
[[bin]]
name = "lzbt"
path = "src/main.rs"
name = "lzbt-systemd"
path = "src/systemd-main.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -1,65 +1,29 @@
use std::array::IntoIter;
use std::path::{Path, PathBuf};
use std::{path::{PathBuf, Path}, array::IntoIter};
use anyhow::{Context, Result};
use crate::generation::Generation;
/// Paths to the boot files that are not specific to a generation.
pub struct EspPaths {
pub esp: PathBuf,
pub efi: PathBuf,
pub nixos: PathBuf,
pub linux: PathBuf,
pub efi_fallback_dir: PathBuf,
pub efi_fallback: PathBuf,
pub systemd: PathBuf,
pub systemd_boot: PathBuf,
pub loader: PathBuf,
pub systemd_boot_loader_config: PathBuf,
}
impl EspPaths {
pub fn new(esp: impl AsRef<Path>) -> Self {
let esp = esp.as_ref();
let efi = esp.join("EFI");
let efi_nixos = efi.join("nixos");
let efi_linux = efi.join("Linux");
let efi_systemd = efi.join("systemd");
let efi_efi_fallback_dir = efi.join("BOOT");
let loader = esp.join("loader");
let systemd_boot_loader_config = loader.join("loader.conf");
Self {
esp: esp.to_path_buf(),
efi,
nixos: efi_nixos,
linux: efi_linux,
efi_fallback_dir: efi_efi_fallback_dir.clone(),
efi_fallback: efi_efi_fallback_dir.join("BOOTX64.EFI"),
systemd: efi_systemd.clone(),
systemd_boot: efi_systemd.join("systemd-bootx64.efi"),
loader,
systemd_boot_loader_config,
}
}
use crate::common::generation::Generation;
/// Generic ESP paths which can be specific to a bootloader
// The const generics is necessary because:
// (a) we cannot return Trait objects in trait definitions, see https://rust-lang.github.io/impl-trait-initiative/explainer/rpit_trait.html
// (b) we cannot return std::slice::Iter<'_, PathBuf> because PathBuf is owned
// (c) we cannot return std::slice::Iter<'_, &PathBuf> because then Item = &&PathBuf
// (d) we cannot return std::slice::Iter<'_, Path> because Path is unsized
// (e) we cannot return std::slice::Iter<'_, &Path> because then Item = &&Path
// (f) we can bring an associated type `BorrowedIterator` and then because we want to return
// borrows, Rust needs a lifetime and the struct cannot hold the borrow so you need to bring a
// PhantomData<'a ()> inside the structure to keep the lifetime, this is needlessly complicated
// when this solution ensures proper monomorphisation at a small complexity cost.
pub trait EspPaths<const N: usize> {
/// Build an ESP path structure out of the ESP root directory
fn new(esp: impl AsRef<Path>) -> Self;
/// Return the used file paths to store as garbage collection roots.
pub fn to_iter(&self) -> IntoIter<&PathBuf, 10> {
[
&self.esp,
&self.efi,
&self.nixos,
&self.linux,
&self.efi_fallback_dir,
&self.efi_fallback,
&self.systemd,
&self.systemd_boot,
&self.loader,
&self.systemd_boot_loader_config,
]
.into_iter()
}
fn iter(&self) -> std::array::IntoIter<&PathBuf, N>;
/// Returns the path containing NixOS EFI binaries
fn nixos_path(&self) -> &Path;
/// Returns the path containing Linux EFI binaries
fn linux_path(&self) -> &Path;
}
/// Paths to the boot files of a specific generation.
@ -70,21 +34,21 @@ pub struct EspGenerationPaths {
}
impl EspGenerationPaths {
pub fn new(esp_paths: &EspPaths, generation: &Generation) -> Result<Self> {
pub fn new<const N: usize, P: EspPaths<N>>(esp_paths: &P, generation: &Generation) -> Result<Self> {
let bootspec = &generation.spec.bootspec.bootspec;
Ok(Self {
kernel: esp_paths
.nixos
.nixos_path()
.join(nixos_path(&bootspec.kernel, "bzImage")?),
initrd: esp_paths.nixos.join(nixos_path(
initrd: esp_paths.nixos_path().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)),
lanzaboote_image: esp_paths.linux_path().join(generation_path(generation)),
})
}

View File

@ -0,0 +1,7 @@
pub mod esp;
pub mod gc;
pub mod generation;
pub mod os_release;
pub mod pe;
pub mod signature;
pub mod utils;

View File

@ -3,7 +3,7 @@ use std::fmt;
use anyhow::{Context, Result};
use crate::generation::Generation;
use crate::common::generation::Generation;
/// An os-release file represented by a BTreeMap.
///

View File

@ -8,8 +8,8 @@ use anyhow::{Context, Result};
use goblin::pe::PE;
use tempfile::TempDir;
use crate::esp::EspGenerationPaths;
use crate::utils::{file_hash, tmpname, SecureTempDirExt};
use crate::common::esp::EspGenerationPaths;
use crate::common::utils::{file_hash, tmpname, SecureTempDirExt};
/// Assemble a lanzaboote image.
#[allow(clippy::too_many_arguments)]

View File

@ -1,18 +0,0 @@
mod cli;
mod esp;
mod gc;
mod generation;
mod install;
mod os_release;
mod pe;
mod signature;
mod systemd;
mod utils;
use clap::Parser;
use cli::Cli;
fn main() {
Cli::parse().call(module_path!())
}

View File

@ -0,0 +1,8 @@
mod systemd;
pub mod common;
use clap::Parser;
fn main() {
systemd::Cli::parse().call(module_path!())
}

View File

@ -3,8 +3,8 @@ use std::path::PathBuf;
use anyhow::{Context, Result};
use clap::{Parser, Subcommand};
use crate::install;
use crate::signature::KeyPair;
use crate::systemd::install;
use crate::common::signature::KeyPair;
/// The default log level.
///

View File

@ -0,0 +1,67 @@
use std::path::{Path, PathBuf};
use crate::common::esp::EspPaths;
/// Paths to the boot files that are not specific to a generation.
/// Systemd variant
pub struct SystemdEspPaths {
pub esp: PathBuf,
pub efi: PathBuf,
pub nixos: PathBuf,
pub linux: PathBuf,
pub efi_fallback_dir: PathBuf,
pub efi_fallback: PathBuf,
pub systemd: PathBuf,
pub systemd_boot: PathBuf,
pub loader: PathBuf,
pub systemd_boot_loader_config: PathBuf,
}
impl EspPaths<10> for SystemdEspPaths {
fn new(esp: impl AsRef<Path>) -> Self {
let esp = esp.as_ref();
let efi = esp.join("EFI");
let efi_nixos = efi.join("nixos");
let efi_linux = efi.join("Linux");
let efi_systemd = efi.join("systemd");
let efi_efi_fallback_dir = efi.join("BOOT");
let loader = esp.join("loader");
let systemd_boot_loader_config = loader.join("loader.conf");
Self {
esp: esp.to_path_buf(),
efi,
nixos: efi_nixos,
linux: efi_linux,
efi_fallback_dir: efi_efi_fallback_dir.clone(),
efi_fallback: efi_efi_fallback_dir.join("BOOTX64.EFI"),
systemd: efi_systemd.clone(),
systemd_boot: efi_systemd.join("systemd-bootx64.efi"),
loader,
systemd_boot_loader_config
}
}
fn nixos_path(&self) -> &Path {
&self.nixos
}
fn linux_path(&self) -> &Path {
&self.linux
}
fn iter(&self) -> std::array::IntoIter<&PathBuf, 10> {
[
&self.esp,
&self.efi,
&self.nixos,
&self.linux,
&self.efi_fallback_dir,
&self.efi_fallback,
&self.systemd,
&self.systemd_boot,
&self.loader,
&self.systemd_boot_loader_config,
].into_iter()
}
}

View File

@ -10,14 +10,15 @@ use anyhow::{anyhow, Context, Result};
use nix::unistd::syncfs;
use tempfile::TempDir;
use crate::esp::{EspGenerationPaths, EspPaths};
use crate::gc::Roots;
use crate::generation::{Generation, GenerationLink};
use crate::os_release::OsRelease;
use crate::pe;
use crate::signature::KeyPair;
use crate::systemd::SystemdVersion;
use crate::utils::{file_hash, SecureTempDirExt};
use crate::common::gc::Roots;
use crate::common::generation::{Generation, GenerationLink};
use crate::common::os_release::OsRelease;
use crate::common::pe;
use crate::common::signature::KeyPair;
use crate::common::esp::{EspGenerationPaths, EspPaths};
use crate::systemd::esp::SystemdEspPaths;
use crate::systemd::version::SystemdVersion;
use crate::common::utils::{file_hash, SecureTempDirExt};
pub struct Installer {
broken_gens: BTreeSet<u64>,
@ -27,7 +28,7 @@ pub struct Installer {
systemd_boot_loader_config: PathBuf,
key_pair: KeyPair,
configuration_limit: usize,
esp_paths: EspPaths,
esp_paths: SystemdEspPaths,
generation_links: Vec<PathBuf>,
}
@ -42,8 +43,8 @@ impl Installer {
generation_links: Vec<PathBuf>,
) -> Self {
let mut gc_roots = Roots::new();
let esp_paths = EspPaths::new(esp);
gc_roots.extend(esp_paths.to_iter());
let esp_paths = SystemdEspPaths::new(esp);
gc_roots.extend(esp_paths.iter());
Self {
broken_gens: BTreeSet::new(),

View File

@ -0,0 +1,6 @@
pub mod version;
mod cli;
mod esp;
mod install;
pub use cli::Cli;

View File

@ -5,8 +5,8 @@ use std::str::FromStr;
use anyhow::{Context, Result};
use crate::os_release::OsRelease;
use crate::pe;
use crate::common::os_release::OsRelease;
use crate::common::pe;
/// A systemd version.
///