tool: disable gc in the presence of malformed gens

Disable GC if there are any malformed gens to avoid catastrophic failure
when there are upstream changes to NixOS that are not handled in lzbt.
This commit is contained in:
nikstur 2023-04-24 21:54:14 +02:00
parent 1b27ddd753
commit 09e12eb559
3 changed files with 45 additions and 24 deletions

7
rust/tool/Cargo.lock generated
View File

@ -473,6 +473,12 @@ dependencies = [
"cxx-build", "cxx-build",
] ]
[[package]]
name = "indoc"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f2cb48b81b1dc9f39676bf99f5499babfec7cd8fe14307f7b3d747208fb5690"
[[package]] [[package]]
name = "instant" name = "instant"
version = "0.1.12" version = "0.1.12"
@ -541,6 +547,7 @@ dependencies = [
"fastrand", "fastrand",
"filetime", "filetime",
"goblin", "goblin",
"indoc",
"log", "log",
"nix", "nix",
"rand", "rand",

View File

@ -27,6 +27,7 @@ sha2 = "0.10.6"
fastrand = "1.9.0" fastrand = "1.9.0"
log = { version = "0.4.17", features = ["std"] } log = { version = "0.4.17", features = ["std"] }
stderrlog = "0.5.4" stderrlog = "0.5.4"
indoc = "2.0.1"
[dev-dependencies] [dev-dependencies]
assert_cmd = "2.0.11" assert_cmd = "2.0.11"

View File

@ -18,6 +18,7 @@ use crate::systemd::SystemdVersion;
use crate::utils::{file_hash, SecureTempDirExt}; use crate::utils::{file_hash, SecureTempDirExt};
pub struct Installer { pub struct Installer {
enable_gc: bool,
gc_roots: Roots, gc_roots: Roots,
lanzaboote_stub: PathBuf, lanzaboote_stub: PathBuf,
systemd: PathBuf, systemd: PathBuf,
@ -43,6 +44,7 @@ impl Installer {
gc_roots.extend(esp_paths.to_iter()); gc_roots.extend(esp_paths.to_iter());
Self { Self {
enable_gc: true,
gc_roots, gc_roots,
lanzaboote_stub, lanzaboote_stub,
systemd, systemd,
@ -85,6 +87,7 @@ impl Installer {
self.install_systemd_boot()?; self.install_systemd_boot()?;
if self.enable_gc {
log::info!("Collecting garbage..."); log::info!("Collecting garbage...");
// Only collect garbage in these two directories. This way, no files that do not belong to // Only collect garbage in these two directories. This way, no files that do not belong to
// 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
@ -100,6 +103,18 @@ impl Installer {
.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-"))
})?; })?;
} else {
// Garbage collection can only be disabled if there are malformed generations. If
// garbage collection can ever be disabled differently, the below log message most
// likely does not make sense anymore.
log::warn!(indoc::indoc! {"
Garbage collection is disabled because you have malformed NixOS generations that do
not contain a readable bootspec document.
Remove the malformed generations with `nix-env --delete-generations` to re-enable
garbage collection.
"})
};
log::info!("Successfully installed Lanzaboote."); log::info!("Successfully installed Lanzaboote.");
Ok(()) Ok(())
@ -171,15 +186,13 @@ impl Installer {
// Ignore failing to read a generation so that old malformed generations do not stop // Ignore failing to read a generation so that old malformed generations do not stop
// lzbt from working. // lzbt from working.
if let Err(e) = &generation_result { if generation_result.is_err() {
// Semantically, this message should be a warning. However, since users might // If there is ANY malformed generation present, completely disable all garbage
// have hundreds of old and thus malformed generations and can do little about // collection to protect the old generations from being deleted. The user has
// it, this should remain a debug message. This way the user is not spammed // to manually intervene by getting rid of the old generations to re-enable
// with no-op warnings while still enabling debugging. // garbage collection. This safeguard against catastrophic failure in case of
log::debug!( // unhandled upstream changes to NixOS.
"Ignoring generation {} because it's malformed: {e:#}", self.enable_gc = false;
link.version
);
} }
generation_result.ok() generation_result.ok()