@@ -98,6 +98,8 @@ use bootc_mount::{inspect_filesystem, Filesystem};
9898
9999/// The toplevel boot directory
100100const BOOT : & str = "boot" ;
101+ /// The EFI Linux directory
102+ const EFI_LINUX : & str = "EFI/Linux" ;
101103/// Directory for transient runtime state
102104#[ cfg( feature = "install-to-disk" ) ]
103105const RUN_BOOTC : & str = "/run/bootc" ;
@@ -1691,7 +1693,7 @@ pub(crate) fn setup_composefs_bls_boot(
16911693) -> Result < String > {
16921694 let id_hex = id. to_hex ( ) ;
16931695
1694- let ( root_path , cmdline_refs) = match setup_type {
1696+ let ( esp_device , cmdline_refs) = match setup_type {
16951697 BootSetupType :: Setup ( ( root_setup, state) ) => {
16961698 // root_setup.kargs has [root=UUID=<UUID>, "rw"]
16971699 let mut cmdline_options = String :: from ( root_setup. kargs . join ( " " ) ) ;
@@ -1705,23 +1707,53 @@ pub(crate) fn setup_composefs_bls_boot(
17051707 }
17061708 } ;
17071709
1708- ( root_setup. physical_root_path . clone ( ) , cmdline_options)
1710+ // Locate ESP partition device
1711+ let esp_part = root_setup
1712+ . device_info
1713+ . partitions
1714+ . iter ( )
1715+ . find ( |p| p. parttype . as_str ( ) == ESP_GUID )
1716+ . ok_or_else ( || anyhow:: anyhow!( "ESP partition not found" ) ) ?;
1717+
1718+ ( esp_part. node . clone ( ) , cmdline_options)
17091719 }
17101720
1711- BootSetupType :: Upgrade => (
1712- Utf8PathBuf :: from ( "/sysroot" ) ,
1713- vec ! [
1714- format!( "root=UUID={DPS_UUID}" ) ,
1715- RW_KARG . to_string( ) ,
1716- format!( "{COMPOSEFS_CMDLINE}={id_hex}" ) ,
1717- ]
1718- . join ( " " ) ,
1719- ) ,
1721+ BootSetupType :: Upgrade => {
1722+ let sysroot = Utf8PathBuf :: from ( "/sysroot" ) ;
1723+
1724+ let fsinfo = inspect_filesystem ( & sysroot) ?;
1725+ let parent_devices = find_parent_devices ( & fsinfo. source ) ?;
1726+
1727+ let Some ( parent) = parent_devices. into_iter ( ) . next ( ) else {
1728+ anyhow:: bail!( "Could not find parent device for mountpoint /sysroot" ) ;
1729+ } ;
1730+
1731+ (
1732+ get_esp_partition ( & parent) ?. 0 ,
1733+ vec ! [
1734+ format!( "root=UUID={DPS_UUID}" ) ,
1735+ RW_KARG . to_string( ) ,
1736+ format!( "{COMPOSEFS_CMDLINE}={id_hex}" ) ,
1737+ ]
1738+ . join ( " " ) ,
1739+ )
1740+ }
17201741 } ;
17211742
1722- let boot_dir = root_path. join ( "boot" ) ;
1743+ let temp_efi_dir = tempfile:: tempdir ( )
1744+ . map_err ( |e| anyhow:: anyhow!( "Failed to create temporary directory for EFI mount: {e}" ) ) ?;
1745+ let mounted_efi = temp_efi_dir. path ( ) . to_path_buf ( ) ;
1746+
1747+ Command :: new ( "mount" )
1748+ . args ( [ & PathBuf :: from ( & esp_device) , & mounted_efi] )
1749+ . log_debug ( )
1750+ . run_inherited_with_cmd_context ( )
1751+ . context ( "Mounting EFI" ) ?;
1752+
17231753 let is_upgrade = matches ! ( setup_type, BootSetupType :: Upgrade ) ;
17241754
1755+ let efi_dir = Utf8PathBuf :: from_path_buf ( mounted_efi. join ( EFI_LINUX ) )
1756+ . map_err ( |_| anyhow:: anyhow!( "EFI dir is not valid UTF-8" ) ) ?;
17251757 let ( bls_config, boot_digest) = match & entry {
17261758 ComposefsBootEntry :: Type1 ( ..) => unimplemented ! ( ) ,
17271759 ComposefsBootEntry :: Type2 ( ..) => unimplemented ! ( ) ,
@@ -1735,16 +1767,16 @@ pub(crate) fn setup_composefs_bls_boot(
17351767 bls_config. title = Some ( id_hex. clone ( ) ) ;
17361768 bls_config. sort_key = Some ( "1" . into ( ) ) ;
17371769 bls_config. machine_id = None ;
1738- bls_config. linux = format ! ( "/boot /{id_hex}/vmlinuz" ) ;
1739- bls_config. initrd = vec ! [ format!( "/boot /{id_hex}/initrd" ) ] ;
1770+ bls_config. linux = format ! ( "/{EFI_LINUX} /{id_hex}/vmlinuz" ) ;
1771+ bls_config. initrd = vec ! [ format!( "/{EFI_LINUX} /{id_hex}/initrd" ) ] ;
17401772 bls_config. options = Some ( cmdline_refs) ;
17411773 bls_config. extra = HashMap :: new ( ) ;
17421774
17431775 if let Some ( symlink_to) = find_vmlinuz_initrd_duplicates ( & boot_digest) ? {
1744- bls_config. linux = format ! ( "/boot /{symlink_to}/vmlinuz" ) ;
1745- bls_config. initrd = vec ! [ format!( "/boot /{symlink_to}/initrd" ) ] ;
1776+ bls_config. linux = format ! ( "/{EFI_LINUX} /{symlink_to}/vmlinuz" ) ;
1777+ bls_config. initrd = vec ! [ format!( "/{EFI_LINUX} /{symlink_to}/initrd" ) ] ;
17461778 } else {
1747- write_bls_boot_entries_to_disk ( & boot_dir , id, usr_lib_modules_vmlinuz, & repo) ?;
1779+ write_bls_boot_entries_to_disk ( & efi_dir , id, usr_lib_modules_vmlinuz, & repo) ?;
17481780 }
17491781
17501782 ( bls_config, boot_digest)
@@ -1757,43 +1789,55 @@ pub(crate) fn setup_composefs_bls_boot(
17571789
17581790 // This will be atomically renamed to 'loader/entries' on shutdown/reboot
17591791 (
1760- boot_dir . join ( format ! ( "loader/{STAGED_BOOT_LOADER_ENTRIES}" ) ) ,
1792+ mounted_efi . join ( format ! ( "loader/{STAGED_BOOT_LOADER_ENTRIES}" ) ) ,
17611793 Some ( booted_bls) ,
17621794 )
17631795 } else {
1764- ( boot_dir. join ( format ! ( "loader/{BOOT_LOADER_ENTRIES}" ) ) , None )
1796+ (
1797+ mounted_efi. join ( format ! ( "loader/{BOOT_LOADER_ENTRIES}" ) ) ,
1798+ None ,
1799+ )
17651800 } ;
17661801
17671802 create_dir_all ( & entries_path) . with_context ( || format ! ( "Creating {:?}" , entries_path) ) ?;
17681803
1769- let loader_entries_dir =
1770- cap_std:: fs:: Dir :: open_ambient_dir ( & entries_path, cap_std:: ambient_authority ( ) )
1771- . with_context ( || format ! ( "Opening {entries_path}" ) ) ?;
1772-
1773- loader_entries_dir. atomic_write (
1774- // SAFETY: We set sort_key above
1775- format ! (
1776- "bootc-composefs-{}.conf" ,
1777- bls_config. sort_key. as_ref( ) . unwrap( )
1778- ) ,
1779- bls_config. to_string ( ) . as_bytes ( ) ,
1780- ) ?;
1804+ // Scope to allow for proper unmounting
1805+ {
1806+ let loader_entries_dir =
1807+ cap_std:: fs:: Dir :: open_ambient_dir ( & entries_path, cap_std:: ambient_authority ( ) )
1808+ . with_context ( || format ! ( "Opening {entries_path:?}" ) ) ?;
17811809
1782- if let Some ( booted_bls) = booted_bls {
17831810 loader_entries_dir. atomic_write (
17841811 // SAFETY: We set sort_key above
17851812 format ! (
17861813 "bootc-composefs-{}.conf" ,
1787- booted_bls . sort_key. as_ref( ) . unwrap( )
1814+ bls_config . sort_key. as_ref( ) . unwrap( )
17881815 ) ,
1789- booted_bls . to_string ( ) . as_bytes ( ) ,
1816+ bls_config . to_string ( ) . as_bytes ( ) ,
17901817 ) ?;
1818+
1819+ if let Some ( booted_bls) = booted_bls {
1820+ loader_entries_dir. atomic_write (
1821+ // SAFETY: We set sort_key above
1822+ format ! (
1823+ "bootc-composefs-{}.conf" ,
1824+ booted_bls. sort_key. as_ref( ) . unwrap( )
1825+ ) ,
1826+ booted_bls. to_string ( ) . as_bytes ( ) ,
1827+ ) ?;
1828+ }
1829+
1830+ let owned_loader_entries_fd = loader_entries_dir
1831+ . reopen_as_ownedfd ( )
1832+ . context ( "Reopening as owned fd" ) ?;
1833+ rustix:: fs:: fsync ( owned_loader_entries_fd) . context ( "fsync" ) ?;
17911834 }
17921835
1793- let owned_loader_entries_fd = loader_entries_dir
1794- . reopen_as_ownedfd ( )
1795- . context ( "Reopening as owned fd" ) ?;
1796- rustix:: fs:: fsync ( owned_loader_entries_fd) . context ( "fsync" ) ?;
1836+ Command :: new ( "umount" )
1837+ . arg ( & mounted_efi)
1838+ . log_debug ( )
1839+ . run_inherited_with_cmd_context ( )
1840+ . context ( "Unmounting EFI" ) ?;
17971841
17981842 Ok ( boot_digest)
17991843}
@@ -1868,13 +1912,12 @@ pub(crate) fn setup_composefs_uki_boot(
18681912 }
18691913 } ;
18701914
1871- let mounted_esp: PathBuf = root_path. join ( "esp" ) . into ( ) ;
1872- let esp_mount_point_existed = mounted_esp. exists ( ) ;
1873-
1874- create_dir_all ( & mounted_esp) . context ( "Failed to create dir {mounted_esp:?}" ) ?;
1915+ let temp_efi_dir = tempfile:: tempdir ( )
1916+ . map_err ( |e| anyhow:: anyhow!( "Failed to create temporary directory for EFI mount: {e}" ) ) ?;
1917+ let mounted_efi = temp_efi_dir. path ( ) . to_path_buf ( ) ;
18751918
18761919 Task :: new ( "Mounting ESP" , "mount" )
1877- . args ( [ & PathBuf :: from ( & esp_device) , & mounted_esp . clone ( ) ] )
1920+ . args ( [ & PathBuf :: from ( & esp_device) , & mounted_efi . clone ( ) ] )
18781921 . run ( ) ?;
18791922
18801923 let boot_label = match entry {
@@ -1916,7 +1959,7 @@ pub(crate) fn setup_composefs_uki_boot(
19161959 }
19171960
19181961 // Write the UKI to ESP
1919- let efi_linux_path = mounted_esp . join ( "EFI/Linux" ) ;
1962+ let efi_linux_path = mounted_efi . join ( EFI_LINUX ) ;
19201963 create_dir_all ( & efi_linux_path) . context ( "Creating EFI/Linux" ) ?;
19211964
19221965 let efi_linux =
@@ -1938,16 +1981,11 @@ pub(crate) fn setup_composefs_uki_boot(
19381981 }
19391982 } ;
19401983
1941- Task :: new ( "Unmounting ESP" , "umount" )
1942- . arg ( & mounted_esp)
1943- . run ( ) ?;
1944-
1945- if !esp_mount_point_existed {
1946- // This shouldn't be a fatal error
1947- if let Err ( e) = std:: fs:: remove_dir ( & mounted_esp) {
1948- tracing:: error!( "Failed to remove mount point '{mounted_esp:?}': {e}" ) ;
1949- }
1950- }
1984+ Command :: new ( "umount" )
1985+ . arg ( & mounted_efi)
1986+ . log_debug ( )
1987+ . run_inherited_with_cmd_context ( )
1988+ . context ( "Unmounting ESP" ) ?;
19511989
19521990 let boot_dir = root_path. join ( "boot" ) ;
19531991 create_dir_all ( & boot_dir) . context ( "Failed to create boot dir" ) ?;
0 commit comments