Skip to content

Commit 0b51f0e

Browse files
committed
install/bootupd: chroot to deployment
When `--src-imgref` is passed, the deployed systemd does not match the running environnement. In this case, let's chroot into the deployment before calling bootupd. This makes sure we are using the binaries shipped in the image (and relevant config files such as grub fragements). We could do that in all cases but i kept it behind the `--src-imgref` option since when using the target container as the buildroot it will have no impact, and we expect this scenario to be the most common. In CoreOS we have a specific test that checks if the bootloader was installed with the `grub2-install` of the image. Fixes #1559 Also see #1455
1 parent f687add commit 0b51f0e

File tree

1 file changed

+45
-6
lines changed

1 file changed

+45
-6
lines changed

crates/lib/src/bootloader.rs

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use fn_error_context::context;
88

99
use bootc_blockdev::{Partition, PartitionTable};
1010
use bootc_mount as mount;
11+
use rustix::mount::UnmountFlags;
1112

1213
use crate::bootc_composefs::boot::mount_esp;
1314
use crate::{discoverable_partition_specification, utils};
@@ -50,22 +51,60 @@ pub(crate) fn install_via_bootupd(
5051
// bootc defaults to only targeting the platform boot method.
5152
let bootupd_opts = (!configopts.generic_image).then_some(["--update-firmware", "--auto"]);
5253

53-
let abs_deployment_path = deployment_path.map(|v| rootfs.join(v));
54-
let src_root_arg = if let Some(p) = abs_deployment_path.as_deref() {
55-
vec!["--src-root", p.as_str()]
54+
let abs_deployment_path = deployment_path.map(|deploy| rootfs.join(deploy));
55+
// When not running inside the target container (through `--src-imgref`) we chroot
56+
// into the deployment before running bootupd. This makes sure we use binaries
57+
// from the target image rather than the buildroot
58+
let bind_mount_dirs = ["/dev", "/run", "/proc", "/sys"];
59+
let chroot_args = if let Some(target_root) = abs_deployment_path.as_deref() {
60+
tracing::debug!("Setting up bind-mounts before chrooting to the target deployment");
61+
for src in bind_mount_dirs {
62+
let dest = target_root
63+
// joining an absolute path
64+
// makes it replace self, so we strip the prefix
65+
.join_os(src.strip_prefix("/").unwrap());
66+
tracing::debug!("bind mounting {}", dest.display());
67+
rustix::mount::mount_bind_recursive(src, dest)?;
68+
}
69+
// Append the `bootupctl` command, it will be passed as
70+
// an argument to chroot
71+
vec![target_root.as_str(), "bootupctl"]
5672
} else {
5773
vec![]
5874
};
75+
5976
let devpath = device.path();
6077
println!("Installing bootloader via bootupd");
61-
Command::new("bootupctl")
78+
let mut bootupctl = if abs_deployment_path.is_some() {
79+
Command::new("chroot")
80+
} else {
81+
Command::new("bootupctl")
82+
};
83+
let install_result = bootupctl
84+
.args(chroot_args)
6285
.args(["backend", "install", "--write-uuid"])
6386
.args(verbose)
6487
.args(bootupd_opts.iter().copied().flatten())
65-
.args(src_root_arg)
6688
.args(["--device", devpath.as_str(), rootfs.as_str()])
6789
.log_debug()
68-
.run_inherited_with_cmd_context()
90+
.run_inherited_with_cmd_context();
91+
92+
// Clean up the mounts after ourselves
93+
if let Some(target_root) = abs_deployment_path {
94+
let mut unmount_res = Ok(());
95+
for dir in bind_mount_dirs {
96+
let mount = target_root
97+
.join(dir.strip_prefix("/").unwrap())
98+
.into_std_path_buf();
99+
if let Err(e) = rustix::mount::unmount(&mount, UnmountFlags::DETACH) {
100+
tracing::warn!("Error unmounting {}: {e}", mount.display());
101+
unmount_res = Err(e.into());
102+
}
103+
}
104+
install_result.and(unmount_res)
105+
} else {
106+
install_result
107+
}
69108
}
70109

71110
#[context("Installing bootloader")]

0 commit comments

Comments
 (0)