@@ -11,7 +11,8 @@ use camino::{Utf8Path, Utf8PathBuf};
1111use cap_std_ext:: { cap_std, dirext:: CapStdExtDirExt } ;
1212use clap:: ValueEnum ;
1313use composefs:: fs:: read_file;
14- use composefs:: tree:: FileSystem ;
14+ use composefs:: tree:: { FileSystem , RegularFile } ;
15+ use composefs_boot:: bootloader:: { PEType , EFI_ADDON_DIR_EXT , EFI_ADDON_FILE_EXT , EFI_EXT } ;
1516use composefs_boot:: BootOps ;
1617use fn_error_context:: context;
1718use ostree_ext:: composefs:: {
@@ -283,7 +284,7 @@ pub(crate) fn setup_composefs_bls_boot(
283284 // TODO: Make this generic
284285 repo : ComposefsRepository < Sha256HashValue > ,
285286 id : & Sha256HashValue ,
286- entry : ComposefsBootEntry < Sha256HashValue > ,
287+ entry : & ComposefsBootEntry < Sha256HashValue > ,
287288) -> Result < String > {
288289 let id_hex = id. to_hex ( ) ;
289290
@@ -527,13 +528,107 @@ pub(crate) fn setup_composefs_bls_boot(
527528 Ok ( boot_digest)
528529}
529530
531+ /// Writes a PortableExecutable to ESP along with any PE specific or Global addons
532+ fn write_pe_to_esp (
533+ repo : & ComposefsRepository < Sha256HashValue > ,
534+ file : & RegularFile < Sha256HashValue > ,
535+ file_path : & PathBuf ,
536+ pe_type : PEType ,
537+ uki_id : & String ,
538+ is_insecure_from_opts : bool ,
539+ mounted_efi : & PathBuf ,
540+ ) -> Result < Option < String > > {
541+ let efi_bin = read_file ( file, & repo) . context ( "Reading .efi binary" ) ?;
542+
543+ let mut boot_label = None ;
544+
545+ // UKI Extension might not even have a cmdline
546+ // TODO: UKI Addon might also have a composefs= cmdline?
547+ if matches ! ( pe_type, PEType :: Uki ) {
548+ let cmdline = uki:: get_cmdline ( & efi_bin) . context ( "Getting UKI cmdline" ) ?;
549+
550+ let ( composefs_cmdline, insecure) = get_cmdline_composefs :: < Sha256HashValue > ( cmdline) ?;
551+
552+ // If the UKI cmdline does not match what the user has passed as cmdline option
553+ // NOTE: This will only be checked for new installs and now upgrades/switches
554+ match is_insecure_from_opts {
555+ true if !insecure => {
556+ tracing:: warn!( "--insecure passed as option but UKI cmdline does not support it" ) ;
557+ }
558+
559+ false if insecure => {
560+ tracing:: warn!( "UKI cmdline has composefs set as insecure" ) ;
561+ }
562+
563+ _ => { /* no-op */ }
564+ }
565+
566+ if composefs_cmdline. to_hex ( ) != * uki_id {
567+ anyhow:: bail!(
568+ "The UKI has the wrong composefs= parameter (is '{composefs_cmdline:?}', should be {uki_id:?})"
569+ ) ;
570+ }
571+
572+ boot_label = Some ( uki:: get_boot_label ( & efi_bin) . context ( "Getting UKI boot label" ) ?) ;
573+ }
574+
575+ // Write the UKI to ESP
576+ let efi_linux_path = mounted_efi. join ( EFI_LINUX ) ;
577+ create_dir_all ( & efi_linux_path) . context ( "Creating EFI/Linux" ) ?;
578+
579+ let final_pe_path = match file_path. parent ( ) {
580+ Some ( parent) => {
581+ let renamed_path = match parent. as_str ( ) ?. ends_with ( EFI_ADDON_DIR_EXT ) {
582+ true => {
583+ let dir_name = format ! ( "{}{}" , uki_id, EFI_ADDON_DIR_EXT ) ;
584+
585+ parent
586+ . parent ( )
587+ . map ( |p| p. join ( & dir_name) )
588+ . unwrap_or ( dir_name. into ( ) )
589+ }
590+
591+ false => parent. to_path_buf ( ) ,
592+ } ;
593+
594+ let full_path = efi_linux_path. join ( renamed_path) ;
595+ create_dir_all ( & full_path) ?;
596+
597+ full_path
598+ }
599+
600+ None => efi_linux_path,
601+ } ;
602+
603+ let pe_dir = cap_std:: fs:: Dir :: open_ambient_dir ( & final_pe_path, cap_std:: ambient_authority ( ) )
604+ . with_context ( || format ! ( "Opening {final_pe_path:?}" ) ) ?;
605+
606+ let pe_name = match pe_type {
607+ PEType :: Uki => format ! ( "{}{}" , uki_id, EFI_EXT ) ,
608+ PEType :: UkiAddon => format ! ( "{}{}" , uki_id, EFI_ADDON_FILE_EXT ) ,
609+ } ;
610+
611+ pe_dir
612+ . atomic_write ( pe_name, efi_bin)
613+ . context ( "Writing UKI" ) ?;
614+
615+ rustix:: fs:: fsync (
616+ pe_dir
617+ . reopen_as_ownedfd ( )
618+ . context ( "Reopening as owned fd" ) ?,
619+ )
620+ . context ( "fsync" ) ?;
621+
622+ Ok ( boot_label)
623+ }
624+
530625#[ context( "Setting up UKI boot" ) ]
531626pub ( crate ) fn setup_composefs_uki_boot (
532627 setup_type : BootSetupType ,
533628 // TODO: Make this generic
534629 repo : ComposefsRepository < Sha256HashValue > ,
535630 id : & Sha256HashValue ,
536- entry : ComposefsBootEntry < Sha256HashValue > ,
631+ entries : Vec < ComposefsBootEntry < Sha256HashValue > > ,
537632) -> Result < ( ) > {
538633 let ( root_path, esp_device, is_insecure_from_opts) = match setup_type {
539634 BootSetupType :: Setup ( ( root_setup, state, ..) ) => {
@@ -553,15 +648,19 @@ pub(crate) fn setup_composefs_uki_boot(
553648 (
554649 root_setup. physical_root_path . clone ( ) ,
555650 esp_part. node . clone ( ) ,
556- state. composefs_options . as_ref ( ) . map ( |x| x. insecure ) ,
651+ state
652+ . composefs_options
653+ . as_ref ( )
654+ . map ( |x| x. insecure )
655+ . unwrap_or ( false ) ,
557656 )
558657 }
559658
560659 BootSetupType :: Upgrade ( ..) => {
561660 let sysroot = Utf8PathBuf :: from ( "/sysroot" ) ;
562661 let sysroot_parent = get_sysroot_parent_dev ( ) ?;
563662
564- ( sysroot, get_esp_partition ( & sysroot_parent) ?. 0 , None )
663+ ( sysroot, get_esp_partition ( & sysroot_parent) ?. 0 , false )
565664 }
566665 } ;
567666
@@ -573,65 +672,32 @@ pub(crate) fn setup_composefs_uki_boot(
573672 . args ( [ & PathBuf :: from ( & esp_device) , & mounted_efi. clone ( ) ] )
574673 . run ( ) ?;
575674
576- let boot_label = match entry {
577- ComposefsBootEntry :: Type1 ( ..) => unimplemented ! ( ) ,
578- ComposefsBootEntry :: UsrLibModulesVmLinuz ( ..) => unimplemented ! ( ) ,
579-
580- ComposefsBootEntry :: Type2 ( type2_entry) => {
581- let uki = read_file ( & type2_entry. file , & repo) . context ( "Reading UKI" ) ?;
582- let cmdline = uki:: get_cmdline ( & uki) . context ( "Getting UKI cmdline" ) ?;
583- let ( composefs_cmdline, insecure) = get_cmdline_composefs :: < Sha256HashValue > ( cmdline) ?;
584-
585- // If the UKI cmdline does not match what the user has passed as cmdline option
586- // NOTE: This will only be checked for new installs and now upgrades/switches
587- if let Some ( is_insecure_from_opts) = is_insecure_from_opts {
588- match is_insecure_from_opts {
589- true => {
590- if !insecure {
591- tracing:: warn!(
592- "--insecure passed as option but UKI cmdline does not support it"
593- )
594- }
595- }
675+ let mut boot_label = String :: new ( ) ;
596676
597- false => {
598- if insecure {
599- tracing:: warn!( "UKI cmdline has composefs set as insecure" )
600- }
601- }
602- }
677+ for entry in entries {
678+ match entry {
679+ ComposefsBootEntry :: Type1 ( ..) => tracing:: debug!( "Skipping Type1 Entry" ) ,
680+ ComposefsBootEntry :: UsrLibModulesVmLinuz ( ..) => {
681+ tracing:: debug!( "Skipping vmlinuz in /usr/lib/modules" )
603682 }
604683
605- let boot_label = uki:: get_boot_label ( & uki) . context ( "Getting UKI boot label" ) ?;
684+ ComposefsBootEntry :: Type2 ( entry) => {
685+ let ret = write_pe_to_esp (
686+ & repo,
687+ & entry. file ,
688+ & entry. file_path ,
689+ entry. pe_type ,
690+ & id. to_hex ( ) ,
691+ is_insecure_from_opts,
692+ & mounted_efi,
693+ ) ?;
606694
607- if composefs_cmdline != * id {
608- anyhow:: bail!(
609- "The UKI has the wrong composefs= parameter (is '{composefs_cmdline:?}', should be {id:?})"
610- ) ;
695+ if let Some ( label) = ret {
696+ boot_label = label;
697+ }
611698 }
612-
613- // Write the UKI to ESP
614- let efi_linux_path = mounted_efi. join ( EFI_LINUX ) ;
615- create_dir_all ( & efi_linux_path) . context ( "Creating EFI/Linux" ) ?;
616-
617- let efi_linux =
618- cap_std:: fs:: Dir :: open_ambient_dir ( & efi_linux_path, cap_std:: ambient_authority ( ) )
619- . with_context ( || format ! ( "Opening {efi_linux_path:?}" ) ) ?;
620-
621- efi_linux
622- . atomic_write ( format ! ( "{}.efi" , id. to_hex( ) ) , uki)
623- . context ( "Writing UKI" ) ?;
624-
625- rustix:: fs:: fsync (
626- efi_linux
627- . reopen_as_ownedfd ( )
628- . context ( "Reopening as owned fd" ) ?,
629- )
630- . context ( "fsync" ) ?;
631-
632- boot_label
633- }
634- } ;
699+ } ;
700+ }
635701
636702 Command :: new ( "umount" )
637703 . arg ( & mounted_efi)
@@ -750,11 +816,11 @@ pub(crate) fn setup_composefs_boot(
750816 let entries = fs. transform_for_boot ( & repo) ?;
751817 let id = fs. commit_image ( & repo, None ) ?;
752818
753- let Some ( entry) = entries. into_iter ( ) . next ( ) else {
819+ let Some ( entry) = entries. iter ( ) . next ( ) else {
754820 anyhow:: bail!( "No boot entries!" ) ;
755821 } ;
756822
757- let boot_type = BootType :: from ( & entry) ;
823+ let boot_type = BootType :: from ( entry) ;
758824 let mut boot_digest: Option < String > = None ;
759825
760826 match boot_type {
@@ -772,7 +838,7 @@ pub(crate) fn setup_composefs_boot(
772838 BootSetupType :: Setup ( ( & root_setup, & state, & fs) ) ,
773839 repo,
774840 & id,
775- entry ,
841+ entries ,
776842 ) ?,
777843 } ;
778844
0 commit comments