@@ -19,6 +19,7 @@ use rustix::fd::BorrowedFd;
1919use walkdir:: WalkDir ;
2020use widestring:: U16CString ;
2121
22+ use crate :: blockdev;
2223use crate :: filetree;
2324use crate :: model:: * ;
2425use crate :: ostreeutil;
@@ -57,28 +58,7 @@ pub(crate) struct Efi {
5758}
5859
5960impl Efi {
60- fn esp_path ( & self ) -> Result < PathBuf > {
61- self . ensure_mounted_esp ( Path :: new ( "/" ) )
62- . map ( |v| v. join ( "EFI" ) )
63- }
64-
65- fn open_esp_optional ( & self ) -> Result < Option < openat:: Dir > > {
66- if !is_efi_booted ( ) ? && self . get_esp_device ( ) . is_none ( ) {
67- log:: debug!( "Skip EFI" ) ;
68- return Ok ( None ) ;
69- }
70- let sysroot = openat:: Dir :: open ( "/" ) ?;
71- let esp = sysroot. sub_dir_optional ( & self . esp_path ( ) ?) ?;
72- Ok ( esp)
73- }
74-
75- fn open_esp ( & self ) -> Result < openat:: Dir > {
76- self . ensure_mounted_esp ( Path :: new ( "/" ) ) ?;
77- let sysroot = openat:: Dir :: open ( "/" ) ?;
78- let esp = sysroot. sub_dir ( & self . esp_path ( ) ?) ?;
79- Ok ( esp)
80- }
81-
61+ // Get esp device via legacy
8262 fn get_esp_device ( & self ) -> Option < PathBuf > {
8363 let esp_devices = [ COREOS_ESP_PART_LABEL , ANACONDA_ESP_PART_LABEL ]
8464 . into_iter ( )
@@ -93,11 +73,26 @@ impl Efi {
9373 return esp_device;
9474 }
9575
96- pub ( crate ) fn ensure_mounted_esp ( & self , root : & Path ) -> Result < PathBuf > {
97- let mut mountpoint = self . mountpoint . borrow_mut ( ) ;
76+ // Get esp device list on all devices
77+ fn get_esp_devices ( & self ) -> Option < Vec < String > > {
78+ let mut esp_devices = vec ! [ ] ;
79+ if let Some ( esp_device) = self . get_esp_device ( ) {
80+ esp_devices. push ( esp_device. to_string_lossy ( ) . into_owned ( ) ) ;
81+ } else {
82+ esp_devices = blockdev:: find_colocated_esps ( "/" ) . expect ( "get esp devices" ) ;
83+ } ;
84+ if !esp_devices. is_empty ( ) {
85+ return Some ( esp_devices) ;
86+ }
87+ return None ;
88+ }
89+
90+ fn check_mounted_esp < P : AsRef < Path > > ( & self , root : P ) -> Result < Option < PathBuf > > {
91+ let mountpoint = self . mountpoint . borrow_mut ( ) ;
9892 if let Some ( mountpoint) = mountpoint. as_deref ( ) {
99- return Ok ( mountpoint. to_owned ( ) ) ;
93+ return Ok ( Some ( mountpoint. to_owned ( ) ) ) ;
10094 }
95+ let root = root. as_ref ( ) ;
10196 for & mnt in ESP_MOUNTS {
10297 let mnt = root. join ( mnt) ;
10398 if !mnt. exists ( ) {
@@ -109,13 +104,23 @@ impl Efi {
109104 continue ;
110105 }
111106 util:: ensure_writable_mount ( & mnt) ?;
112- log:: debug!( "Reusing existing {mnt:?}" ) ;
113- return Ok ( mnt) ;
107+ log:: debug!( "Reusing existing mount point {mnt:?}" ) ;
108+ return Ok ( Some ( mnt) ) ;
109+ }
110+ Ok ( None )
111+ }
112+
113+ pub ( crate ) fn ensure_mounted_esp < P : AsRef < Path > > (
114+ & self ,
115+ root : P ,
116+ esp_device : & str ,
117+ ) -> Result < PathBuf > {
118+ let mut mountpoint = self . mountpoint . borrow_mut ( ) ;
119+ if let Some ( mountpoint) = mountpoint. as_deref ( ) {
120+ return Ok ( mountpoint. to_owned ( ) ) ;
114121 }
115122
116- let esp_device = self
117- . get_esp_device ( )
118- . ok_or_else ( || anyhow:: anyhow!( "Failed to find ESP device" ) ) ?;
123+ let root = root. as_ref ( ) ;
119124 for & mnt in ESP_MOUNTS . iter ( ) {
120125 let mnt = root. join ( mnt) ;
121126 if !mnt. exists ( ) {
@@ -137,6 +142,7 @@ impl Efi {
137142 if let Some ( mount) = self . mountpoint . borrow_mut ( ) . take ( ) {
138143 Command :: new ( "umount" )
139144 . arg ( & mount)
145+ . arg ( "-l" )
140146 . run ( )
141147 . with_context ( || format ! ( "Failed to unmount {mount:?}" ) ) ?;
142148 log:: trace!( "Unmounted" ) ;
@@ -243,8 +249,7 @@ impl Component for Efi {
243249 }
244250
245251 fn query_adopt ( & self ) -> Result < Option < Adoptable > > {
246- let esp = self . open_esp_optional ( ) ?;
247- if esp. is_none ( ) {
252+ if self . get_esp_devices ( ) . is_none ( ) {
248253 log:: trace!( "No ESP detected" ) ;
249254 return Ok ( None ) ;
250255 } ;
@@ -267,16 +272,32 @@ impl Component for Efi {
267272 anyhow:: bail!( "Failed to find adoptable system" )
268273 } ;
269274
270- let esp = self . open_esp ( ) ?;
271- validate_esp ( & esp) ?;
272275 let updated = sysroot
273276 . sub_dir ( & component_updatedirname ( self ) )
274277 . context ( "opening update dir" ) ?;
275278 let updatef = filetree:: FileTree :: new_from_dir ( & updated) . context ( "reading update dir" ) ?;
276- // For adoption, we should only touch files that we know about.
277- let diff = updatef. relative_diff_to ( & esp) ?;
278- log:: trace!( "applying adoption diff: {}" , & diff) ;
279- filetree:: apply_diff ( & updated, & esp, & diff, None ) . context ( "applying filesystem changes" ) ?;
279+ let esp_devices = self
280+ . get_esp_devices ( )
281+ . expect ( "get esp devices before adopt" ) ;
282+ let sysroot = sysroot. recover_path ( ) ?;
283+
284+ for esp_dev in esp_devices {
285+ let dest_path = if let Some ( dest_path) = self . check_mounted_esp ( & sysroot) ? {
286+ dest_path. join ( "EFI" )
287+ } else {
288+ self . ensure_mounted_esp ( & sysroot, & esp_dev) ?. join ( "EFI" )
289+ } ;
290+
291+ let esp = openat:: Dir :: open ( & dest_path) . context ( "opening EFI dir" ) ?;
292+ validate_esp ( & esp) ?;
293+
294+ // For adoption, we should only touch files that we know about.
295+ let diff = updatef. relative_diff_to ( & esp) ?;
296+ log:: trace!( "applying adoption diff: {}" , & diff) ;
297+ filetree:: apply_diff ( & updated, & esp, & diff, None )
298+ . context ( "applying filesystem changes" ) ?;
299+ self . unmount ( ) . context ( "unmount after adopt" ) ?;
300+ }
280301 Ok ( InstalledContent {
281302 meta : updatemeta. clone ( ) ,
282303 filetree : Some ( updatef) ,
@@ -298,9 +319,17 @@ impl Component for Efi {
298319 log:: debug!( "Found metadata {}" , meta. version) ;
299320 let srcdir_name = component_updatedirname ( self ) ;
300321 let ft = crate :: filetree:: FileTree :: new_from_dir ( & src_root. sub_dir ( & srcdir_name) ?) ?;
301- let destdir = & self . ensure_mounted_esp ( Path :: new ( dest_root) ) ?;
322+ let destdir = if let Some ( destdir) = self . check_mounted_esp ( dest_root) ? {
323+ destdir
324+ } else {
325+ let esp_device = self
326+ . get_esp_device ( )
327+ . ok_or_else ( || anyhow:: anyhow!( "Failed to find ESP device" ) ) ?;
328+ let esp_device = esp_device. to_str ( ) . unwrap ( ) ;
329+ self . ensure_mounted_esp ( dest_root, esp_device) ?
330+ } ;
302331
303- let destd = & openat:: Dir :: open ( destdir)
332+ let destd = & openat:: Dir :: open ( & destdir)
304333 . with_context ( || format ! ( "opening dest dir {}" , destdir. display( ) ) ) ?;
305334 validate_esp ( destd) ?;
306335
@@ -339,12 +368,25 @@ impl Component for Efi {
339368 . context ( "opening update dir" ) ?;
340369 let updatef = filetree:: FileTree :: new_from_dir ( & updated) . context ( "reading update dir" ) ?;
341370 let diff = currentf. diff ( & updatef) ?;
342- self . ensure_mounted_esp ( Path :: new ( "/" ) ) ?;
343- let destdir = self . open_esp ( ) . context ( "opening EFI dir" ) ?;
344- validate_esp ( & destdir) ?;
345- log:: trace!( "applying diff: {}" , & diff) ;
346- filetree:: apply_diff ( & updated, & destdir, & diff, None )
347- . context ( "applying filesystem changes" ) ?;
371+ let esp_devices = self
372+ . get_esp_devices ( )
373+ . context ( "get esp devices when running update" ) ?;
374+ let sysroot = sysroot. recover_path ( ) ?;
375+
376+ for esp in esp_devices {
377+ let dest_path = if let Some ( dest_path) = self . check_mounted_esp ( & sysroot) ? {
378+ dest_path. join ( "EFI" )
379+ } else {
380+ self . ensure_mounted_esp ( & sysroot, & esp) ?. join ( "EFI" )
381+ } ;
382+
383+ let destdir = openat:: Dir :: open ( & dest_path) . context ( "opening EFI dir" ) ?;
384+ validate_esp ( & destdir) ?;
385+ log:: trace!( "applying diff: {}" , & diff) ;
386+ filetree:: apply_diff ( & updated, & destdir, & diff, None )
387+ . context ( "applying filesystem changes" ) ?;
388+ self . unmount ( ) . context ( "unmount after update" ) ?;
389+ }
348390 let adopted_from = None ;
349391 Ok ( InstalledContent {
350392 meta : updatemeta,
@@ -392,24 +434,37 @@ impl Component for Efi {
392434 }
393435
394436 fn validate ( & self , current : & InstalledContent ) -> Result < ValidationResult > {
395- if !is_efi_booted ( ) ? && self . get_esp_device ( ) . is_none ( ) {
437+ let esp_devices = self . get_esp_devices ( ) ;
438+ if !is_efi_booted ( ) ? && esp_devices. is_none ( ) {
396439 return Ok ( ValidationResult :: Skip ) ;
397440 }
398441 let currentf = current
399442 . filetree
400443 . as_ref ( )
401444 . ok_or_else ( || anyhow:: anyhow!( "No filetree for installed EFI found!" ) ) ?;
402- self . ensure_mounted_esp ( Path :: new ( "/" ) ) ?;
403- let efidir = self . open_esp ( ) ?;
404- let diff = currentf. relative_diff_to ( & efidir) ?;
445+
405446 let mut errs = Vec :: new ( ) ;
406- for f in diff. changes . iter ( ) {
407- errs. push ( format ! ( "Changed: {}" , f) ) ;
408- }
409- for f in diff. removals . iter ( ) {
410- errs. push ( format ! ( "Removed: {}" , f) ) ;
447+ let esps = esp_devices. ok_or_else ( || anyhow:: anyhow!( "No esp device found!" ) ) ?;
448+ let dest_root = Path :: new ( "/" ) ;
449+ for esp_dev in esps. iter ( ) {
450+ let dest_path = if let Some ( dest_path) = self . check_mounted_esp ( dest_root) ? {
451+ dest_path. join ( "EFI" )
452+ } else {
453+ self . ensure_mounted_esp ( dest_root, & esp_dev) ?. join ( "EFI" )
454+ } ;
455+
456+ let efidir = openat:: Dir :: open ( dest_path. as_path ( ) ) ?;
457+ let diff = currentf. relative_diff_to ( & efidir) ?;
458+
459+ for f in diff. changes . iter ( ) {
460+ errs. push ( format ! ( "Changed: {}" , f) ) ;
461+ }
462+ for f in diff. removals . iter ( ) {
463+ errs. push ( format ! ( "Removed: {}" , f) ) ;
464+ }
465+ assert_eq ! ( diff. additions. len( ) , 0 ) ;
466+ self . unmount ( ) . context ( "unmount after validate" ) ?;
411467 }
412- assert_eq ! ( diff. additions. len( ) , 0 ) ;
413468 if !errs. is_empty ( ) {
414469 Ok ( ValidationResult :: Errors ( errs) )
415470 } else {
0 commit comments