@@ -99,6 +99,8 @@ use bootc_mount::{inspect_filesystem, Filesystem};
99
99
100
100
/// The toplevel boot directory
101
101
const BOOT : & str = "boot" ;
102
+ /// The EFI Linux directory
103
+ const EFI_LINUX : & str = "EFI/Linux" ;
102
104
/// Directory for transient runtime state
103
105
#[ cfg( feature = "install-to-disk" ) ]
104
106
const RUN_BOOTC : & str = "/run/bootc" ;
@@ -1715,7 +1717,7 @@ pub(crate) fn setup_composefs_bls_boot(
1715
1717
) -> Result < String > {
1716
1718
let id_hex = id. to_hex ( ) ;
1717
1719
1718
- let ( root_path , cmdline_refs) = match setup_type {
1720
+ let ( esp_device , cmdline_refs) = match setup_type {
1719
1721
BootSetupType :: Setup ( ( root_setup, state) ) => {
1720
1722
// root_setup.kargs has [root=UUID=<UUID>, "rw"]
1721
1723
let mut cmdline_options = String :: from ( root_setup. kargs . join ( " " ) ) ;
@@ -1729,23 +1731,53 @@ pub(crate) fn setup_composefs_bls_boot(
1729
1731
}
1730
1732
} ;
1731
1733
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)
1733
1743
}
1734
1744
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
+ }
1744
1765
} ;
1745
1766
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
+
1747
1777
let is_upgrade = matches ! ( setup_type, BootSetupType :: Upgrade ) ;
1748
1778
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" ) ) ?;
1749
1781
let ( bls_config, boot_digest) = match & entry {
1750
1782
ComposefsBootEntry :: Type1 ( ..) => unimplemented ! ( ) ,
1751
1783
ComposefsBootEntry :: Type2 ( ..) => unimplemented ! ( ) ,
@@ -1759,16 +1791,16 @@ pub(crate) fn setup_composefs_bls_boot(
1759
1791
bls_config. title = Some ( id_hex. clone ( ) ) ;
1760
1792
bls_config. sort_key = Some ( "1" . into ( ) ) ;
1761
1793
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" ) ] ;
1764
1796
bls_config. options = Some ( cmdline_refs) ;
1765
1797
bls_config. extra = HashMap :: new ( ) ;
1766
1798
1767
1799
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" ) ] ;
1770
1802
} 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) ?;
1772
1804
}
1773
1805
1774
1806
( bls_config, boot_digest)
@@ -1781,43 +1813,55 @@ pub(crate) fn setup_composefs_bls_boot(
1781
1813
1782
1814
// This will be atomically renamed to 'loader/entries' on shutdown/reboot
1783
1815
(
1784
- boot_dir . join ( format ! ( "loader/{STAGED_BOOT_LOADER_ENTRIES}" ) ) ,
1816
+ mounted_efi . join ( format ! ( "loader/{STAGED_BOOT_LOADER_ENTRIES}" ) ) ,
1785
1817
Some ( booted_bls) ,
1786
1818
)
1787
1819
} else {
1788
- ( boot_dir. join ( format ! ( "loader/{BOOT_LOADER_ENTRIES}" ) ) , None )
1820
+ (
1821
+ mounted_efi. join ( format ! ( "loader/{BOOT_LOADER_ENTRIES}" ) ) ,
1822
+ None ,
1823
+ )
1789
1824
} ;
1790
1825
1791
1826
create_dir_all ( & entries_path) . with_context ( || format ! ( "Creating {:?}" , entries_path) ) ?;
1792
1827
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:?}" ) ) ?;
1805
1833
1806
- if let Some ( booted_bls) = booted_bls {
1807
1834
loader_entries_dir. atomic_write (
1808
1835
// SAFETY: We set sort_key above
1809
1836
format ! (
1810
1837
"bootc-composefs-{}.conf" ,
1811
- booted_bls . sort_key. as_ref( ) . unwrap( )
1838
+ bls_config . sort_key. as_ref( ) . unwrap( )
1812
1839
) ,
1813
- booted_bls . to_string ( ) . as_bytes ( ) ,
1840
+ bls_config . to_string ( ) . as_bytes ( ) ,
1814
1841
) ?;
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" ) ?;
1815
1858
}
1816
1859
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" ) ?;
1821
1865
1822
1866
Ok ( boot_digest)
1823
1867
}
@@ -1892,13 +1936,12 @@ pub(crate) fn setup_composefs_uki_boot(
1892
1936
}
1893
1937
} ;
1894
1938
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 ( ) ;
1899
1942
1900
1943
Task :: new ( "Mounting ESP" , "mount" )
1901
- . args ( [ & PathBuf :: from ( & esp_device) , & mounted_esp . clone ( ) ] )
1944
+ . args ( [ & PathBuf :: from ( & esp_device) , & mounted_efi . clone ( ) ] )
1902
1945
. run ( ) ?;
1903
1946
1904
1947
let boot_label = match entry {
@@ -1940,7 +1983,7 @@ pub(crate) fn setup_composefs_uki_boot(
1940
1983
}
1941
1984
1942
1985
// 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 ) ;
1944
1987
create_dir_all ( & efi_linux_path) . context ( "Creating EFI/Linux" ) ?;
1945
1988
1946
1989
let efi_linux =
@@ -1962,16 +2005,11 @@ pub(crate) fn setup_composefs_uki_boot(
1962
2005
}
1963
2006
} ;
1964
2007
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" ) ?;
1975
2013
1976
2014
let boot_dir = root_path. join ( "boot" ) ;
1977
2015
create_dir_all ( & boot_dir) . context ( "Failed to create boot dir" ) ?;
0 commit comments