@@ -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
18271837impl 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,
@@ -2651,21 +2694,31 @@ pub(crate) async fn install_to_filesystem(
26512694 }
26522695 } ;
26532696
2654- // Find the UUID of /boot because we need it for GRUB.
2655- let boot_uuid = match state. config_opts . bootloader {
2656- Some ( Bootloader :: Grub ) | None if boot_is_mount => {
2657- let boot_path = target_root_path. join ( BOOT ) ;
2658- tracing:: debug!( "boot_path={boot_path}" ) ;
2659- let u = bootc_mount:: inspect_filesystem ( & boot_path)
2660- . with_context ( || format ! ( "Inspecting /{BOOT}" ) ) ?
2661- . uuid
2662- . ok_or_else ( || anyhow ! ( "No UUID found for /{BOOT}" ) ) ?;
2663- Some ( u)
2664- }
2665-
2666- _ => None ,
2697+ let mut boot_uuid = None ;
2698+
2699+ let get_boot_uuid = || -> Result < Option < String > > {
2700+ let boot_path = target_root_path. join ( BOOT ) ;
2701+ tracing:: debug!( "boot_path={boot_path}" ) ;
2702+ let u = bootc_mount:: inspect_filesystem ( & boot_path)
2703+ . with_context ( || format ! ( "Inspecting /{BOOT}" ) ) ?
2704+ . uuid
2705+ . ok_or_else ( || anyhow ! ( "No UUID found for /{BOOT}" ) ) ?;
2706+
2707+ Ok ( Some ( u) )
26672708 } ;
26682709
2710+ // Find the UUID of /boot because we need it for GRUB.
2711+ if boot_is_mount {
2712+ if matches ! ( state. host_bootloader, Some ( Bootloader :: Grub ) ) {
2713+ boot_uuid = get_boot_uuid ( ) . context ( "Getting boot uuid" ) ?;
2714+ }
2715+
2716+ // If not set by `host_bootloader`
2717+ if boot_uuid. is_none ( ) && matches ! ( state. config_opts. bootloader, Some ( Bootloader :: Grub ) ) {
2718+ boot_uuid = get_boot_uuid ( ) . context ( "Getting boot uuid" ) ?;
2719+ }
2720+ }
2721+
26692722 tracing:: debug!( "boot UUID: {boot_uuid:?}" ) ;
26702723
26712724 // Find the real underlying backing device for the root. This is currently just required
0 commit comments