use std::fs;
use std::path::PathBuf;
use std::process::Command;
use kexec_loader::{KexecRequest, load_dry};
fn integration_enabled() -> bool {
std::env::var("AEGIS_INTEGRATION_ROOT").is_ok()
}
fn find_readable_kernel() -> Option<PathBuf> {
let dir = PathBuf::from("/boot");
let entries = fs::read_dir(&dir).ok()?;
for entry in entries.flatten() {
let name = entry.file_name().to_string_lossy().to_string();
if !name.starts_with("vmlinuz-") {
continue;
}
if !(name.ends_with("-generic") || name.ends_with("-virtual")) {
continue;
}
let path = entry.path();
if fs::read(&path).is_ok() {
return Some(path);
}
}
None
}
fn read_kexec_loaded() -> String {
fs::read_to_string("/sys/kernel/kexec_loaded")
.map(|s| s.trim().to_string())
.unwrap_or_default()
}
#[test]
#[ignore = "needs root + CAP_SYS_BOOT; run with `sudo -E cargo test -p kexec-loader -- --ignored`"]
fn load_dry_flips_kexec_loaded() {
if !integration_enabled() {
eprintln!("skipping: set AEGIS_INTEGRATION_ROOT=1 to opt in");
return;
}
let kernel = find_readable_kernel().unwrap_or_else(|| {
panic!("no readable /boot/vmlinuz-*-{{generic,virtual}} found; can't run dry-run test")
});
eprintln!("using kernel: {}", kernel.display());
if read_kexec_loaded() == "1" {
let _ = Command::new("kexec").arg("-u").status();
}
assert_eq!(
read_kexec_loaded(),
"0",
"precondition: kexec_loaded must be 0 before the test"
);
let req = KexecRequest {
kernel: kernel.clone(),
initrd: None,
cmdline: "quiet".to_string(),
};
load_dry(&req).unwrap_or_else(|e| panic!("load_dry failed: {e}"));
assert_eq!(
read_kexec_loaded(),
"1",
"kexec_file_load should set /sys/kernel/kexec_loaded to 1"
);
let _ = Command::new("kexec").arg("-u").status();
}