nixos-init: pick the last init= on the kernel cmdline

This matches the behaviour of both the scripted initrd and
the kernel itself.
This commit is contained in:
r-vdp
2026-06-16 11:53:08 +02:00
parent feaf19ea26
commit ef86f4c78e
+29 -12
View File
@@ -87,20 +87,16 @@ pub fn find_init_in_prefix(prefix: &str) -> Result<PathBuf> {
}
/// Extract the value of the `init` parameter from the given kernel `cmdline`.
///
/// If `init=` appears multiple times the last one wins, matching the kernel.
/// This is what makes appending `init=/bin/sh` at the boot prompt work even
/// though the boot entry already has an `init=`.
fn extract_init(cmdline: &str) -> Result<PathBuf> {
let init_params: Vec<&str> = cmdline
let init = cmdline
.split_ascii_whitespace()
.filter(|p| p.starts_with("init="))
.collect();
if init_params.len() != 1 {
bail!("Expected exactly one init param on kernel cmdline: {cmdline}")
}
let init = init_params
.first()
.and_then(|s| s.split('=').next_back())
.context("Failed to extract init path from kernel cmdline: {cmdline}")?;
.filter_map(|p| p.strip_prefix("init="))
.next_back()
.with_context(|| format!("No init= parameter on kernel cmdline: {cmdline}"))?;
Ok(PathBuf::from(init))
}
@@ -129,4 +125,25 @@ mod tests {
Ok(())
}
#[test]
fn test_extract_init_single() {
assert_eq!(
extract_init("root=fstab init=/nix/store/xxx-nixos/init quiet").unwrap(),
PathBuf::from("/nix/store/xxx-nixos/init")
);
}
#[test]
fn test_extract_init_last_wins() {
assert_eq!(
extract_init("init=/nix/store/xxx-nixos/init init=/bin/sh").unwrap(),
PathBuf::from("/bin/sh")
);
}
#[test]
fn test_extract_init_missing() {
assert!(extract_init("root=fstab quiet").is_err());
}
}