Skip to content

Commit 3363f2a

Browse files
cfs: Use bootupd for all installs if available
Check if we have a new enough version of bootupd (by checking if the binary provides a `--bootloader` flag). If we have a new enough bootupd, use it to install grub-cc and systemd-boot We do not have this version of bootupd as an rpm package, so this will not break any existing systems. This is mostly for reverse dep testing in bootupd as testing this for bootc requires packaging bootupd, updating grub-cc and systemd-boot rpms to install their respective EFI binaries in the correct place which they don't right now Signed-off-by: Pragyan Poudyal <pragyanpoudyal41999@gmail.com>
1 parent efd83cb commit 3363f2a

4 files changed

Lines changed: 78 additions & 23 deletions

File tree

crates/lib/src/bootc_composefs/boot.rs

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ use serde::{Deserialize, Serialize};
9898
use crate::bootc_composefs::state::{get_booted_bls, write_composefs_state};
9999
use crate::bootc_composefs::status::ComposefsCmdline;
100100
use crate::bootc_kargs::compute_new_kargs;
101+
use crate::bootloader::bootupd_supports_bootloader_flag;
101102
use crate::composefs_consts::{TYPE1_BOOT_DIR_PREFIX, TYPE1_ENT_PATH, TYPE1_ENT_PATH_STAGED};
102103
use crate::parsers::bls_config::{BLSConfig, BLSConfigType, EFIKey};
103104
use crate::spec::BootloaderKind;
@@ -1455,32 +1456,44 @@ pub(crate) async fn setup_composefs_boot(
14551456
.or(root_setup.rootfs_uuid.as_deref())
14561457
.ok_or_else(|| anyhow!("No uuid for boot/root"))?;
14571458

1459+
let bootupd_chroot_target = Utf8Path::from_path(mounted_root.root_path())
1460+
.ok_or_else(|| anyhow!("composefs tmpdir path is not valid UTF-8"))?;
1461+
1462+
// Like the ostree backend, bind the physical root's real /boot (an
1463+
// ordinary ext4/xfs/... directory, not yet populated with kernels at
1464+
// this point) into the chroot. This gives bootupd both a correct
1465+
// filesystem to inspect for `--write-uuid` (rather than the ESP,
1466+
// which is otherwise mounted at the composefs root's own /boot) and
1467+
// an empty `boot/efi` directory for its EFI component to discover
1468+
// and mount the real ESP into, exactly as it would on ostree.
1469+
let bind_boot_path = root_setup.physical_root_path.join("boot");
1470+
14581471
if cfg!(target_arch = "s390x") {
14591472
// TODO: Integrate s390x support into install_via_bootupd
14601473
crate::bootloader::install_via_zipl(
14611474
&root_setup.device_info.require_single_root()?,
14621475
boot_uuid,
14631476
)?;
1477+
} else if bootupd_supports_bootloader_flag(Some(bootupd_chroot_target))? {
1478+
crate::bootloader::install_via_bootupd(
1479+
&root_setup.device_info,
1480+
&root_setup.physical_root_path,
1481+
&state.config_opts,
1482+
Some(bootupd_chroot_target),
1483+
Some(bind_boot_path.as_path()),
1484+
Some(postfetch.detected_bootloader),
1485+
)?;
14641486
} else if matches!(
14651487
postfetch.detected_bootloader,
14661488
Bootloader::Grub | Bootloader::GrubCC
14671489
) {
1468-
let chroot_target = Utf8Path::from_path(mounted_root.root_path())
1469-
.ok_or_else(|| anyhow!("composefs tmpdir path is not valid UTF-8"))?;
1470-
// Like the ostree backend, bind the physical root's real /boot (an
1471-
// ordinary ext4/xfs/... directory, not yet populated with kernels at
1472-
// this point) into the chroot. This gives bootupd both a correct
1473-
// filesystem to inspect for `--write-uuid` (rather than the ESP,
1474-
// which is otherwise mounted at the composefs root's own /boot) and
1475-
// an empty `boot/efi` directory for its EFI component to discover
1476-
// and mount the real ESP into, exactly as it would on ostree.
1477-
let bind_boot_path = root_setup.physical_root_path.join("boot");
14781490
crate::bootloader::install_via_bootupd(
14791491
&root_setup.device_info,
14801492
&root_setup.physical_root_path,
14811493
&state.config_opts,
1482-
Some(chroot_target),
1494+
Some(bootupd_chroot_target),
14831495
Some(bind_boot_path.as_path()),
1496+
None,
14841497
)?;
14851498

14861499
// FIXME: Remove this hack once we have support in bootupd

crates/lib/src/bootloader.rs

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use fn_error_context::context;
1212
use bootc_mount as mount;
1313

1414
use crate::bootc_composefs::boot::{MountedImageRoot, SecurebootKeys};
15+
use crate::spec::Bootloader;
1516
use crate::utils;
1617

1718
/// The name of the mountpoint for efi (as a subdirectory of /boot, or at the toplevel)
@@ -95,15 +96,17 @@ pub(crate) fn supports_bootupd(root: &Dir) -> Result<bool> {
9596
Ok(r)
9697
}
9798

98-
/// Check whether the target bootupd supports `--filesystem`.
99-
///
100-
/// Runs `bootupctl backend install --help` and looks for `--filesystem` in the
101-
/// output. When `chroot_target` is set the command runs inside a chroot
102-
/// (via [`ChrootCmd`]) so we probe the binary from the target image.
103-
fn bootupd_supports_filesystem(chroot_target: Option<&Utf8Path>) -> Result<bool> {
99+
fn bootupd_install_help(chroot_target: Option<&Utf8Path>) -> Result<String> {
100+
static STATUS: std::sync::OnceLock<String> = std::sync::OnceLock::new();
101+
102+
if let Some(s) = STATUS.get() {
103+
return Ok(s.clone());
104+
};
105+
104106
let help_args = ["bootupctl", "backend", "install", "--help"];
107+
105108
let output = if let Some(target_root) = chroot_target {
106-
ChrootCmd::new(target_root)
109+
ChrootCmd::new(&target_root)
107110
.set_default_path()
108111
.run_get_string(help_args)?
109112
} else {
@@ -113,6 +116,17 @@ fn bootupd_supports_filesystem(chroot_target: Option<&Utf8Path>) -> Result<bool>
113116
.run_get_string()?
114117
};
115118

119+
Ok(STATUS.get_or_init(|| output).to_string())
120+
}
121+
122+
/// Check whether the target bootupd supports `--filesystem`.
123+
///
124+
/// Runs `bootupctl backend install --help` and looks for `--filesystem` in the
125+
/// output. When `chroot_target` is set the command runs inside a chroot
126+
/// (via [`ChrootCmd`]) so we probe the binary from the target image.
127+
fn bootupd_supports_filesystem(chroot_target: Option<&Utf8Path>) -> Result<bool> {
128+
let output = bootupd_install_help(chroot_target)?;
129+
116130
let use_filesystem = output.contains("--filesystem");
117131

118132
if use_filesystem {
@@ -124,6 +138,23 @@ fn bootupd_supports_filesystem(chroot_target: Option<&Utf8Path>) -> Result<bool>
124138
Ok(use_filesystem)
125139
}
126140

141+
/// Check whether the target bootupd supports `--bootloader` for installs
142+
/// Caches the result of the first call; callers must use the same chroot_target
143+
#[context("Checking if bootupd supports bootloader flag")]
144+
pub(crate) fn bootupd_supports_bootloader_flag(chroot_target: Option<&Utf8Path>) -> Result<bool> {
145+
let output = bootupd_install_help(chroot_target)?;
146+
147+
let supports_bootloader = output.contains("--bootloader");
148+
149+
if supports_bootloader {
150+
tracing::debug!("bootupd supports --bootloader");
151+
} else {
152+
tracing::debug!("bootupd does not support --bootloader");
153+
}
154+
155+
Ok(supports_bootloader)
156+
}
157+
127158
/// Install the bootloader via bootupd.
128159
///
129160
/// When the target bootupd supports `--filesystem` we pass it pointing at a
@@ -151,6 +182,7 @@ pub(crate) fn install_via_bootupd(
151182
configopts: &crate::install::InstallConfigOpts,
152183
chroot_target: Option<&Utf8Path>,
153184
bind_boot_path: Option<&Utf8Path>,
185+
bootloader: Option<Bootloader>,
154186
) -> Result<()> {
155187
let verbose = std::env::var_os("BOOTC_BOOTLOADER_DEBUG").map(|_| "-vvvv");
156188
// bootc defaults to only targeting the platform boot method.
@@ -184,6 +216,11 @@ pub(crate) fn install_via_bootupd(
184216
bootupd_args.extend(opts.iter().copied());
185217
}
186218

219+
if let Some(b) = bootloader {
220+
bootupd_args.push("--bootloader");
221+
bootupd_args.push(b.as_str());
222+
};
223+
187224
// When the target bootupd lacks --filesystem support, fall back to the
188225
// legacy --device flag. For --device we need the whole-disk device path
189226
// (e.g. /dev/vda), not a partition (e.g. /dev/vda3), so resolve the

crates/lib/src/install.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1880,6 +1880,7 @@ async fn install_with_sysroot(
18801880
&state.config_opts,
18811881
Some(chroot_target.as_path()),
18821882
Some(bind_boot_path.as_path()),
1883+
None,
18831884
)?;
18841885
}
18851886
Bootloader::Systemd | Bootloader::GrubCC => {

crates/lib/src/spec.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -255,16 +255,20 @@ pub enum BootloaderKind {
255255
GRUBClassic,
256256
}
257257

258-
impl Display for Bootloader {
259-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
260-
let string = match self {
258+
impl Bootloader {
259+
pub fn as_str(self) -> &'static str {
260+
match self {
261261
Bootloader::Grub => "grub",
262262
Bootloader::GrubCC => "grub-cc",
263263
Bootloader::Systemd => "systemd",
264264
Bootloader::None => "none",
265-
};
265+
}
266+
}
267+
}
266268

267-
write!(f, "{}", string)
269+
impl Display for Bootloader {
270+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
271+
f.write_str(self.as_str())
268272
}
269273
}
270274

0 commit comments

Comments
 (0)