55#![ allow( dead_code) ]
66
77use anyhow:: { anyhow, Result } ;
8+ use core:: fmt;
89use std:: collections:: HashMap ;
910use std:: fmt:: Display ;
1011use uapi_version:: Version ;
1112
13+ #[ derive( Debug , PartialEq , PartialOrd , Eq , Default ) ]
14+ pub enum BLSConfigType {
15+ EFI {
16+ /// The path to the EFI binary, usually a UKI
17+ efi : String ,
18+ } ,
19+ NonEFI {
20+ /// The path to the linux kernel to boot.
21+ linux : String ,
22+ /// The paths to the initrd images.
23+ initrd : Vec < String > ,
24+ /// Kernel command line options.
25+ options : Option < String > ,
26+ } ,
27+ #[ default]
28+ Unknown ,
29+ }
30+
1231/// Represents a single Boot Loader Specification config file.
1332///
1433/// The boot loader should present the available boot menu entries to the user in a sorted list.
@@ -24,12 +43,9 @@ pub(crate) struct BLSConfig {
2443 ///
2544 /// This is hidden and must be accessed via [`Self::version()`];
2645 version : String ,
27- /// The path to the linux kernel to boot.
28- pub ( crate ) linux : String ,
29- /// The paths to the initrd images.
30- pub ( crate ) initrd : Vec < String > ,
31- /// Kernel command line options.
32- pub ( crate ) options : Option < String > ,
46+
47+ pub ( crate ) cfg_type : BLSConfigType ,
48+
3349 /// The machine ID of the OS.
3450 pub ( crate ) machine_id : Option < String > ,
3551 /// The sort key for the boot menu.
@@ -79,13 +95,30 @@ impl Display for BLSConfig {
7995 }
8096
8197 writeln ! ( f, "version {}" , self . version) ?;
82- writeln ! ( f, "linux {}" , self . linux) ?;
83- for initrd in self . initrd . iter ( ) {
84- writeln ! ( f, "initrd {}" , initrd) ?;
85- }
86- if let Some ( options) = self . options . as_deref ( ) {
87- writeln ! ( f, "options {}" , options) ?;
98+
99+ match & self . cfg_type {
100+ BLSConfigType :: EFI { efi } => {
101+ writeln ! ( f, "efi {}" , efi) ?;
102+ }
103+
104+ BLSConfigType :: NonEFI {
105+ linux,
106+ initrd,
107+ options,
108+ } => {
109+ writeln ! ( f, "linux {}" , linux) ?;
110+ for initrd in initrd. iter ( ) {
111+ writeln ! ( f, "initrd {}" , initrd) ?;
112+ }
113+
114+ if let Some ( options) = options. as_deref ( ) {
115+ writeln ! ( f, "options {}" , options) ?;
116+ }
117+ }
118+
119+ BLSConfigType :: Unknown => return Err ( fmt:: Error ) ,
88120 }
121+
89122 if let Some ( machine_id) = self . machine_id . as_deref ( ) {
90123 writeln ! ( f, "machine-id {}" , machine_id) ?;
91124 }
@@ -114,16 +147,8 @@ impl BLSConfig {
114147 self . version = new_val;
115148 self
116149 }
117- pub ( crate ) fn with_linux ( & mut self , new_val : String ) -> & mut Self {
118- self . linux = new_val;
119- self
120- }
121- pub ( crate ) fn with_initrd ( & mut self , new_val : Vec < String > ) -> & mut Self {
122- self . initrd = new_val;
123- self
124- }
125- pub ( crate ) fn with_options ( & mut self , new_val : String ) -> & mut Self {
126- self . options = Some ( new_val) ;
150+ pub ( crate ) fn with_cfg ( & mut self , config : BLSConfigType ) -> & mut Self {
151+ self . cfg_type = config;
127152 self
128153 }
129154 #[ allow( dead_code) ]
@@ -146,6 +171,7 @@ pub(crate) fn parse_bls_config(input: &str) -> Result<BLSConfig> {
146171 let mut title = None ;
147172 let mut version = None ;
148173 let mut linux = None ;
174+ let mut efi = None ;
149175 let mut initrd = Vec :: new ( ) ;
150176 let mut options = None ;
151177 let mut machine_id = None ;
@@ -168,22 +194,35 @@ pub(crate) fn parse_bls_config(input: &str) -> Result<BLSConfig> {
168194 "options" => options = Some ( value) ,
169195 "machine-id" => machine_id = Some ( value) ,
170196 "sort-key" => sort_key = Some ( value) ,
197+ "efi" => efi = Some ( value) ,
171198 _ => {
172199 extra. insert ( key. to_string ( ) , value) ;
173200 }
174201 }
175202 }
176203 }
177204
178- let linux = linux. ok_or_else ( || anyhow ! ( "Missing 'linux' value" ) ) ?;
179205 let version = version. ok_or_else ( || anyhow ! ( "Missing 'version' value" ) ) ?;
180206
207+ let cfg_type = match ( linux, efi) {
208+ ( None , Some ( efi) ) => BLSConfigType :: EFI { efi } ,
209+
210+ ( Some ( linux) , None ) => BLSConfigType :: NonEFI {
211+ linux,
212+ initrd,
213+ options,
214+ } ,
215+
216+ // The spec makes no mention of whether both can be present or not
217+ // Fow now, for us, we won't have both at the same time
218+ ( Some ( _) , Some ( _) ) => anyhow:: bail!( "'linux' and 'efi' values present" ) ,
219+ ( None , None ) => anyhow:: bail!( "Missing 'linux' or 'efi' value" ) ,
220+ } ;
221+
181222 Ok ( BLSConfig {
182223 title,
183224 version,
184- linux,
185- initrd,
186- options,
225+ cfg_type,
187226 machine_id,
188227 sort_key,
189228 extra,
@@ -208,14 +247,23 @@ mod tests {
208247
209248 let config = parse_bls_config ( input) ?;
210249
250+ let BLSConfigType :: NonEFI {
251+ linux,
252+ initrd,
253+ options,
254+ } = config. cfg_type
255+ else {
256+ panic ! ( "Expected non EFI variant" ) ;
257+ } ;
258+
211259 assert_eq ! (
212260 config. title,
213261 Some ( "Fedora 42.20250623.3.1 (CoreOS)" . to_string( ) )
214262 ) ;
215263 assert_eq ! ( config. version, "2" ) ;
216- assert_eq ! ( config . linux, "/boot/7e11ac46e3e022053e7226a20104ac656bf72d1a84e3a398b7cce70e9df188b6/vmlinuz-5.14.10" ) ;
217- assert_eq ! ( config . initrd, vec![ "/boot/7e11ac46e3e022053e7226a20104ac656bf72d1a84e3a398b7cce70e9df188b6/initramfs-5.14.10.img" ] ) ;
218- assert_eq ! ( config . options, Some ( "root=UUID=abc123 rw composefs=7e11ac46e3e022053e7226a20104ac656bf72d1a84e3a398b7cce70e9df188b6" . to_string( ) ) ) ;
264+ assert_eq ! ( linux, "/boot/7e11ac46e3e022053e7226a20104ac656bf72d1a84e3a398b7cce70e9df188b6/vmlinuz-5.14.10" ) ;
265+ assert_eq ! ( initrd, vec![ "/boot/7e11ac46e3e022053e7226a20104ac656bf72d1a84e3a398b7cce70e9df188b6/initramfs-5.14.10.img" ] ) ;
266+ assert_eq ! ( options, Some ( "root=UUID=abc123 rw composefs=7e11ac46e3e022053e7226a20104ac656bf72d1a84e3a398b7cce70e9df188b6" . to_string( ) ) ) ;
219267 assert_eq ! ( config. extra. get( "custom1" ) , Some ( & "value1" . to_string( ) ) ) ;
220268 assert_eq ! ( config. extra. get( "custom2" ) , Some ( & "value2" . to_string( ) ) ) ;
221269
@@ -235,8 +283,12 @@ mod tests {
235283
236284 let config = parse_bls_config ( input) ?;
237285
286+ let BLSConfigType :: NonEFI { initrd, .. } = config. cfg_type else {
287+ panic ! ( "Expected non EFI variant" ) ;
288+ } ;
289+
238290 assert_eq ! (
239- config . initrd,
291+ initrd,
240292 vec![ "/boot/initramfs-1.img" , "/boot/initramfs-2.img" ]
241293 ) ;
242294
0 commit comments