5
5
#![ allow( dead_code) ]
6
6
7
7
use anyhow:: { anyhow, Result } ;
8
+ use core:: fmt;
8
9
use std:: collections:: HashMap ;
9
10
use std:: fmt:: Display ;
10
11
use uapi_version:: Version ;
11
12
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
+
12
31
/// Represents a single Boot Loader Specification config file.
13
32
///
14
33
/// 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 {
24
43
///
25
44
/// This is hidden and must be accessed via [`Self::version()`];
26
45
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
+
33
49
/// The machine ID of the OS.
34
50
pub ( crate ) machine_id : Option < String > ,
35
51
/// The sort key for the boot menu.
@@ -79,13 +95,30 @@ impl Display for BLSConfig {
79
95
}
80
96
81
97
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 ) ,
88
120
}
121
+
89
122
if let Some ( machine_id) = self . machine_id . as_deref ( ) {
90
123
writeln ! ( f, "machine-id {}" , machine_id) ?;
91
124
}
@@ -114,16 +147,8 @@ impl BLSConfig {
114
147
self . version = new_val;
115
148
self
116
149
}
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;
127
152
self
128
153
}
129
154
#[ allow( dead_code) ]
@@ -146,6 +171,7 @@ pub(crate) fn parse_bls_config(input: &str) -> Result<BLSConfig> {
146
171
let mut title = None ;
147
172
let mut version = None ;
148
173
let mut linux = None ;
174
+ let mut efi = None ;
149
175
let mut initrd = Vec :: new ( ) ;
150
176
let mut options = None ;
151
177
let mut machine_id = None ;
@@ -168,22 +194,35 @@ pub(crate) fn parse_bls_config(input: &str) -> Result<BLSConfig> {
168
194
"options" => options = Some ( value) ,
169
195
"machine-id" => machine_id = Some ( value) ,
170
196
"sort-key" => sort_key = Some ( value) ,
197
+ "efi" => efi = Some ( value) ,
171
198
_ => {
172
199
extra. insert ( key. to_string ( ) , value) ;
173
200
}
174
201
}
175
202
}
176
203
}
177
204
178
- let linux = linux. ok_or_else ( || anyhow ! ( "Missing 'linux' value" ) ) ?;
179
205
let version = version. ok_or_else ( || anyhow ! ( "Missing 'version' value" ) ) ?;
180
206
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
+
181
222
Ok ( BLSConfig {
182
223
title,
183
224
version,
184
- linux,
185
- initrd,
186
- options,
225
+ cfg_type,
187
226
machine_id,
188
227
sort_key,
189
228
extra,
@@ -208,14 +247,23 @@ mod tests {
208
247
209
248
let config = parse_bls_config ( input) ?;
210
249
250
+ let BLSConfigType :: NonEFI {
251
+ linux,
252
+ initrd,
253
+ options,
254
+ } = config. cfg_type
255
+ else {
256
+ panic ! ( "Expected non EFI variant" ) ;
257
+ } ;
258
+
211
259
assert_eq ! (
212
260
config. title,
213
261
Some ( "Fedora 42.20250623.3.1 (CoreOS)" . to_string( ) )
214
262
) ;
215
263
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( ) ) ) ;
219
267
assert_eq ! ( config. extra. get( "custom1" ) , Some ( & "value1" . to_string( ) ) ) ;
220
268
assert_eq ! ( config. extra. get( "custom2" ) , Some ( & "value2" . to_string( ) ) ) ;
221
269
@@ -235,8 +283,12 @@ mod tests {
235
283
236
284
let config = parse_bls_config ( input) ?;
237
285
286
+ let BLSConfigType :: NonEFI { initrd, .. } = config. cfg_type else {
287
+ panic ! ( "Expected non EFI variant" ) ;
288
+ } ;
289
+
238
290
assert_eq ! (
239
- config . initrd,
291
+ initrd,
240
292
vec![ "/boot/initramfs-1.img" , "/boot/initramfs-2.img" ]
241
293
) ;
242
294
0 commit comments