Skip to content

Commit 3db2c19

Browse files
yeetypeteJohan-Liebert1
authored andcommitted
sd-boot: Only use --random-seed flag on systemd >= 257
`bootctl install --random-seed no` is only available on systemd >= 257. Query the bootctl version and only pass the flag when supported. Signed-off-by: Peter Siegel <psiegel2000@icloud.com>
1 parent e10e933 commit 3db2c19

1 file changed

Lines changed: 60 additions & 1 deletion

File tree

crates/lib/src/bootloader.rs

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ const SYSTEMD_KEY_DIR: &str = "loader/keys";
3333
/// bootc does not use the entry-token at all.
3434
const KERNEL_INSTALL_CONF_ROOT: &str = "/tmp";
3535

36+
/// First systemd release whose `bootctl install` accepts `--random-seed`.
37+
/// See: <https://www.freedesktop.org/software/systemd/man/latest/bootctl.html>
38+
const BOOTCTL_RANDOM_SEED_MIN_VERSION: u32 = 257;
39+
3640
/// Mount the first ESP found among backing devices at /boot/efi.
3741
///
3842
/// This is used by the install-alongside path to clean stale bootloader
@@ -256,7 +260,16 @@ pub(crate) fn install_systemd_boot(
256260
];
257261

258262
if configopts.generic_image {
259-
bootctl_args.extend(["--random-seed", "no", "--no-variables"]);
263+
bootctl_args.push("--no-variables");
264+
// `--random-seed` was only added to `bootctl install` in systemd 257.
265+
let systemd_version = bootctl_systemd_version()?;
266+
if systemd_version >= BOOTCTL_RANDOM_SEED_MIN_VERSION {
267+
bootctl_args.extend(["--random-seed", "no"]);
268+
} else {
269+
tracing::debug!(
270+
"Skipping --random-seed: requires systemd >= {BOOTCTL_RANDOM_SEED_MIN_VERSION}, found {systemd_version}"
271+
);
272+
}
260273
}
261274

262275
Command::new("bootctl")
@@ -312,6 +325,24 @@ pub(crate) fn install_systemd_boot(
312325
Ok(())
313326
}
314327

328+
#[context("Querying bootctl version")]
329+
fn bootctl_systemd_version() -> Result<u32> {
330+
let out = Command::new("bootctl").arg("--version").run_get_string()?;
331+
parse_systemd_version(&out)
332+
}
333+
334+
/// Parse the systemd major version from `bootctl --version` output, whose first
335+
/// line looks like `systemd 259 (259.5-0ubuntu3)`.
336+
fn parse_systemd_version(output: &str) -> Result<u32> {
337+
output
338+
.split_whitespace()
339+
.nth(1)
340+
.and_then(|s| s.parse::<u32>().ok())
341+
.ok_or_else(|| {
342+
anyhow!("Could not parse systemd version from bootctl --version: {output:?}")
343+
})
344+
}
345+
315346
#[context("Installing bootloader using zipl")]
316347
pub(crate) fn install_via_zipl(device: &bootc_blockdev::Device, boot_uuid: &str) -> Result<()> {
317348
// Identify the target boot partition from UUID
@@ -389,3 +420,31 @@ pub(crate) fn install_via_zipl(device: &bootc_blockdev::Device, boot_uuid: &str)
389420
.log_debug()
390421
.run_inherited_with_cmd_context()
391422
}
423+
424+
#[cfg(test)]
425+
mod tests {
426+
use super::*;
427+
428+
#[test]
429+
fn test_parse_systemd_version() {
430+
// The first line of `bootctl --version`. the trailing feature line is ignored.
431+
let cases = [
432+
("systemd 259 (259.5-0ubuntu3)", 259),
433+
("systemd 257 (257-26.el10-g1d19ad5)", 257),
434+
("systemd 255 (255.4-1ubuntu8.16)", 255),
435+
];
436+
for (input, expected) in cases {
437+
assert_eq!(
438+
parse_systemd_version(input).unwrap(),
439+
expected,
440+
"input: {input:?}"
441+
);
442+
}
443+
for bad in ["", "systemd", "not a version string"] {
444+
assert!(
445+
parse_systemd_version(bad).is_err(),
446+
"should reject: {bad:?}"
447+
);
448+
}
449+
}
450+
}

0 commit comments

Comments
 (0)