Merge pull request #161 from nix-community/safeguard-gc
tool: disable gc in the presence of malformed gens
This commit is contained in:
commit
b1101610f8
|
@ -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",
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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,21 +87,34 @@ impl Installer {
|
||||||
|
|
||||||
self.install_systemd_boot()?;
|
self.install_systemd_boot()?;
|
||||||
|
|
||||||
log::info!("Collecting garbage...");
|
if self.enable_gc {
|
||||||
// Only collect garbage in these two directories. This way, no files that do not belong to
|
log::info!("Collecting garbage...");
|
||||||
// the NixOS installation are deleted. Lanzatool takes full control over the esp/EFI/nixos
|
// Only collect garbage in these two directories. This way, no files that do not belong to
|
||||||
// directory and deletes ALL files that it doesn't know about. Dual- or multiboot setups
|
// the NixOS installation are deleted. Lanzatool takes full control over the esp/EFI/nixos
|
||||||
// that need files in this directory will NOT work.
|
// directory and deletes ALL files that it doesn't know about. Dual- or multiboot setups
|
||||||
self.gc_roots.collect_garbage(&self.esp_paths.nixos)?;
|
// that need files in this directory will NOT work.
|
||||||
// The esp/EFI/Linux directory is assumed to be potentially shared with other distros.
|
self.gc_roots.collect_garbage(&self.esp_paths.nixos)?;
|
||||||
// Thus, only files that start with "nixos-" are garbage collected (i.e. potentially
|
// The esp/EFI/Linux directory is assumed to be potentially shared with other distros.
|
||||||
// deleted).
|
// Thus, only files that start with "nixos-" are garbage collected (i.e. potentially
|
||||||
self.gc_roots
|
// deleted).
|
||||||
.collect_garbage_with_filter(&self.esp_paths.linux, |p| {
|
self.gc_roots
|
||||||
p.file_name()
|
.collect_garbage_with_filter(&self.esp_paths.linux, |p| {
|
||||||
.and_then(|n| n.to_str())
|
p.file_name()
|
||||||
.map_or(false, |n| n.starts_with("nixos-"))
|
.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.");
|
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()
|
||||||
|
|
Loading…
Reference in New Issue