@@ -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} ;
@@ -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,17 @@ pub(crate) fn setup_composefs_bls_boot(
17561782 anyhow:: bail!( "Could not find parent device for mountpoint /sysroot" ) ;
17571783 } ;
17581784
1785+ // SAFETY: All of these will exist as we have checks prior to Upgrading
1786+ let bootloader = host
1787+ . status
1788+ . booted
1789+ . as_ref ( )
1790+ . and_then ( |b| b. composefs . as_ref ( ) )
1791+ . map ( |c| c. bootloader . clone ( ) )
1792+ . unwrap ( ) ;
1793+
17591794 (
1795+ Utf8PathBuf :: from ( "/sysroot" ) ,
17601796 get_esp_partition ( & parent) ?. 0 ,
17611797 vec ! [
17621798 format!( "root=UUID={DPS_UUID}" ) ,
@@ -1765,24 +1801,45 @@ pub(crate) fn setup_composefs_bls_boot(
17651801 ]
17661802 . join ( " " ) ,
17671803 fs,
1804+ bootloader,
17681805 )
17691806 }
17701807 } ;
17711808
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 ( ) ;
1809+ let is_upgrade = matches ! ( setup_type, BootSetupType :: Upgrade ( ..) ) ;
17751810
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" ) ?;
1811+ let entry_paths = match bootloader {
1812+ Bootloader :: Grub => BLSEntryPath {
1813+ entries_path : root_path. join ( "boot" ) ,
1814+ config_path : root_path. join ( "boot" ) ,
1815+ abs_entries_path : "boot" ,
1816+ mount_path : None ,
1817+ } ,
17811818
1782- let is_upgrade = matches ! ( setup_type, BootSetupType :: Upgrade ( ..) ) ;
1819+ Bootloader :: Systemd => {
1820+ let temp_efi_dir = tempfile:: tempdir ( ) . map_err ( |e| {
1821+ anyhow:: anyhow!( "Failed to create temporary directory for EFI mount: {e}" )
1822+ } ) ?;
1823+
1824+ let mounted_efi = Utf8PathBuf :: from_path_buf ( temp_efi_dir. path ( ) . to_path_buf ( ) )
1825+ . map_err ( |_| anyhow:: anyhow!( "EFI dir is not valid UTF-8" ) ) ?;
17831826
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" ) ) ?;
1827+ Command :: new ( "mount" )
1828+ . args ( [ & PathBuf :: from ( & esp_device) , mounted_efi. as_std_path ( ) ] )
1829+ . log_debug ( )
1830+ . run_inherited_with_cmd_context ( )
1831+ . context ( "Mounting EFI" ) ?;
1832+
1833+ let efi_linux_dir = mounted_efi. join ( EFI_LINUX ) ;
1834+
1835+ BLSEntryPath {
1836+ entries_path : efi_linux_dir,
1837+ config_path : mounted_efi. clone ( ) ,
1838+ abs_entries_path : EFI_LINUX ,
1839+ mount_path : Some ( mounted_efi) ,
1840+ }
1841+ }
1842+ } ;
17861843
17871844 let ( bls_config, boot_digest) = match & entry {
17881845 ComposefsBootEntry :: Type1 ( ..) => unimplemented ! ( ) ,
@@ -1831,44 +1888,66 @@ pub(crate) fn setup_composefs_bls_boot(
18311888 . with_title ( id_hex. clone ( ) )
18321889 . with_sort_key ( default_sort_key. into ( ) )
18331890 . 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" ) ] )
1891+ . with_linux ( format ! (
1892+ "/{}/{id_hex}/vmlinuz" ,
1893+ entry_paths. abs_entries_path
1894+ ) )
1895+ . with_initrd ( vec ! [ format!(
1896+ "/{}/{id_hex}/initrd" ,
1897+ entry_paths. abs_entries_path
1898+ ) ] )
18361899 . with_options ( cmdline_refs) ;
18371900
18381901 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" ) ] ;
1902+ bls_config. linux =
1903+ format ! ( "/{}/{symlink_to}/vmlinuz" , entry_paths. abs_entries_path) ;
1904+
1905+ bls_config. initrd = vec ! [ format!(
1906+ "/{}/{symlink_to}/initrd" ,
1907+ entry_paths. abs_entries_path
1908+ ) ] ;
18411909 } else {
1842- write_bls_boot_entries_to_disk ( & efi_dir, id, usr_lib_modules_vmlinuz, & repo) ?;
1910+ write_bls_boot_entries_to_disk (
1911+ & entry_paths. entries_path ,
1912+ id,
1913+ usr_lib_modules_vmlinuz,
1914+ & repo,
1915+ ) ?;
18431916 }
18441917
18451918 ( bls_config, boot_digest)
18461919 }
18471920 } ;
18481921
1849- let ( entries_path , booted_bls) = if is_upgrade {
1922+ let ( config_path , booted_bls) = if is_upgrade {
18501923 let mut booted_bls = get_booted_bls ( ) ?;
18511924 booted_bls. sort_key = Some ( "0" . into ( ) ) ; // entries are sorted by their filename in reverse order
18521925
18531926 // This will be atomically renamed to 'loader/entries' on shutdown/reboot
18541927 (
1855- mounted_efi. join ( format ! ( "loader/{STAGED_BOOT_LOADER_ENTRIES}" ) ) ,
1928+ entry_paths
1929+ . config_path
1930+ . join ( "loader" )
1931+ . join ( STAGED_BOOT_LOADER_ENTRIES ) ,
18561932 Some ( booted_bls) ,
18571933 )
18581934 } else {
18591935 (
1860- mounted_efi. join ( format ! ( "loader/{BOOT_LOADER_ENTRIES}" ) ) ,
1936+ entry_paths
1937+ . config_path
1938+ . join ( "loader" )
1939+ . join ( BOOT_LOADER_ENTRIES ) ,
18611940 None ,
18621941 )
18631942 } ;
18641943
1865- create_dir_all ( & entries_path ) . with_context ( || format ! ( "Creating {:?}" , entries_path ) ) ?;
1944+ create_dir_all ( & config_path ) . with_context ( || format ! ( "Creating {:?}" , config_path ) ) ?;
18661945
18671946 // Scope to allow for proper unmounting
18681947 {
18691948 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 :?}" ) ) ?;
1949+ cap_std:: fs:: Dir :: open_ambient_dir ( & config_path , cap_std:: ambient_authority ( ) )
1950+ . with_context ( || format ! ( "Opening {config_path :?}" ) ) ?;
18721951
18731952 loader_entries_dir. atomic_write (
18741953 // SAFETY: We set sort_key above
@@ -1893,14 +1972,17 @@ pub(crate) fn setup_composefs_bls_boot(
18931972 let owned_loader_entries_fd = loader_entries_dir
18941973 . reopen_as_ownedfd ( )
18951974 . context ( "Reopening as owned fd" ) ?;
1975+
18961976 rustix:: fs:: fsync ( owned_loader_entries_fd) . context ( "fsync" ) ?;
18971977 }
18981978
1899- Command :: new ( "umount" )
1900- . arg ( & mounted_efi)
1901- . log_debug ( )
1902- . run_inherited_with_cmd_context ( )
1903- . context ( "Unmounting EFI" ) ?;
1979+ if let Some ( mounted_efi) = entry_paths. mount_path {
1980+ Command :: new ( "umount" )
1981+ . arg ( mounted_efi)
1982+ . log_debug ( )
1983+ . run_inherited_with_cmd_context ( )
1984+ . context ( "Unmounting EFI" ) ?;
1985+ }
19041986
19051987 Ok ( boot_digest)
19061988}
0 commit comments