Skip to content

Commit 4cb1e63

Browse files
cfs/to-existing-root: Bootloader support
To figure out which bootloader to install, get the host's bootloader (read from LoaderInfo from efivars) and store it in state. Before finalizing the bootloader, check if the detected bootloader is compatible with the current image (as the bootloader on host and the one in the new image might differ) Signed-off-by: Pragyan Poudyal <pragyanpoudyal41999@gmail.com>
1 parent fa18de1 commit 4cb1e63

2 files changed

Lines changed: 50 additions & 5 deletions

File tree

crates/lib/src/install.rs

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -642,8 +642,12 @@ pub(crate) struct State {
642642
#[allow(dead_code)]
643643
pub(crate) composefs_required: bool,
644644

645-
// If Some, then --composefs_native is passed
645+
/// If Some, then --composefs-backend is passed
646646
pub(crate) composefs_options: InstallComposefsOpts,
647+
648+
/// The bootloader on the host (determined by reading LoaderInfo from efivars)
649+
/// Only Some when bootc is invoked with `install to-existing-root`
650+
pub(crate) host_bootloader: Option<Bootloader>,
647651
}
648652

649653
// Shared read-only global state
@@ -1709,8 +1713,13 @@ async fn prepare_install(
17091713

17101714
// Read efivars to get the bootloader
17111715
// Only if the operation is to replace the existing installation
1712-
if let Some(..) = replace_mode {
1713-
config_opts.bootloader = Some(get_bootloader().context("Determining existing bootloader")?)
1716+
let host_bootloader = match replace_mode {
1717+
Some(..) => {
1718+
let host_bootloader = get_bootloader().context("Determining existing bootloader")?;
1719+
println!("Detected bootloader on host: {host_bootloader}");
1720+
Some(host_bootloader)
1721+
}
1722+
None => None,
17141723
};
17151724

17161725
// Now, deal with SELinux state.
@@ -1819,26 +1828,60 @@ async fn prepare_install(
18191828
host_is_container,
18201829
composefs_required,
18211830
composefs_options,
1831+
host_bootloader,
18221832
});
18231833

18241834
Ok(state)
18251835
}
18261836

18271837
impl PostFetchState {
18281838
pub(crate) fn new(state: &State, d: &Dir) -> Result<Self> {
1839+
let supports_bootupd = crate::bootloader::supports_bootupd(d)?;
1840+
18291841
// Determine bootloader type for the target system
18301842
// Priority: user-specified > bootupd availability > systemd-boot fallback
18311843
let detected_bootloader = {
18321844
if let Some(bootloader) = state.config_opts.bootloader.clone() {
18331845
bootloader
18341846
} else {
1835-
if crate::bootloader::supports_bootupd(d)? {
1847+
// TODO(Johan-Liebert1): The new release of bootupd would support all
1848+
if supports_bootupd {
18361849
crate::spec::Bootloader::Grub
18371850
} else {
18381851
crate::spec::Bootloader::Systemd
18391852
}
18401853
}
18411854
};
1855+
1856+
// If this exists it means we're replacing the current root
1857+
// or installing alongside it. The new image may or may not have
1858+
// the same bootloader as the host
1859+
//
1860+
// We could simply throw an error here, but at this point we'd have
1861+
// already nuked the boot or ESP so we should try our best to figure
1862+
// out what to install
1863+
let detected_bootloader = match state.host_bootloader {
1864+
Some(b) => match b {
1865+
Bootloader::Grub | Bootloader::GrubCC => {
1866+
if supports_bootupd {
1867+
b
1868+
} else {
1869+
Bootloader::Systemd
1870+
}
1871+
}
1872+
Bootloader::Systemd => match crate::bootloader::bootctl_systemd_version() {
1873+
Ok(_) => Bootloader::Systemd,
1874+
Err(_) => {
1875+
println!("Could not find bootctl, defaulting to Grub");
1876+
Bootloader::Grub
1877+
}
1878+
},
1879+
Bootloader::None => Bootloader::None,
1880+
},
1881+
1882+
None => detected_bootloader,
1883+
};
1884+
18421885
println!("Bootloader: {detected_bootloader}");
18431886
let r = Self {
18441887
detected_bootloader,

crates/lib/src/utils.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,9 @@ pub fn have_executable(name: &str) -> Result<bool> {
8484
/// Given a target directory, if it's a read-only mount, then remount it writable
8585
#[context("Opening {target} with writable mount")]
8686
pub(crate) fn open_dir_remount_rw(root: &Dir, target: &Utf8Path) -> Result<Dir> {
87-
let target_dir = root.open_dir(target).with_context(|| format!("Opening {target}"))?;
87+
let target_dir = root
88+
.open_dir(target)
89+
.with_context(|| format!("Opening {target}"))?;
8890

8991
if matches!(target_dir.is_mountpoint("."), Ok(Some(true))) {
9092
let st = rustix::fs::fstatvfs(target_dir.as_fd())

0 commit comments

Comments
 (0)