diff --git a/crates/lib/src/bootc_composefs/boot.rs b/crates/lib/src/bootc_composefs/boot.rs index 265fd58c4..513217f04 100644 --- a/crates/lib/src/bootc_composefs/boot.rs +++ b/crates/lib/src/bootc_composefs/boot.rs @@ -129,10 +129,6 @@ pub(crate) const EFI_UUID_FILE: &str = "efiuuid.cfg"; /// The EFI Linux directory pub(crate) const EFI_LINUX: &str = "EFI/Linux"; -/// Timeout for systemd-boot bootloader menu -const SYSTEMD_TIMEOUT: &str = "timeout 5"; -const SYSTEMD_LOADER_CONF_PATH: &str = "loader/loader.conf"; - pub(crate) const INITRD: &str = "initrd"; pub(crate) const VMLINUZ: &str = "vmlinuz"; @@ -1759,13 +1755,6 @@ fn write_systemd_uki_config( )?; } - // Write the timeout for bootloader menu if not exists - if !esp_dir.exists(SYSTEMD_LOADER_CONF_PATH) { - esp_dir - .atomic_write(SYSTEMD_LOADER_CONF_PATH, SYSTEMD_TIMEOUT) - .with_context(|| format!("Writing to {SYSTEMD_LOADER_CONF_PATH}"))?; - } - let esp_dir = esp_dir .reopen_as_ownedfd() .context("Reopening as owned fd")?; diff --git a/crates/lib/src/bootloader.rs b/crates/lib/src/bootloader.rs index 08a208d28..7d9ba16a4 100644 --- a/crates/lib/src/bootloader.rs +++ b/crates/lib/src/bootloader.rs @@ -1,4 +1,5 @@ use std::fs::create_dir_all; +use std::io::Read; use std::process::Command; use std::sync::OnceLock; @@ -262,6 +263,13 @@ pub(crate) fn install_via_bootupd( } } +/// Timeout for systemd-boot bootloader menu +/// +/// If you update this, make sure to update the readonly test +/// 030-test-composefs.nu +const SYSTEMD_TIMEOUT: &str = "timeout 5"; +const SYSTEMD_LOADER_CONF_PATH: &str = "loader/loader.conf"; + /// Install systemd-boot using a pre-prepared boot root. #[context("Installing bootloader")] pub(crate) fn install_systemd_boot( @@ -298,6 +306,13 @@ pub(crate) fn install_systemd_boot( "Skipping --random-seed: requires systemd >= {BOOTCTL_RANDOM_SEED_MIN_VERSION}, found {systemd_version}" ); } + } else { + // Update firmware variables if not a generic image + // This corresponds to --update-firmware CLI option for bootupd installs + // This option was added in systemd v258 + if systemd_version()? >= 258 { + bootctl_args.push("--variables=yes"); + } } Command::new("bootctl") @@ -358,6 +373,45 @@ pub(crate) fn install_systemd_boot( } } + let esp_dir = prepared_root.open_esp_dir()?; + + // systemd-boot creates a loader.conf files with all lines + // commented out + match esp_dir + .open_optional(SYSTEMD_LOADER_CONF_PATH) + .context("Opening systemd-boot loader config")? + { + // Update timeout in the loader config file + // We can't use bootctl set-timeout as that updates EFI variables + Some(mut f) => { + let mut s = String::new(); + f.read_to_string(&mut s) + .context("Reading systemd-boot loader config")?; + + let mut new_contents = vec![SYSTEMD_TIMEOUT]; + + for line in s.lines() { + // We only want to replace the timeout + if line.contains("timeout") { + continue; + } + + new_contents.push(line); + } + + esp_dir + .atomic_write(SYSTEMD_LOADER_CONF_PATH, new_contents.join("\n")) + .with_context(|| format!("Writing to {SYSTEMD_LOADER_CONF_PATH}"))?; + } + + // Write the timeout for bootloader menu as it doesn't exist + None => { + esp_dir + .atomic_write(SYSTEMD_LOADER_CONF_PATH, SYSTEMD_TIMEOUT) + .with_context(|| format!("Writing to {SYSTEMD_LOADER_CONF_PATH}"))?; + } + } + Ok(()) } diff --git a/tmt/tests/booted/readonly/030-test-composefs.nu b/tmt/tests/booted/readonly/030-test-composefs.nu index 801c5a7ee..7423f78dc 100644 --- a/tmt/tests/booted/readonly/030-test-composefs.nu +++ b/tmt/tests/booted/readonly/030-test-composefs.nu @@ -31,6 +31,13 @@ if $expecting_composefs { if ($bootctl_output | str contains 'Product: systemd-boot') { find_root_eq_in_cmdline "systemd-boot" + + # Make sure our "timeout 5" is actually present + + mkdir /var/tmp/efi + mount /dev/disk/by-partlabel/EFI-SYSTEM /var/tmp/efi + + assert (open /var/tmp/efi/loader/loader.conf | lines | any {|s| $s == "timeout 5" }) } } diff --git a/tmt/tests/booted/test-install-composefs-native.nu b/tmt/tests/booted/test-install-composefs-native.nu index 1a96ef8c5..00b4774dd 100644 --- a/tmt/tests/booted/test-install-composefs-native.nu +++ b/tmt/tests/booted/test-install-composefs-native.nu @@ -62,7 +62,7 @@ def install [image: string, ...args: string] { let dropin = glob $"($MNT)/state/deploy/*/etc/tmpfiles.d/bootc-root-ssh.conf" | append (glob $"($MNT)/ostree/deploy/*/deploy/*/etc/tmpfiles.d/bootc-root-ssh.conf") | each {|p| {content: (open --raw $p | decode utf-8), mode: (stat -c %a $p | str trim)}} - umount $MNT + umount -l $MNT rm -f $DISK assert equal $dropin [{content: $"f~ /var/roothome/.ssh/authorized_keys 600 root root - ($KEY | encode base64)\n", mode: "644"}] "root ssh drop-in" match [$composefs $ostree] { diff --git a/tmt/tests/booted/test-multi-device-esp.nu b/tmt/tests/booted/test-multi-device-esp.nu index acf5bff4f..91c2ba034 100644 --- a/tmt/tests/booted/test-multi-device-esp.nu +++ b/tmt/tests/booted/test-multi-device-esp.nu @@ -37,7 +37,7 @@ const ROOT_TYPE = "4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709" # Cleanup function for LVM and loop devices def cleanup [vg_name: string, loops: list, mountpoint: string] { # Unmount if mounted - do { umount $mountpoint } | complete | ignore + do { umount -l $mountpoint } | complete | ignore do { rmdir $mountpoint } | complete | ignore # Deactivate and remove LVM @@ -126,7 +126,7 @@ def setup_disk_with_root [ # Simple cleanup for non-LVM scenarios (single loop device, no VG) def cleanup_simple [loop: string, mountpoint: string] { - do { umount $mountpoint } | complete | ignore + do { umount -l $mountpoint } | complete | ignore do { rmdir $mountpoint } | complete | ignore if ($loop | path exists) { @@ -143,14 +143,14 @@ def validate_esp [esp_partition: string] { # Check for EFI directory with bootloader files let efi_dir = $"($esp_mount)/EFI" if not ($efi_dir | path exists) { - umount $esp_mount + umount -l $esp_mount rmdir $esp_mount error make {msg: $"ESP validation failed: EFI directory not found on ($esp_partition)"} } # Verify there's actual content in EFI (not just empty) let efi_contents = (ls $efi_dir | length) - umount $esp_mount + umount -l $esp_mount rmdir $esp_mount if $efi_contents == 0 { @@ -164,7 +164,7 @@ def with_esp [esp_partition: string, f: closure] { mkdir $esp_mount mount $esp_partition $esp_mount let r = (do $f $esp_mount) - umount $esp_mount + umount -l $esp_mount rmdir $esp_mount $r }