@@ -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,27 @@ 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 Ok ( esp_devices) = blockdev:: find_colocated_esps ( "/" ) {
80+ return Some ( esp_devices) ;
81+ } else {
82+ let device = self . get_esp_device ( ) . expect ( "get esp device" ) ;
83+ esp_devices. push ( device. to_string_lossy ( ) . into_owned ( ) ) ;
84+ } ;
85+ if !esp_devices. is_empty ( ) {
86+ return Some ( esp_devices) ;
87+ }
88+ return None ;
89+ }
90+
91+ fn check_mounted_esp < P : AsRef < Path > > ( & self , root : P ) -> Result < Option < PathBuf > > {
92+ let mountpoint = self . mountpoint . borrow_mut ( ) ;
9893 if let Some ( mountpoint) = mountpoint. as_deref ( ) {
99- return Ok ( mountpoint. to_owned ( ) ) ;
94+ return Ok ( Some ( mountpoint. to_owned ( ) ) ) ;
10095 }
96+ let root = root. as_ref ( ) ;
10197 for & mnt in ESP_MOUNTS {
10298 let mnt = root. join ( mnt) ;
10399 if !mnt. exists ( ) {
@@ -109,13 +105,23 @@ impl Efi {
109105 continue ;
110106 }
111107 util:: ensure_writable_mount ( & mnt) ?;
112- log:: debug!( "Reusing existing {mnt:?}" ) ;
113- return Ok ( mnt) ;
108+ log:: debug!( "Reusing existing mount point {mnt:?}" ) ;
109+ return Ok ( Some ( mnt) ) ;
114110 }
111+ Ok ( None )
112+ }
115113
116- let esp_device = self
117- . get_esp_device ( )
118- . ok_or_else ( || anyhow:: anyhow!( "Failed to find ESP device" ) ) ?;
114+ pub ( crate ) fn ensure_mounted_esp < P : AsRef < Path > > (
115+ & self ,
116+ root : P ,
117+ esp_device : & str ,
118+ ) -> Result < PathBuf > {
119+ let mut mountpoint = self . mountpoint . borrow_mut ( ) ;
120+ if let Some ( mountpoint) = mountpoint. as_deref ( ) {
121+ return Ok ( mountpoint. to_owned ( ) ) ;
122+ }
123+
124+ let root = root. as_ref ( ) ;
119125 for & mnt in ESP_MOUNTS . iter ( ) {
120126 let mnt = root. join ( mnt) ;
121127 if !mnt. exists ( ) {
@@ -137,6 +143,7 @@ impl Efi {
137143 if let Some ( mount) = self . mountpoint . borrow_mut ( ) . take ( ) {
138144 Command :: new ( "umount" )
139145 . arg ( & mount)
146+ . arg ( "-l" )
140147 . run ( )
141148 . with_context ( || format ! ( "Failed to unmount {mount:?}" ) ) ?;
142149 log:: trace!( "Unmounted" ) ;
@@ -243,8 +250,7 @@ impl Component for Efi {
243250 }
244251
245252 fn query_adopt ( & self ) -> Result < Option < Adoptable > > {
246- let esp = self . open_esp_optional ( ) ?;
247- if esp. is_none ( ) {
253+ if self . get_esp_devices ( ) . is_none ( ) {
248254 log:: trace!( "No ESP detected" ) ;
249255 return Ok ( None ) ;
250256 } ;
@@ -267,16 +273,32 @@ impl Component for Efi {
267273 anyhow:: bail!( "Failed to find adoptable system" )
268274 } ;
269275
270- let esp = self . open_esp ( ) ?;
271- validate_esp ( & esp) ?;
272276 let updated = sysroot
273277 . sub_dir ( & component_updatedirname ( self ) )
274278 . context ( "opening update dir" ) ?;
275279 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" ) ?;
280+ let esp_devices = self
281+ . get_esp_devices ( )
282+ . expect ( "get esp devices before adopt" ) ;
283+ let sysroot = sysroot. recover_path ( ) ?;
284+
285+ for esp_dev in esp_devices {
286+ let dest_path = if let Some ( dest_path) = self . check_mounted_esp ( & sysroot) ? {
287+ dest_path. join ( "EFI" )
288+ } else {
289+ self . ensure_mounted_esp ( & sysroot, & esp_dev) ?. join ( "EFI" )
290+ } ;
291+
292+ let esp = openat:: Dir :: open ( & dest_path) . context ( "opening EFI dir" ) ?;
293+ validate_esp ( & esp) ?;
294+
295+ // For adoption, we should only touch files that we know about.
296+ let diff = updatef. relative_diff_to ( & esp) ?;
297+ log:: trace!( "applying adoption diff: {}" , & diff) ;
298+ filetree:: apply_diff ( & updated, & esp, & diff, None )
299+ . context ( "applying filesystem changes" ) ?;
300+ self . unmount ( ) . context ( "unmount after adopt" ) ?;
301+ }
280302 Ok ( InstalledContent {
281303 meta : updatemeta. clone ( ) ,
282304 filetree : Some ( updatef) ,
@@ -298,9 +320,17 @@ impl Component for Efi {
298320 log:: debug!( "Found metadata {}" , meta. version) ;
299321 let srcdir_name = component_updatedirname ( self ) ;
300322 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) ) ?;
323+ let destdir = if let Some ( destdir) = self . check_mounted_esp ( dest_root) ? {
324+ destdir
325+ } else {
326+ let esp_device = self
327+ . get_esp_device ( )
328+ . ok_or_else ( || anyhow:: anyhow!( "Failed to find ESP device" ) ) ?;
329+ let esp_device = esp_device. to_str ( ) . unwrap ( ) ;
330+ self . ensure_mounted_esp ( dest_root, esp_device) ?
331+ } ;
302332
303- let destd = & openat:: Dir :: open ( destdir)
333+ let destd = & openat:: Dir :: open ( & destdir)
304334 . with_context ( || format ! ( "opening dest dir {}" , destdir. display( ) ) ) ?;
305335 validate_esp ( destd) ?;
306336
@@ -339,12 +369,25 @@ impl Component for Efi {
339369 . context ( "opening update dir" ) ?;
340370 let updatef = filetree:: FileTree :: new_from_dir ( & updated) . context ( "reading update dir" ) ?;
341371 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" ) ?;
372+ let esp_devices = self
373+ . get_esp_devices ( )
374+ . context ( "get esp devices when running update" ) ?;
375+ let sysroot = sysroot. recover_path ( ) ?;
376+
377+ for esp in esp_devices {
378+ let dest_path = if let Some ( dest_path) = self . check_mounted_esp ( & sysroot) ? {
379+ dest_path. join ( "EFI" )
380+ } else {
381+ self . ensure_mounted_esp ( & sysroot, & esp) ?. join ( "EFI" )
382+ } ;
383+
384+ let destdir = openat:: Dir :: open ( & dest_path) . context ( "opening EFI dir" ) ?;
385+ validate_esp ( & destdir) ?;
386+ log:: trace!( "applying diff: {}" , & diff) ;
387+ filetree:: apply_diff ( & updated, & destdir, & diff, None )
388+ . context ( "applying filesystem changes" ) ?;
389+ self . unmount ( ) . context ( "unmount after update" ) ?;
390+ }
348391 let adopted_from = None ;
349392 Ok ( InstalledContent {
350393 meta : updatemeta,
@@ -392,24 +435,37 @@ impl Component for Efi {
392435 }
393436
394437 fn validate ( & self , current : & InstalledContent ) -> Result < ValidationResult > {
395- if !is_efi_booted ( ) ? && self . get_esp_device ( ) . is_none ( ) {
438+ let esp_devices = self . get_esp_devices ( ) ;
439+ if !is_efi_booted ( ) ? && esp_devices. is_none ( ) {
396440 return Ok ( ValidationResult :: Skip ) ;
397441 }
398442 let currentf = current
399443 . filetree
400444 . as_ref ( )
401445 . 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) ?;
446+
405447 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) ) ;
448+ let esps = esp_devices. ok_or_else ( || anyhow:: anyhow!( "No esp device found!" ) ) ?;
449+ let dest_root = Path :: new ( "/" ) ;
450+ for esp_dev in esps. iter ( ) {
451+ let dest_path = if let Some ( dest_path) = self . check_mounted_esp ( dest_root) ? {
452+ dest_path. join ( "EFI" )
453+ } else {
454+ self . ensure_mounted_esp ( dest_root, & esp_dev) ?. join ( "EFI" )
455+ } ;
456+
457+ let efidir = openat:: Dir :: open ( dest_path. as_path ( ) ) ?;
458+ let diff = currentf. relative_diff_to ( & efidir) ?;
459+
460+ for f in diff. changes . iter ( ) {
461+ errs. push ( format ! ( "Changed: {}" , f) ) ;
462+ }
463+ for f in diff. removals . iter ( ) {
464+ errs. push ( format ! ( "Removed: {}" , f) ) ;
465+ }
466+ assert_eq ! ( diff. additions. len( ) , 0 ) ;
467+ self . unmount ( ) . context ( "unmount after validate" ) ?;
411468 }
412- assert_eq ! ( diff. additions. len( ) , 0 ) ;
413469 if !errs. is_empty ( ) {
414470 Ok ( ValidationResult :: Errors ( errs) )
415471 } else {
0 commit comments