@@ -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,6 @@ 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-
8261 fn get_esp_device ( & self ) -> Option < PathBuf > {
8362 let esp_devices = [ COREOS_ESP_PART_LABEL , ANACONDA_ESP_PART_LABEL ]
8463 . into_iter ( )
@@ -93,11 +72,25 @@ impl Efi {
9372 return esp_device;
9473 }
9574
96- pub ( crate ) fn ensure_mounted_esp ( & self , root : & Path ) -> Result < PathBuf > {
97- let mut mountpoint = self . mountpoint . borrow_mut ( ) ;
75+ fn get_all_esp_devices ( & self ) -> Option < Vec < String > > {
76+ let mut esp_devices = vec ! [ ] ;
77+ if let Some ( esp_device) = self . get_esp_device ( ) {
78+ esp_devices. push ( esp_device. to_string_lossy ( ) . into_owned ( ) ) ;
79+ } else {
80+ esp_devices = blockdev:: find_colocated_esps ( "/" ) . expect ( "get esp devices" ) ;
81+ } ;
82+ if !esp_devices. is_empty ( ) {
83+ return Some ( esp_devices) ;
84+ }
85+ return None ;
86+ }
87+
88+ fn check_existing_esp < P : AsRef < Path > > ( & self , root : P ) -> Result < Option < PathBuf > > {
89+ let mountpoint = self . mountpoint . borrow_mut ( ) ;
9890 if let Some ( mountpoint) = mountpoint. as_deref ( ) {
99- return Ok ( mountpoint. to_owned ( ) ) ;
91+ return Ok ( Some ( mountpoint. to_owned ( ) ) ) ;
10092 }
93+ let root = root. as_ref ( ) ;
10194 for & mnt in ESP_MOUNTS {
10295 let mnt = root. join ( mnt) ;
10396 if !mnt. exists ( ) {
@@ -109,13 +102,23 @@ impl Efi {
109102 continue ;
110103 }
111104 util:: ensure_writable_mount ( & mnt) ?;
112- log:: debug!( "Reusing existing {mnt:?}" ) ;
113- return Ok ( mnt) ;
105+ log:: debug!( "Reusing existing mount point {mnt:?}" ) ;
106+ return Ok ( Some ( mnt) ) ;
114107 }
108+ Ok ( None )
109+ }
115110
116- let esp_device = self
117- . get_esp_device ( )
118- . ok_or_else ( || anyhow:: anyhow!( "Failed to find ESP device" ) ) ?;
111+ pub ( crate ) fn ensure_mounted_esp < P : AsRef < Path > > (
112+ & self ,
113+ root : P ,
114+ esp_device : & str ,
115+ ) -> Result < PathBuf > {
116+ let mut mountpoint = self . mountpoint . borrow_mut ( ) ;
117+ if let Some ( mountpoint) = mountpoint. as_deref ( ) {
118+ return Ok ( mountpoint. to_owned ( ) ) ;
119+ }
120+
121+ let root = root. as_ref ( ) ;
119122 for & mnt in ESP_MOUNTS . iter ( ) {
120123 let mnt = root. join ( mnt) ;
121124 if !mnt. exists ( ) {
@@ -134,10 +137,9 @@ impl Efi {
134137 }
135138 Ok ( mountpoint. as_deref ( ) . unwrap ( ) . to_owned ( ) )
136139 }
137-
138140 fn unmount ( & self ) -> Result < ( ) > {
139141 if let Some ( mount) = self . mountpoint . borrow_mut ( ) . take ( ) {
140- let status = Command :: new ( "umount" ) . arg ( & mount) . status ( ) ?;
142+ let status = Command :: new ( "umount" ) . arg ( "-l" ) . arg ( & mount) . status ( ) ?;
141143 if !status. success ( ) {
142144 anyhow:: bail!( "Failed to unmount {mount:?}: {status:?}" ) ;
143145 }
@@ -245,8 +247,7 @@ impl Component for Efi {
245247 }
246248
247249 fn query_adopt ( & self ) -> Result < Option < Adoptable > > {
248- let esp = self . open_esp_optional ( ) ?;
249- if esp. is_none ( ) {
250+ if self . get_all_esp_devices ( ) . is_none ( ) {
250251 log:: trace!( "No ESP detected" ) ;
251252 return Ok ( None ) ;
252253 } ;
@@ -269,16 +270,32 @@ impl Component for Efi {
269270 anyhow:: bail!( "Failed to find adoptable system" )
270271 } ;
271272
272- let esp = self . open_esp ( ) ?;
273- validate_esp ( & esp) ?;
274273 let updated = sysroot
275274 . sub_dir ( & component_updatedirname ( self ) )
276275 . context ( "opening update dir" ) ?;
277276 let updatef = filetree:: FileTree :: new_from_dir ( & updated) . context ( "reading update dir" ) ?;
278- // For adoption, we should only touch files that we know about.
279- let diff = updatef. relative_diff_to ( & esp) ?;
280- log:: trace!( "applying adoption diff: {}" , & diff) ;
281- filetree:: apply_diff ( & updated, & esp, & diff, None ) . context ( "applying filesystem changes" ) ?;
277+ let esp_devices = self
278+ . get_all_esp_devices ( )
279+ . expect ( "get esp devices before adopt" ) ;
280+ let sysroot = sysroot. recover_path ( ) ?;
281+
282+ for esp_dev in esp_devices {
283+ let dest_path = if let Some ( dest_path) = self . check_existing_esp ( & sysroot) ? {
284+ dest_path. join ( "EFI" )
285+ } else {
286+ self . ensure_mounted_esp ( & sysroot, & esp_dev) ?. join ( "EFI" )
287+ } ;
288+
289+ let esp = openat:: Dir :: open ( & dest_path) . context ( "opening EFI dir" ) ?;
290+ validate_esp ( & esp) ?;
291+
292+ // For adoption, we should only touch files that we know about.
293+ let diff = updatef. relative_diff_to ( & esp) ?;
294+ log:: trace!( "applying adoption diff: {}" , & diff) ;
295+ filetree:: apply_diff ( & updated, & esp, & diff, None )
296+ . context ( "applying filesystem changes" ) ?;
297+ self . unmount ( ) . context ( "unmount after adopt" ) ?;
298+ }
282299 Ok ( InstalledContent {
283300 meta : updatemeta. clone ( ) ,
284301 filetree : Some ( updatef) ,
@@ -300,9 +317,18 @@ impl Component for Efi {
300317 log:: debug!( "Found metadata {}" , meta. version) ;
301318 let srcdir_name = component_updatedirname ( self ) ;
302319 let ft = crate :: filetree:: FileTree :: new_from_dir ( & src_root. sub_dir ( & srcdir_name) ?) ?;
303- let destdir = & self . ensure_mounted_esp ( Path :: new ( dest_root) ) ?;
304320
305- let destd = & openat:: Dir :: open ( destdir)
321+ let destdir = if let Some ( destdir) = self . check_existing_esp ( dest_root) ? {
322+ destdir
323+ } else {
324+ let esp_device = self
325+ . get_esp_device ( )
326+ . ok_or_else ( || anyhow:: anyhow!( "Failed to find ESP device" ) ) ?;
327+ let esp_device = esp_device. to_str ( ) . unwrap ( ) ;
328+ self . ensure_mounted_esp ( dest_root, esp_device) ?
329+ } ;
330+
331+ let destd = & openat:: Dir :: open ( & destdir)
306332 . with_context ( || format ! ( "opening dest dir {}" , destdir. display( ) ) ) ?;
307333 validate_esp ( destd) ?;
308334
@@ -344,12 +370,25 @@ impl Component for Efi {
344370 . context ( "opening update dir" ) ?;
345371 let updatef = filetree:: FileTree :: new_from_dir ( & updated) . context ( "reading update dir" ) ?;
346372 let diff = currentf. diff ( & updatef) ?;
347- self . ensure_mounted_esp ( Path :: new ( "/" ) ) ?;
348- let destdir = self . open_esp ( ) . context ( "opening EFI dir" ) ?;
349- validate_esp ( & destdir) ?;
350- log:: trace!( "applying diff: {}" , & diff) ;
351- filetree:: apply_diff ( & updated, & destdir, & diff, None )
352- . context ( "applying filesystem changes" ) ?;
373+ let esp_devices = self
374+ . get_all_esp_devices ( )
375+ . context ( "get esp devices when running update" ) ?;
376+ let sysroot = sysroot. recover_path ( ) ?;
377+
378+ for esp in esp_devices {
379+ let dest_path = if let Some ( dest_path) = self . check_existing_esp ( & sysroot) ? {
380+ dest_path. join ( "EFI" )
381+ } else {
382+ self . ensure_mounted_esp ( & sysroot, & esp) ?. join ( "EFI" )
383+ } ;
384+
385+ let destdir = openat:: Dir :: open ( & dest_path) . context ( "opening EFI dir" ) ?;
386+ validate_esp ( & destdir) ?;
387+ log:: trace!( "applying diff: {}" , & diff) ;
388+ filetree:: apply_diff ( & updated, & destdir, & diff, None )
389+ . context ( "applying filesystem changes" ) ?;
390+ self . unmount ( ) . context ( "unmount after update" ) ?;
391+ }
353392 let adopted_from = None ;
354393 Ok ( InstalledContent {
355394 meta : updatemeta,
@@ -397,24 +436,36 @@ impl Component for Efi {
397436 }
398437
399438 fn validate ( & self , current : & InstalledContent ) -> Result < ValidationResult > {
400- if !is_efi_booted ( ) ? && self . get_esp_device ( ) . is_none ( ) {
439+ let esp_devices = self . get_all_esp_devices ( ) ;
440+ if !is_efi_booted ( ) ? && esp_devices. is_none ( ) {
401441 return Ok ( ValidationResult :: Skip ) ;
402442 }
403443 let currentf = current
404444 . filetree
405445 . as_ref ( )
406446 . ok_or_else ( || anyhow:: anyhow!( "No filetree for installed EFI found!" ) ) ?;
407- self . ensure_mounted_esp ( Path :: new ( "/" ) ) ?;
408- let efidir = self . open_esp ( ) ?;
409- let diff = currentf. relative_diff_to ( & efidir) ?;
410447 let mut errs = Vec :: new ( ) ;
411- for f in diff. changes . iter ( ) {
412- errs. push ( format ! ( "Changed: {}" , f) ) ;
413- }
414- for f in diff. removals . iter ( ) {
415- 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_existing_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" ) ?;
416468 }
417- assert_eq ! ( diff. additions. len( ) , 0 ) ;
418469 if !errs. is_empty ( ) {
419470 Ok ( ValidationResult :: Errors ( errs) )
420471 } else {
0 commit comments