@@ -94,7 +94,7 @@ use crate::lsm;
9494use crate :: parsers:: bls_config:: { parse_bls_config, BLSConfig } ;
9595use crate :: parsers:: grub_menuconfig:: MenuEntry ;
9696use crate :: progress_jsonl:: ProgressWriter ;
97- use crate :: spec:: ImageReference ;
97+ use crate :: spec:: { Bootloader , Host , ImageReference } ;
9898use crate :: store:: Storage ;
9999use crate :: task:: Task ;
100100use crate :: utils:: { path_relative_to, sigpolicy_from_opt} ;
@@ -119,7 +119,7 @@ const OSTREE_COMPOSEFS_SUPER: &str = ".ostree.cfs";
119119/// The mount path for selinux
120120const SELINUXFS : & str = "/sys/fs/selinux" ;
121121/// The mount path for uefi
122- const EFIVARFS : & str = "/sys/firmware/efi/efivars" ;
122+ pub ( crate ) const EFIVARFS : & str = "/sys/firmware/efi/efivars" ;
123123pub ( crate ) const ARCH_USES_EFI : bool = cfg ! ( any( target_arch = "x86_64" , target_arch = "aarch64" ) ) ;
124124pub ( crate ) const ESP_GUID : & str = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" ;
125125pub ( crate ) const DPS_UUID : & str = "6523f8ae-3eb1-4e2a-a05a-18b695ae656f" ;
@@ -311,6 +311,10 @@ pub(crate) struct InstallComposefsOpts {
311311 #[ clap( long, default_value_t) ]
312312 #[ serde( default ) ]
313313 pub ( crate ) insecure : bool ,
314+
315+ #[ clap( long, default_value_t) ]
316+ #[ serde( default ) ]
317+ pub ( crate ) bootloader : Bootloader ,
314318}
315319
316320#[ cfg( feature = "install-to-disk" ) ]
@@ -1581,7 +1585,7 @@ pub(crate) enum BootSetupType<'a> {
15811585 /// For initial setup, i.e. install to-disk
15821586 Setup ( ( & ' a RootSetup , & ' a State , & ' a FileSystem < Sha256HashValue > ) ) ,
15831587 /// For `bootc upgrade`
1584- Upgrade ( & ' a FileSystem < Sha256HashValue > ) ,
1588+ Upgrade ( ( & ' a FileSystem < Sha256HashValue > , & ' a Host ) ) ,
15851589}
15861590
15871591/// Compute SHA256Sum of VMlinuz + Initrd
@@ -1707,6 +1711,18 @@ fn write_bls_boot_entries_to_disk(
17071711 Ok ( ( ) )
17081712}
17091713
1714+ struct BLSEntryPath < ' a > {
1715+ /// Where to write vmlinuz/initrd
1716+ entries_path : Utf8PathBuf ,
1717+ /// The absolute path, with reference to the partition's root, where the vmlinuz/initrd are written to
1718+ /// We need this as when installing, the mounted path will not
1719+ abs_entries_path : & ' a str ,
1720+ /// Where to write the .conf files
1721+ config_path : Utf8PathBuf ,
1722+ /// If we mounted EFI, the target path
1723+ mount_path : Option < Utf8PathBuf > ,
1724+ }
1725+
17101726/// Sets up and writes BLS entries and binaries (VMLinuz + Initrd) to disk
17111727///
17121728/// # Returns
@@ -1721,7 +1737,7 @@ pub(crate) fn setup_composefs_bls_boot(
17211737) -> Result < String > {
17221738 let id_hex = id. to_hex ( ) ;
17231739
1724- let ( esp_device, cmdline_refs, fs) = match setup_type {
1740+ let ( root_path , esp_device, cmdline_refs, fs, bootloader ) = match setup_type {
17251741 BootSetupType :: Setup ( ( root_setup, state, fs) ) => {
17261742 // root_setup.kargs has [root=UUID=<UUID>, "rw"]
17271743 let mut cmdline_options = String :: from ( root_setup. kargs . join ( " " ) ) ;
@@ -1743,10 +1759,20 @@ pub(crate) fn setup_composefs_bls_boot(
17431759 . find ( |p| p. parttype . as_str ( ) == ESP_GUID )
17441760 . ok_or_else ( || anyhow:: anyhow!( "ESP partition not found" ) ) ?;
17451761
1746- ( esp_part. node . clone ( ) , cmdline_options, fs)
1762+ (
1763+ root_setup. physical_root_path . clone ( ) ,
1764+ esp_part. node . clone ( ) ,
1765+ cmdline_options,
1766+ fs,
1767+ state
1768+ . composefs_options
1769+ . as_ref ( )
1770+ . map ( |opts| opts. bootloader . clone ( ) )
1771+ . unwrap_or ( Bootloader :: default ( ) ) ,
1772+ )
17471773 }
17481774
1749- BootSetupType :: Upgrade ( fs ) => {
1775+ BootSetupType :: Upgrade ( ( fs , host ) ) => {
17501776 let sysroot = Utf8PathBuf :: from ( "/sysroot" ) ;
17511777
17521778 let fsinfo = inspect_filesystem ( & sysroot) ?;
@@ -1756,7 +1782,10 @@ pub(crate) fn setup_composefs_bls_boot(
17561782 anyhow:: bail!( "Could not find parent device for mountpoint /sysroot" ) ;
17571783 } ;
17581784
1785+ let bootloader = host. require_composefs_booted ( ) ?. bootloader . clone ( ) ;
1786+
17591787 (
1788+ Utf8PathBuf :: from ( "/sysroot" ) ,
17601789 get_esp_partition ( & parent) ?. 0 ,
17611790 vec ! [
17621791 format!( "root=UUID={DPS_UUID}" ) ,
@@ -1765,24 +1794,51 @@ pub(crate) fn setup_composefs_bls_boot(
17651794 ]
17661795 . join ( " " ) ,
17671796 fs,
1797+ bootloader,
17681798 )
17691799 }
17701800 } ;
17711801
1772- let temp_efi_dir = tempfile:: tempdir ( )
1773- . map_err ( |e| anyhow:: anyhow!( "Failed to create temporary directory for EFI mount: {e}" ) ) ?;
1774- let mounted_efi = temp_efi_dir. path ( ) . to_path_buf ( ) ;
1802+ let is_upgrade = matches ! ( setup_type, BootSetupType :: Upgrade ( ..) ) ;
17751803
1776- Command :: new ( "mount" )
1777- . args ( [ & PathBuf :: from ( & esp_device) , & mounted_efi] )
1778- . log_debug ( )
1779- . run_inherited_with_cmd_context ( )
1780- . context ( "Mounting EFI" ) ?;
1804+ let ( entry_paths, _tmpdir_guard) = match bootloader {
1805+ Bootloader :: Grub => (
1806+ BLSEntryPath {
1807+ entries_path : root_path. join ( "boot" ) ,
1808+ config_path : root_path. join ( "boot" ) ,
1809+ abs_entries_path : "boot" ,
1810+ mount_path : None ,
1811+ } ,
1812+ None ,
1813+ ) ,
17811814
1782- let is_upgrade = matches ! ( setup_type, BootSetupType :: Upgrade ( ..) ) ;
1815+ Bootloader :: Systemd => {
1816+ let temp_efi_dir = tempfile:: tempdir ( ) . map_err ( |e| {
1817+ anyhow:: anyhow!( "Failed to create temporary directory for EFI mount: {e}" )
1818+ } ) ?;
1819+
1820+ let mounted_efi = Utf8PathBuf :: from_path_buf ( temp_efi_dir. path ( ) . to_path_buf ( ) )
1821+ . map_err ( |_| anyhow:: anyhow!( "EFI dir is not valid UTF-8" ) ) ?;
17831822
1784- let efi_dir = Utf8PathBuf :: from_path_buf ( mounted_efi. join ( EFI_LINUX ) )
1785- . map_err ( |_| anyhow:: anyhow!( "EFI dir is not valid UTF-8" ) ) ?;
1823+ Command :: new ( "mount" )
1824+ . args ( [ & PathBuf :: from ( & esp_device) , mounted_efi. as_std_path ( ) ] )
1825+ . log_debug ( )
1826+ . run_inherited_with_cmd_context ( )
1827+ . context ( "Mounting EFI" ) ?;
1828+
1829+ let efi_linux_dir = mounted_efi. join ( EFI_LINUX ) ;
1830+
1831+ (
1832+ BLSEntryPath {
1833+ entries_path : efi_linux_dir,
1834+ config_path : mounted_efi. clone ( ) ,
1835+ abs_entries_path : EFI_LINUX ,
1836+ mount_path : Some ( mounted_efi) ,
1837+ } ,
1838+ Some ( temp_efi_dir) ,
1839+ )
1840+ }
1841+ } ;
17861842
17871843 let ( bls_config, boot_digest) = match & entry {
17881844 ComposefsBootEntry :: Type1 ( ..) => unimplemented ! ( ) ,
@@ -1831,44 +1887,66 @@ pub(crate) fn setup_composefs_bls_boot(
18311887 . with_title ( id_hex. clone ( ) )
18321888 . with_sort_key ( default_sort_key. into ( ) )
18331889 . with_version ( version. unwrap_or ( default_sort_key. into ( ) ) )
1834- . with_linux ( format ! ( "/{EFI_LINUX}/{id_hex}/vmlinuz" ) )
1835- . with_initrd ( vec ! [ format!( "/{EFI_LINUX}/{id_hex}/initrd" ) ] )
1890+ . with_linux ( format ! (
1891+ "/{}/{id_hex}/vmlinuz" ,
1892+ entry_paths. abs_entries_path
1893+ ) )
1894+ . with_initrd ( vec ! [ format!(
1895+ "/{}/{id_hex}/initrd" ,
1896+ entry_paths. abs_entries_path
1897+ ) ] )
18361898 . with_options ( cmdline_refs) ;
18371899
18381900 if let Some ( symlink_to) = find_vmlinuz_initrd_duplicates ( & boot_digest) ? {
1839- bls_config. linux = format ! ( "/{EFI_LINUX}/{symlink_to}/vmlinuz" ) ;
1840- bls_config. initrd = vec ! [ format!( "/{EFI_LINUX}/{symlink_to}/initrd" ) ] ;
1901+ bls_config. linux =
1902+ format ! ( "/{}/{symlink_to}/vmlinuz" , entry_paths. abs_entries_path) ;
1903+
1904+ bls_config. initrd = vec ! [ format!(
1905+ "/{}/{symlink_to}/initrd" ,
1906+ entry_paths. abs_entries_path
1907+ ) ] ;
18411908 } else {
1842- write_bls_boot_entries_to_disk ( & efi_dir, id, usr_lib_modules_vmlinuz, & repo) ?;
1909+ write_bls_boot_entries_to_disk (
1910+ & entry_paths. entries_path ,
1911+ id,
1912+ usr_lib_modules_vmlinuz,
1913+ & repo,
1914+ ) ?;
18431915 }
18441916
18451917 ( bls_config, boot_digest)
18461918 }
18471919 } ;
18481920
1849- let ( entries_path , booted_bls) = if is_upgrade {
1921+ let ( config_path , booted_bls) = if is_upgrade {
18501922 let mut booted_bls = get_booted_bls ( ) ?;
18511923 booted_bls. sort_key = Some ( "0" . into ( ) ) ; // entries are sorted by their filename in reverse order
18521924
18531925 // This will be atomically renamed to 'loader/entries' on shutdown/reboot
18541926 (
1855- mounted_efi. join ( format ! ( "loader/{STAGED_BOOT_LOADER_ENTRIES}" ) ) ,
1927+ entry_paths
1928+ . config_path
1929+ . join ( "loader" )
1930+ . join ( STAGED_BOOT_LOADER_ENTRIES ) ,
18561931 Some ( booted_bls) ,
18571932 )
18581933 } else {
18591934 (
1860- mounted_efi. join ( format ! ( "loader/{BOOT_LOADER_ENTRIES}" ) ) ,
1935+ entry_paths
1936+ . config_path
1937+ . join ( "loader" )
1938+ . join ( BOOT_LOADER_ENTRIES ) ,
18611939 None ,
18621940 )
18631941 } ;
18641942
1865- create_dir_all ( & entries_path ) . with_context ( || format ! ( "Creating {:?}" , entries_path ) ) ?;
1943+ create_dir_all ( & config_path ) . with_context ( || format ! ( "Creating {:?}" , config_path ) ) ?;
18661944
18671945 // Scope to allow for proper unmounting
18681946 {
18691947 let loader_entries_dir =
1870- cap_std:: fs:: Dir :: open_ambient_dir ( & entries_path , cap_std:: ambient_authority ( ) )
1871- . with_context ( || format ! ( "Opening {entries_path :?}" ) ) ?;
1948+ cap_std:: fs:: Dir :: open_ambient_dir ( & config_path , cap_std:: ambient_authority ( ) )
1949+ . with_context ( || format ! ( "Opening {config_path :?}" ) ) ?;
18721950
18731951 loader_entries_dir. atomic_write (
18741952 // SAFETY: We set sort_key above
@@ -1893,14 +1971,17 @@ pub(crate) fn setup_composefs_bls_boot(
18931971 let owned_loader_entries_fd = loader_entries_dir
18941972 . reopen_as_ownedfd ( )
18951973 . context ( "Reopening as owned fd" ) ?;
1974+
18961975 rustix:: fs:: fsync ( owned_loader_entries_fd) . context ( "fsync" ) ?;
18971976 }
18981977
1899- Command :: new ( "umount" )
1900- . arg ( & mounted_efi)
1901- . log_debug ( )
1902- . run_inherited_with_cmd_context ( )
1903- . context ( "Unmounting EFI" ) ?;
1978+ if let Some ( mounted_efi) = entry_paths. mount_path {
1979+ Command :: new ( "umount" )
1980+ . arg ( mounted_efi)
1981+ . log_debug ( )
1982+ . run_inherited_with_cmd_context ( )
1983+ . context ( "Unmounting EFI" ) ?;
1984+ }
19041985
19051986 Ok ( boot_digest)
19061987}
0 commit comments