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

View File

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

View File

@ -18,6 +18,7 @@ use crate::systemd::SystemdVersion;
use crate::utils::{file_hash, SecureTempDirExt};
pub struct Installer {
enable_gc: bool,
gc_roots: Roots,
lanzaboote_stub: PathBuf,
systemd: PathBuf,
@ -43,6 +44,7 @@ impl Installer {
gc_roots.extend(esp_paths.to_iter());
Self {
enable_gc: true,
gc_roots,
lanzaboote_stub,
systemd,
@ -85,21 +87,34 @@ impl Installer {
self.install_systemd_boot()?;
log::info!("Collecting garbage...");
// 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
// directory and deletes ALL files that it doesn't know about. Dual- or multiboot setups
// that need files in this directory will NOT work.
self.gc_roots.collect_garbage(&self.esp_paths.nixos)?;
// 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
// deleted).
self.gc_roots
.collect_garbage_with_filter(&self.esp_paths.linux, |p| {
p.file_name()
.and_then(|n| n.to_str())
.map_or(false, |n| n.starts_with("nixos-"))
})?;
if self.enable_gc {
log::info!("Collecting garbage...");
// 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
// directory and deletes ALL files that it doesn't know about. Dual- or multiboot setups
// that need files in this directory will NOT work.
self.gc_roots.collect_garbage(&self.esp_paths.nixos)?;
// 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
// deleted).
self.gc_roots
.collect_garbage_with_filter(&self.esp_paths.linux, |p| {
p.file_name()
.and_then(|n| n.to_str())
.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.");
Ok(())
@ -171,15 +186,13 @@ impl Installer {
// Ignore failing to read a generation so that old malformed generations do not stop
// lzbt from working.
if let Err(e) = &generation_result {
// Semantically, this message should be a warning. However, since users might
// have hundreds of old and thus malformed generations and can do little about
// it, this should remain a debug message. This way the user is not spammed
// with no-op warnings while still enabling debugging.
log::debug!(
"Ignoring generation {} because it's malformed: {e:#}",
link.version
);
if generation_result.is_err() {
// If there is ANY malformed generation present, completely disable all garbage
// collection to protect the old generations from being deleted. The user has
// to manually intervene by getting rid of the old generations to re-enable
// garbage collection. This safeguard against catastrophic failure in case of
// unhandled upstream changes to NixOS.
self.enable_gc = false;
}
generation_result.ok()