2023-07-22 13:49:46 -05:00
|
|
|
use std::{
|
|
|
|
array::IntoIter,
|
|
|
|
path::{Path, PathBuf},
|
|
|
|
};
|
2022-11-23 08:26:26 -06:00
|
|
|
|
2023-09-14 09:18:58 -05:00
|
|
|
use anyhow::{bail, Context, Result};
|
|
|
|
use indoc::indoc;
|
2022-12-11 19:09:19 -06:00
|
|
|
|
2023-07-22 12:16:39 -05:00
|
|
|
use crate::architecture::Architecture;
|
2023-07-22 13:49:46 -05:00
|
|
|
use crate::generation::Generation;
|
2022-12-11 19:09:19 -06:00
|
|
|
|
2023-07-08 13:54:42 -05:00
|
|
|
/// Generic ESP paths which can be specific to a bootloader
|
|
|
|
pub trait EspPaths<const N: usize> {
|
|
|
|
/// Build an ESP path structure out of the ESP root directory
|
2023-06-16 09:42:19 -05:00
|
|
|
fn new(esp: impl AsRef<Path>, arch: Architecture) -> Self;
|
2023-09-14 05:38:40 -05:00
|
|
|
|
2022-12-11 19:09:19 -06:00
|
|
|
/// Return the used file paths to store as garbage collection roots.
|
2023-07-08 13:54:42 -05:00
|
|
|
fn iter(&self) -> std::array::IntoIter<&PathBuf, N>;
|
2023-09-14 05:38:40 -05:00
|
|
|
|
2023-07-08 13:54:42 -05:00
|
|
|
/// Returns the path containing NixOS EFI binaries
|
|
|
|
fn nixos_path(&self) -> &Path;
|
2023-09-14 05:38:40 -05:00
|
|
|
|
2023-07-08 13:54:42 -05:00
|
|
|
/// Returns the path containing Linux EFI binaries
|
|
|
|
fn linux_path(&self) -> &Path;
|
2022-11-23 08:26:26 -06:00
|
|
|
}
|
2022-11-25 20:14:21 -06:00
|
|
|
|
2023-01-18 16:52:13 -06:00
|
|
|
/// Paths to the boot files of a specific generation.
|
|
|
|
pub struct EspGenerationPaths {
|
|
|
|
pub kernel: PathBuf,
|
|
|
|
pub initrd: PathBuf,
|
|
|
|
pub lanzaboote_image: PathBuf,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl EspGenerationPaths {
|
2023-07-22 13:49:46 -05:00
|
|
|
pub fn new<const N: usize, P: EspPaths<N>>(
|
|
|
|
esp_paths: &P,
|
|
|
|
generation: &Generation,
|
2023-06-16 09:23:39 -05:00
|
|
|
system: Architecture,
|
2023-07-22 13:49:46 -05:00
|
|
|
) -> Result<Self> {
|
2023-04-14 08:48:29 -05:00
|
|
|
let bootspec = &generation.spec.bootspec.bootspec;
|
2023-04-24 18:53:46 -05:00
|
|
|
let bootspec_system: Architecture = Architecture::from_nixos_system(&bootspec.system)?;
|
|
|
|
|
2023-09-14 09:18:58 -05:00
|
|
|
if system != bootspec_system {
|
|
|
|
bail!(indoc! {r#"
|
|
|
|
The CPU architecture declared in your module differs from the one declared in the
|
|
|
|
bootspec of the current generation.
|
|
|
|
"#})
|
|
|
|
}
|
2023-01-18 16:52:13 -06:00
|
|
|
|
|
|
|
Ok(Self {
|
|
|
|
kernel: esp_paths
|
2023-07-08 13:54:42 -05:00
|
|
|
.nixos_path()
|
2023-01-18 16:52:13 -06:00
|
|
|
.join(nixos_path(&bootspec.kernel, "bzImage")?),
|
2023-07-08 13:54:42 -05:00
|
|
|
initrd: esp_paths.nixos_path().join(nixos_path(
|
2023-01-18 16:52:13 -06:00
|
|
|
bootspec
|
|
|
|
.initrd
|
|
|
|
.as_ref()
|
|
|
|
.context("Lanzaboote does not support missing initrd yet")?,
|
|
|
|
"initrd",
|
|
|
|
)?),
|
2023-07-08 13:54:42 -05:00
|
|
|
lanzaboote_image: esp_paths.linux_path().join(generation_path(generation)),
|
2023-01-18 16:52:13 -06:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-25 20:14:21 -06:00
|
|
|
fn nixos_path(path: impl AsRef<Path>, name: &str) -> Result<PathBuf> {
|
2022-11-26 16:19:08 -06:00
|
|
|
let resolved = path
|
|
|
|
.as_ref()
|
|
|
|
.read_link()
|
|
|
|
.unwrap_or_else(|_| path.as_ref().into());
|
2022-11-25 20:14:21 -06:00
|
|
|
|
2022-12-29 18:40:22 -06:00
|
|
|
let parent_final_component = resolved
|
|
|
|
.parent()
|
|
|
|
.and_then(|x| x.file_name())
|
|
|
|
.and_then(|x| x.to_str())
|
|
|
|
.with_context(|| format!("Failed to extract final component from: {:?}", resolved))?;
|
2022-11-25 20:14:21 -06:00
|
|
|
|
2022-12-29 18:40:22 -06:00
|
|
|
let nixos_filename = format!("{}-{}.efi", parent_final_component, name);
|
2022-11-25 20:14:21 -06:00
|
|
|
|
|
|
|
Ok(PathBuf::from(nixos_filename))
|
|
|
|
}
|
|
|
|
|
2022-12-17 17:31:09 -06:00
|
|
|
fn generation_path(generation: &Generation) -> PathBuf {
|
2023-01-06 16:20:31 -06:00
|
|
|
if let Some(specialisation_name) = generation.is_specialised() {
|
2022-11-27 04:19:02 -06:00
|
|
|
PathBuf::from(format!(
|
|
|
|
"nixos-generation-{}-specialisation-{}.efi",
|
|
|
|
generation, specialisation_name
|
|
|
|
))
|
|
|
|
} else {
|
|
|
|
PathBuf::from(format!("nixos-generation-{}.efi", generation))
|
|
|
|
}
|
2022-11-25 20:14:21 -06:00
|
|
|
}
|
2022-12-29 18:40:22 -06:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn nixos_path_creates_correct_filename_from_nix_store_path() -> Result<()> {
|
|
|
|
let path =
|
|
|
|
Path::new("/nix/store/xqplddjjjy1lhzyzbcv4dza11ccpcfds-initrd-linux-6.1.1/initrd");
|
|
|
|
|
|
|
|
let generated_filename = nixos_path(path, "initrd")?;
|
|
|
|
|
|
|
|
let expected_filename =
|
|
|
|
PathBuf::from("xqplddjjjy1lhzyzbcv4dza11ccpcfds-initrd-linux-6.1.1-initrd.efi");
|
|
|
|
|
|
|
|
assert_eq!(generated_filename, expected_filename);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|