diff --git a/rust/tool/Cargo.toml b/rust/tool/Cargo.toml index 25f1b28..0dc2770 100644 --- a/rust/tool/Cargo.toml +++ b/rust/tool/Cargo.toml @@ -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 diff --git a/rust/tool/src/esp.rs b/rust/tool/src/common/esp.rs similarity index 54% rename from rust/tool/src/esp.rs rename to rust/tool/src/common/esp.rs index 440c280..8fce09b 100644 --- a/rust/tool/src/esp.rs +++ b/rust/tool/src/common/esp.rs @@ -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) -> 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 { + /// Build an ESP path structure out of the ESP root directory + fn new(esp: impl AsRef) -> 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 { + pub fn new>(esp_paths: &P, generation: &Generation) -> Result { 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)), }) } diff --git a/rust/tool/src/gc.rs b/rust/tool/src/common/gc.rs similarity index 100% rename from rust/tool/src/gc.rs rename to rust/tool/src/common/gc.rs diff --git a/rust/tool/src/generation.rs b/rust/tool/src/common/generation.rs similarity index 100% rename from rust/tool/src/generation.rs rename to rust/tool/src/common/generation.rs diff --git a/rust/tool/src/common/mod.rs b/rust/tool/src/common/mod.rs new file mode 100644 index 0000000..eb3c899 --- /dev/null +++ b/rust/tool/src/common/mod.rs @@ -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; diff --git a/rust/tool/src/os_release.rs b/rust/tool/src/common/os_release.rs similarity index 99% rename from rust/tool/src/os_release.rs rename to rust/tool/src/common/os_release.rs index 42e75c1..961a767 100644 --- a/rust/tool/src/os_release.rs +++ b/rust/tool/src/common/os_release.rs @@ -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. /// diff --git a/rust/tool/src/pe.rs b/rust/tool/src/common/pe.rs similarity index 98% rename from rust/tool/src/pe.rs rename to rust/tool/src/common/pe.rs index 2a8ebb2..cf51803 100644 --- a/rust/tool/src/pe.rs +++ b/rust/tool/src/common/pe.rs @@ -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)] diff --git a/rust/tool/src/signature.rs b/rust/tool/src/common/signature.rs similarity index 100% rename from rust/tool/src/signature.rs rename to rust/tool/src/common/signature.rs diff --git a/rust/tool/src/utils.rs b/rust/tool/src/common/utils.rs similarity index 100% rename from rust/tool/src/utils.rs rename to rust/tool/src/common/utils.rs diff --git a/rust/tool/src/main.rs b/rust/tool/src/main.rs deleted file mode 100644 index acf91b4..0000000 --- a/rust/tool/src/main.rs +++ /dev/null @@ -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!()) -} diff --git a/rust/tool/src/systemd-main.rs b/rust/tool/src/systemd-main.rs new file mode 100644 index 0000000..ea90535 --- /dev/null +++ b/rust/tool/src/systemd-main.rs @@ -0,0 +1,8 @@ +mod systemd; +pub mod common; + +use clap::Parser; + +fn main() { + systemd::Cli::parse().call(module_path!()) +} diff --git a/rust/tool/src/cli.rs b/rust/tool/src/systemd/cli.rs similarity index 97% rename from rust/tool/src/cli.rs rename to rust/tool/src/systemd/cli.rs index 9ad6091..dfb835c 100644 --- a/rust/tool/src/cli.rs +++ b/rust/tool/src/systemd/cli.rs @@ -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. /// diff --git a/rust/tool/src/systemd/esp.rs b/rust/tool/src/systemd/esp.rs new file mode 100644 index 0000000..c95e221 --- /dev/null +++ b/rust/tool/src/systemd/esp.rs @@ -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) -> 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() + } +} diff --git a/rust/tool/src/install.rs b/rust/tool/src/systemd/install.rs similarity index 97% rename from rust/tool/src/install.rs rename to rust/tool/src/systemd/install.rs index c860dc9..748b92d 100644 --- a/rust/tool/src/install.rs +++ b/rust/tool/src/systemd/install.rs @@ -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, @@ -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, } @@ -42,8 +43,8 @@ impl Installer { generation_links: Vec, ) -> 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(), diff --git a/rust/tool/src/systemd/mod.rs b/rust/tool/src/systemd/mod.rs new file mode 100644 index 0000000..d6573bc --- /dev/null +++ b/rust/tool/src/systemd/mod.rs @@ -0,0 +1,6 @@ +pub mod version; +mod cli; +mod esp; +mod install; + +pub use cli::Cli; diff --git a/rust/tool/src/systemd.rs b/rust/tool/src/systemd/version.rs similarity index 97% rename from rust/tool/src/systemd.rs rename to rust/tool/src/systemd/version.rs index 24a29eb..4495a35 100644 --- a/rust/tool/src/systemd.rs +++ b/rust/tool/src/systemd/version.rs @@ -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. ///