@@ -99,6 +99,8 @@ use bootc_mount::{inspect_filesystem, Filesystem};
9999
100100/// The toplevel boot directory
101101const BOOT : & str = "boot" ;
102+ /// The EFI Linux directory
103+ const EFI_LINUX : & str = "EFI/Linux" ;
102104/// Directory for transient runtime state
103105#[ cfg( feature = "install-to-disk" ) ]
104106const RUN_BOOTC : & str = "/run/bootc" ;
@@ -1715,7 +1717,7 @@ pub(crate) fn setup_composefs_bls_boot(
17151717) -> Result < String > {
17161718 let id_hex = id. to_hex ( ) ;
17171719
1718- let ( root_path , cmdline_refs) = match setup_type {
1720+ let ( esp_device , cmdline_refs) = match setup_type {
17191721 BootSetupType :: Setup ( ( root_setup, state) ) => {
17201722 // root_setup.kargs has [root=UUID=<UUID>, "rw"]
17211723 let mut cmdline_options = String :: from ( root_setup. kargs . join ( " " ) ) ;
@@ -1729,23 +1731,53 @@ pub(crate) fn setup_composefs_bls_boot(
17291731 }
17301732 } ;
17311733
1732- ( root_setup. physical_root_path . clone ( ) , cmdline_options)
1734+ // Locate ESP partition device
1735+ let esp_part = root_setup
1736+ . device_info
1737+ . partitions
1738+ . iter ( )
1739+ . find ( |p| p. parttype . as_str ( ) == ESP_GUID )
1740+ . ok_or_else ( || anyhow:: anyhow!( "ESP partition not found" ) ) ?;
1741+
1742+ ( esp_part. node . clone ( ) , cmdline_options)
17331743 }
17341744
1735- BootSetupType :: Upgrade => (
1736- Utf8PathBuf :: from ( "/sysroot" ) ,
1737- vec ! [
1738- format!( "root=UUID={DPS_UUID}" ) ,
1739- RW_KARG . to_string( ) ,
1740- format!( "{COMPOSEFS_CMDLINE}={id_hex}" ) ,
1741- ]
1742- . join ( " " ) ,
1743- ) ,
1745+ BootSetupType :: Upgrade => {
1746+ let sysroot = Utf8PathBuf :: from ( "/sysroot" ) ;
1747+
1748+ let fsinfo = inspect_filesystem ( & sysroot) ?;
1749+ let parent_devices = find_parent_devices ( & fsinfo. source ) ?;
1750+
1751+ let Some ( parent) = parent_devices. into_iter ( ) . next ( ) else {
1752+ anyhow:: bail!( "Could not find parent device for mountpoint /sysroot" ) ;
1753+ } ;
1754+
1755+ (
1756+ get_esp_partition ( & parent) ?. 0 ,
1757+ vec ! [
1758+ format!( "root=UUID={DPS_UUID}" ) ,
1759+ RW_KARG . to_string( ) ,
1760+ format!( "{COMPOSEFS_CMDLINE}={id_hex}" ) ,
1761+ ]
1762+ . join ( " " ) ,
1763+ )
1764+ }
17441765 } ;
17451766
1746- let boot_dir = root_path. join ( "boot" ) ;
1767+ let temp_efi_dir = tempfile:: tempdir ( )
1768+ . map_err ( |e| anyhow:: anyhow!( "Failed to create temporary directory for EFI mount: {e}" ) ) ?;
1769+ let mounted_efi = temp_efi_dir. path ( ) . to_path_buf ( ) ;
1770+
1771+ Command :: new ( "mount" )
1772+ . args ( [ & PathBuf :: from ( & esp_device) , & mounted_efi] )
1773+ . log_debug ( )
1774+ . run_inherited_with_cmd_context ( )
1775+ . context ( "Mounting EFI" ) ?;
1776+
17471777 let is_upgrade = matches ! ( setup_type, BootSetupType :: Upgrade ) ;
17481778
1779+ let efi_dir = Utf8PathBuf :: from_path_buf ( mounted_efi. join ( EFI_LINUX ) )
1780+ . map_err ( |_| anyhow:: anyhow!( "EFI dir is not valid UTF-8" ) ) ?;
17491781 let ( bls_config, boot_digest) = match & entry {
17501782 ComposefsBootEntry :: Type1 ( ..) => unimplemented ! ( ) ,
17511783 ComposefsBootEntry :: Type2 ( ..) => unimplemented ! ( ) ,
@@ -1759,16 +1791,16 @@ pub(crate) fn setup_composefs_bls_boot(
17591791 bls_config. title = Some ( id_hex. clone ( ) ) ;
17601792 bls_config. sort_key = Some ( "1" . into ( ) ) ;
17611793 bls_config. machine_id = None ;
1762- bls_config. linux = format ! ( "/boot /{id_hex}/vmlinuz" ) ;
1763- bls_config. initrd = vec ! [ format!( "/boot /{id_hex}/initrd" ) ] ;
1794+ bls_config. linux = format ! ( "/{EFI_LINUX} /{id_hex}/vmlinuz" ) ;
1795+ bls_config. initrd = vec ! [ format!( "/{EFI_LINUX} /{id_hex}/initrd" ) ] ;
17641796 bls_config. options = Some ( cmdline_refs) ;
17651797 bls_config. extra = HashMap :: new ( ) ;
17661798
17671799 if let Some ( symlink_to) = find_vmlinuz_initrd_duplicates ( & boot_digest) ? {
1768- bls_config. linux = format ! ( "/boot /{symlink_to}/vmlinuz" ) ;
1769- bls_config. initrd = vec ! [ format!( "/boot /{symlink_to}/initrd" ) ] ;
1800+ bls_config. linux = format ! ( "/{EFI_LINUX} /{symlink_to}/vmlinuz" ) ;
1801+ bls_config. initrd = vec ! [ format!( "/{EFI_LINUX} /{symlink_to}/initrd" ) ] ;
17701802 } else {
1771- write_bls_boot_entries_to_disk ( & boot_dir , id, usr_lib_modules_vmlinuz, & repo) ?;
1803+ write_bls_boot_entries_to_disk ( & efi_dir , id, usr_lib_modules_vmlinuz, & repo) ?;
17721804 }
17731805
17741806 ( bls_config, boot_digest)
@@ -1781,43 +1813,55 @@ pub(crate) fn setup_composefs_bls_boot(
17811813
17821814 // This will be atomically renamed to 'loader/entries' on shutdown/reboot
17831815 (
1784- boot_dir . join ( format ! ( "loader/{STAGED_BOOT_LOADER_ENTRIES}" ) ) ,
1816+ mounted_efi . join ( format ! ( "loader/{STAGED_BOOT_LOADER_ENTRIES}" ) ) ,
17851817 Some ( booted_bls) ,
17861818 )
17871819 } else {
1788- ( boot_dir. join ( format ! ( "loader/{BOOT_LOADER_ENTRIES}" ) ) , None )
1820+ (
1821+ mounted_efi. join ( format ! ( "loader/{BOOT_LOADER_ENTRIES}" ) ) ,
1822+ None ,
1823+ )
17891824 } ;
17901825
17911826 create_dir_all ( & entries_path) . with_context ( || format ! ( "Creating {:?}" , entries_path) ) ?;
17921827
1793- let loader_entries_dir =
1794- cap_std:: fs:: Dir :: open_ambient_dir ( & entries_path, cap_std:: ambient_authority ( ) )
1795- . with_context ( || format ! ( "Opening {entries_path}" ) ) ?;
1796-
1797- loader_entries_dir. atomic_write (
1798- // SAFETY: We set sort_key above
1799- format ! (
1800- "bootc-composefs-{}.conf" ,
1801- bls_config. sort_key. as_ref( ) . unwrap( )
1802- ) ,
1803- bls_config. to_string ( ) . as_bytes ( ) ,
1804- ) ?;
1828+ // Scope to allow for proper unmounting
1829+ {
1830+ let loader_entries_dir =
1831+ cap_std:: fs:: Dir :: open_ambient_dir ( & entries_path, cap_std:: ambient_authority ( ) )
1832+ . with_context ( || format ! ( "Opening {entries_path:?}" ) ) ?;
18051833
1806- if let Some ( booted_bls) = booted_bls {
18071834 loader_entries_dir. atomic_write (
18081835 // SAFETY: We set sort_key above
18091836 format ! (
18101837 "bootc-composefs-{}.conf" ,
1811- booted_bls . sort_key. as_ref( ) . unwrap( )
1838+ bls_config . sort_key. as_ref( ) . unwrap( )
18121839 ) ,
1813- booted_bls . to_string ( ) . as_bytes ( ) ,
1840+ bls_config . to_string ( ) . as_bytes ( ) ,
18141841 ) ?;
1842+
1843+ if let Some ( booted_bls) = booted_bls {
1844+ loader_entries_dir. atomic_write (
1845+ // SAFETY: We set sort_key above
1846+ format ! (
1847+ "bootc-composefs-{}.conf" ,
1848+ booted_bls. sort_key. as_ref( ) . unwrap( )
1849+ ) ,
1850+ booted_bls. to_string ( ) . as_bytes ( ) ,
1851+ ) ?;
1852+ }
1853+
1854+ let owned_loader_entries_fd = loader_entries_dir
1855+ . reopen_as_ownedfd ( )
1856+ . context ( "Reopening as owned fd" ) ?;
1857+ rustix:: fs:: fsync ( owned_loader_entries_fd) . context ( "fsync" ) ?;
18151858 }
18161859
1817- let owned_loader_entries_fd = loader_entries_dir
1818- . reopen_as_ownedfd ( )
1819- . context ( "Reopening as owned fd" ) ?;
1820- rustix:: fs:: fsync ( owned_loader_entries_fd) . context ( "fsync" ) ?;
1860+ Command :: new ( "umount" )
1861+ . arg ( & mounted_efi)
1862+ . log_debug ( )
1863+ . run_inherited_with_cmd_context ( )
1864+ . context ( "Unmounting EFI" ) ?;
18211865
18221866 Ok ( boot_digest)
18231867}
@@ -1892,13 +1936,12 @@ pub(crate) fn setup_composefs_uki_boot(
18921936 }
18931937 } ;
18941938
1895- let mounted_esp: PathBuf = root_path. join ( "esp" ) . into ( ) ;
1896- let esp_mount_point_existed = mounted_esp. exists ( ) ;
1897-
1898- create_dir_all ( & mounted_esp) . context ( "Failed to create dir {mounted_esp:?}" ) ?;
1939+ let temp_efi_dir = tempfile:: tempdir ( )
1940+ . map_err ( |e| anyhow:: anyhow!( "Failed to create temporary directory for EFI mount: {e}" ) ) ?;
1941+ let mounted_efi = temp_efi_dir. path ( ) . to_path_buf ( ) ;
18991942
19001943 Task :: new ( "Mounting ESP" , "mount" )
1901- . args ( [ & PathBuf :: from ( & esp_device) , & mounted_esp . clone ( ) ] )
1944+ . args ( [ & PathBuf :: from ( & esp_device) , & mounted_efi . clone ( ) ] )
19021945 . run ( ) ?;
19031946
19041947 let boot_label = match entry {
@@ -1940,7 +1983,7 @@ pub(crate) fn setup_composefs_uki_boot(
19401983 }
19411984
19421985 // Write the UKI to ESP
1943- let efi_linux_path = mounted_esp . join ( "EFI/Linux" ) ;
1986+ let efi_linux_path = mounted_efi . join ( EFI_LINUX ) ;
19441987 create_dir_all ( & efi_linux_path) . context ( "Creating EFI/Linux" ) ?;
19451988
19461989 let efi_linux =
@@ -1962,16 +2005,11 @@ pub(crate) fn setup_composefs_uki_boot(
19622005 }
19632006 } ;
19642007
1965- Task :: new ( "Unmounting ESP" , "umount" )
1966- . arg ( & mounted_esp)
1967- . run ( ) ?;
1968-
1969- if !esp_mount_point_existed {
1970- // This shouldn't be a fatal error
1971- if let Err ( e) = std:: fs:: remove_dir ( & mounted_esp) {
1972- tracing:: error!( "Failed to remove mount point '{mounted_esp:?}': {e}" ) ;
1973- }
1974- }
2008+ Command :: new ( "umount" )
2009+ . arg ( & mounted_efi)
2010+ . log_debug ( )
2011+ . run_inherited_with_cmd_context ( )
2012+ . context ( "Unmounting ESP" ) ?;
19752013
19762014 let boot_dir = root_path. join ( "boot" ) ;
19772015 create_dir_all ( & boot_dir) . context ( "Failed to create boot dir" ) ?;
0 commit comments