Skip to content

Commit a1a8102

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 Signed-off-by: jbtrystram <jbtrystram@redhat.com>
1 parent 1a61162 commit a1a8102

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
@@ -9,6 +9,7 @@ use fn_error_context::context;
99

1010
use bootc_blockdev::{Partition, PartitionTable};
1111
use bootc_mount as mount;
12+
use rustix::mount::UnmountFlags;
1213

1314
use crate::bootc_composefs::boot::{mount_esp, SecurebootKeys};
1415
use crate::{discoverable_partition_specification, utils};
@@ -54,22 +55,60 @@ pub(crate) fn install_via_bootupd(
5455
// bootc defaults to only targeting the platform boot method.
5556
let bootupd_opts = (!configopts.generic_image).then_some(["--update-firmware", "--auto"]);
5657

57-
let abs_deployment_path = deployment_path.map(|v| rootfs.join(v));
58-
let src_root_arg = if let Some(p) = abs_deployment_path.as_deref() {
59-
vec!["--src-root", p.as_str()]
58+
let abs_deployment_path = deployment_path.map(|deploy| rootfs.join(deploy));
59+
// When not running inside the target container (through `--src-imgref`) we chroot
60+
// into the deployment before running bootupd. This makes sure we use binaries
61+
// from the target image rather than the buildroot
62+
let bind_mount_dirs = ["/dev", "/run", "/proc", "/sys"];
63+
let chroot_args = if let Some(target_root) = abs_deployment_path.as_deref() {
64+
tracing::debug!("Setting up bind-mounts before chrooting to the target deployment");
65+
for src in bind_mount_dirs {
66+
let dest = target_root
67+
// joining an absolute path
68+
// makes it replace self, so we strip the prefix
69+
.join_os(src.strip_prefix("/").unwrap());
70+
tracing::debug!("bind mounting {}", dest.display());
71+
rustix::mount::mount_bind_recursive(src, dest)?;
72+
}
73+
// Append the `bootupctl` command, it will be passed as
74+
// an argument to chroot
75+
vec![target_root.as_str(), "bootupctl"]
6076
} else {
6177
vec![]
6278
};
79+
6380
let devpath = device.path();
6481
println!("Installing bootloader via bootupd");
65-
Command::new("bootupctl")
82+
let mut bootupctl = if abs_deployment_path.is_some() {
83+
Command::new("chroot")
84+
} else {
85+
Command::new("bootupctl")
86+
};
87+
let install_result = bootupctl
88+
.args(chroot_args)
6689
.args(["backend", "install", "--write-uuid"])
6790
.args(verbose)
6891
.args(bootupd_opts.iter().copied().flatten())
69-
.args(src_root_arg)
7092
.args(["--device", devpath.as_str(), rootfs.as_str()])
7193
.log_debug()
72-
.run_inherited_with_cmd_context()
94+
.run_inherited_with_cmd_context();
95+
96+
// Clean up the mounts after ourselves
97+
if let Some(target_root) = abs_deployment_path {
98+
let mut unmount_res = Ok(());
99+
for dir in bind_mount_dirs {
100+
let mount = target_root
101+
.join(dir.strip_prefix("/").unwrap())
102+
.into_std_path_buf();
103+
if let Err(e) = rustix::mount::unmount(&mount, UnmountFlags::DETACH) {
104+
tracing::warn!("Error unmounting {}: {e}", mount.display());
105+
unmount_res = Err(e.into());
106+
}
107+
}
108+
install_result.and(unmount_res)
109+
} else {
110+
install_result
111+
}
73112
}
74113

75114
#[context("Installing bootloader")]

0 commit comments

Comments
 (0)