@@ -25,6 +25,13 @@ use std::fs::{self, File};
2525use std:: io:: { BufRead , BufReader , BufWriter , Write } ;
2626use std:: path:: { Path , PathBuf } ;
2727
28+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
29+ pub ( crate ) enum Bootloader {
30+ Grub2 ,
31+ #[ cfg( feature = "systemd-boot" ) ]
32+ SystemdBoot ,
33+ }
34+
2835pub ( crate ) enum ConfigMode {
2936 None ,
3037 Static ,
@@ -81,6 +88,25 @@ pub(crate) fn install(
8188 anyhow:: bail!( "No components specified" ) ;
8289 }
8390
91+ // If Grub2 binaries are present, use Grub2
92+ // Else if systemd-boot EFI binaries are present, use SystemdBoot
93+ // Else fall back to Grub2
94+ let bootloader = if has_grub ( & source_root) {
95+ Bootloader :: Grub2
96+ } else if has_systemd_boot ( & source_root) {
97+ #[ cfg( feature = "systemd-boot" ) ]
98+ {
99+ Bootloader :: SystemdBoot
100+ }
101+ #[ cfg( not( feature = "systemd-boot" ) ) ]
102+ {
103+ anyhow:: bail!( "systemd-boot support is not enabled in this build" ) ;
104+ }
105+ } else {
106+ log:: warn!( "No bootloader binaries found, defaulting to Grub2" ) ;
107+ Bootloader :: Grub2
108+ } ;
109+
84110 let mut state = SavedState :: default ( ) ;
85111 let mut installed_efi_vendor = None ;
86112 for & component in target_components. iter ( ) {
@@ -93,20 +119,51 @@ pub(crate) fn install(
93119 continue ;
94120 }
95121
122+ #[ cfg( feature = "systemd-boot" ) ]
123+ if bootloader == Bootloader :: SystemdBoot && component. name ( ) == "BIOS" {
124+ log:: warn!( "Skip installing BIOS component when using systemd-boot" ) ;
125+ continue ;
126+ }
127+
128+ let update_firmware = match bootloader {
129+ Bootloader :: Grub2 => update_firmware,
130+ #[ cfg( feature = "systemd-boot" ) ]
131+ Bootloader :: SystemdBoot => false ,
132+ } ;
133+
96134 let meta = component
97- . install ( & source_root, dest_root, device, update_firmware)
135+ . install (
136+ & source_root,
137+ dest_root,
138+ device,
139+ update_firmware,
140+ & bootloader,
141+ )
98142 . with_context ( || format ! ( "installing component {}" , component. name( ) ) ) ?;
99143 log:: info!( "Installed {} {}" , component. name( ) , meta. meta. version) ;
100144 state. installed . insert ( component. name ( ) . into ( ) , meta) ;
101- // Yes this is a hack...the Component thing just turns out to be too generic.
102- if let Some ( vendor) = component. get_efi_vendor ( & source_root) ? {
103- assert ! ( installed_efi_vendor. is_none( ) ) ;
104- installed_efi_vendor = Some ( vendor) ;
145+
146+ match bootloader {
147+ Bootloader :: Grub2 => {
148+ // Yes this is a hack...the Component thing just turns out to be too generic.
149+ if let Some ( vendor) = component. get_efi_vendor ( & source_root) ? {
150+ assert ! ( installed_efi_vendor. is_none( ) ) ;
151+ installed_efi_vendor = Some ( vendor) ;
152+ }
153+ }
154+ #[ cfg( feature = "systemd-boot" ) ]
155+ _ => { }
105156 }
106157 }
107158 let sysroot = & openat:: Dir :: open ( dest_root) ?;
108159
109- match configs. enabled_with_uuid ( ) {
160+ // If systemd-boot is enabled, do not run grubconfigs::install
161+ let configs_with_uuid = match bootloader {
162+ Bootloader :: Grub2 => configs. enabled_with_uuid ( ) ,
163+ #[ cfg( feature = "systemd-boot" ) ]
164+ _ => None ,
165+ } ;
166+ match configs_with_uuid {
110167 Some ( uuid) => {
111168 let meta = get_static_config_meta ( ) ?;
112169 state. static_configs = Some ( meta) ;
@@ -715,6 +772,16 @@ fn strip_grub_config_file(
715772 Ok ( ( ) )
716773}
717774
775+ /// Determine whether the necessary bootloader files are present for GRUB.
776+ fn has_grub ( source_root : & openat:: Dir ) -> bool {
777+ source_root. open_file ( bios:: GRUB_BIN ) . is_ok ( )
778+ }
779+
780+ /// Determine whether the necessary bootloader files are present for systemd-boot.
781+ fn has_systemd_boot ( source_root : & openat:: Dir ) -> bool {
782+ source_root. open_file ( efi:: SYSTEMD_BOOT_EFI ) . is_ok ( )
783+ }
784+
718785#[ cfg( test) ]
719786mod tests {
720787 use super :: * ;
0 commit comments