@@ -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:: {
@@ -270,7 +271,7 @@ pub(crate) fn setup_composefs_bls_boot(
270271 // TODO: Make this generic
271272 repo : ComposefsRepository < Sha256HashValue > ,
272273 id : & Sha256HashValue ,
273- entry : ComposefsBootEntry < Sha256HashValue > ,
274+ entry : & ComposefsBootEntry < Sha256HashValue > ,
274275) -> Result < String > {
275276 let id_hex = id. to_hex ( ) ;
276277
@@ -522,13 +523,107 @@ pub(crate) fn setup_composefs_bls_boot(
522523 Ok ( boot_digest)
523524}
524525
526+ /// Writes a PortableExecutable to ESP along with any PE specific or Global addons
527+ fn write_pe_to_esp (
528+ repo : & ComposefsRepository < Sha256HashValue > ,
529+ file : & RegularFile < Sha256HashValue > ,
530+ file_path : & PathBuf ,
531+ pe_type : PEType ,
532+ uki_id : & String ,
533+ is_insecure_from_opts : bool ,
534+ mounted_efi : & PathBuf ,
535+ ) -> Result < Option < String > > {
536+ let efi_bin = read_file ( file, & repo) . context ( "Reading .efi binary" ) ?;
537+
538+ let mut boot_label = None ;
539+
540+ // UKI Extension might not even have a cmdline
541+ // TODO: UKI Addon might also have a composefs= cmdline?
542+ if matches ! ( pe_type, PEType :: Uki ) {
543+ let cmdline = uki:: get_cmdline ( & efi_bin) . context ( "Getting UKI cmdline" ) ?;
544+
545+ let ( composefs_cmdline, insecure) = get_cmdline_composefs :: < Sha256HashValue > ( cmdline) ?;
546+
547+ // If the UKI cmdline does not match what the user has passed as cmdline option
548+ // NOTE: This will only be checked for new installs and now upgrades/switches
549+ match is_insecure_from_opts {
550+ true if !insecure => {
551+ tracing:: warn!( "--insecure passed as option but UKI cmdline does not support it" ) ;
552+ }
553+
554+ false if insecure => {
555+ tracing:: warn!( "UKI cmdline has composefs set as insecure" ) ;
556+ }
557+
558+ _ => { /* no-op */ }
559+ }
560+
561+ if composefs_cmdline. to_hex ( ) != * uki_id {
562+ anyhow:: bail!(
563+ "The UKI has the wrong composefs= parameter (is '{composefs_cmdline:?}', should be {uki_id:?})"
564+ ) ;
565+ }
566+
567+ boot_label = Some ( uki:: get_boot_label ( & efi_bin) . context ( "Getting UKI boot label" ) ?) ;
568+ }
569+
570+ // Write the UKI to ESP
571+ let efi_linux_path = mounted_efi. join ( EFI_LINUX ) ;
572+ create_dir_all ( & efi_linux_path) . context ( "Creating EFI/Linux" ) ?;
573+
574+ let final_pe_path = match file_path. parent ( ) {
575+ Some ( parent) => {
576+ let renamed_path = match parent. as_str ( ) ?. ends_with ( EFI_ADDON_DIR_EXT ) {
577+ true => {
578+ let dir_name = format ! ( "{}{}" , uki_id, EFI_ADDON_DIR_EXT ) ;
579+
580+ parent
581+ . parent ( )
582+ . map ( |p| p. join ( & dir_name) )
583+ . unwrap_or ( dir_name. into ( ) )
584+ }
585+
586+ false => parent. to_path_buf ( ) ,
587+ } ;
588+
589+ let full_path = efi_linux_path. join ( renamed_path) ;
590+ create_dir_all ( & full_path) ?;
591+
592+ full_path
593+ }
594+
595+ None => efi_linux_path,
596+ } ;
597+
598+ let pe_dir = cap_std:: fs:: Dir :: open_ambient_dir ( & final_pe_path, cap_std:: ambient_authority ( ) )
599+ . with_context ( || format ! ( "Opening {final_pe_path:?}" ) ) ?;
600+
601+ let pe_name = match pe_type {
602+ PEType :: Uki => format ! ( "{}{}" , uki_id, EFI_EXT ) ,
603+ PEType :: UkiAddon => format ! ( "{}{}" , uki_id, EFI_ADDON_FILE_EXT ) ,
604+ } ;
605+
606+ pe_dir
607+ . atomic_write ( pe_name, efi_bin)
608+ . context ( "Writing UKI" ) ?;
609+
610+ rustix:: fs:: fsync (
611+ pe_dir
612+ . reopen_as_ownedfd ( )
613+ . context ( "Reopening as owned fd" ) ?,
614+ )
615+ . context ( "fsync" ) ?;
616+
617+ Ok ( boot_label)
618+ }
619+
525620#[ context( "Setting up UKI boot" ) ]
526621pub ( crate ) fn setup_composefs_uki_boot (
527622 setup_type : BootSetupType ,
528623 // TODO: Make this generic
529624 repo : ComposefsRepository < Sha256HashValue > ,
530625 id : & Sha256HashValue ,
531- entry : ComposefsBootEntry < Sha256HashValue > ,
626+ entries : Vec < ComposefsBootEntry < Sha256HashValue > > ,
532627) -> Result < ( ) > {
533628 let ( root_path, esp_device, is_insecure_from_opts) = match setup_type {
534629 BootSetupType :: Setup ( ( root_setup, state, ..) ) => {
@@ -548,7 +643,11 @@ pub(crate) fn setup_composefs_uki_boot(
548643 (
549644 root_setup. physical_root_path . clone ( ) ,
550645 esp_part. node . clone ( ) ,
551- state. composefs_options . as_ref ( ) . map ( |x| x. insecure ) ,
646+ state
647+ . composefs_options
648+ . as_ref ( )
649+ . map ( |x| x. insecure )
650+ . unwrap_or ( false ) ,
552651 )
553652 }
554653
@@ -562,7 +661,7 @@ pub(crate) fn setup_composefs_uki_boot(
562661 anyhow:: bail!( "Could not find parent device for mountpoint /sysroot" ) ;
563662 } ;
564663
565- ( sysroot, get_esp_partition ( & parent) ?. 0 , None )
664+ ( sysroot, get_esp_partition ( & parent) ?. 0 , false )
566665 }
567666 } ;
568667
@@ -574,65 +673,32 @@ pub(crate) fn setup_composefs_uki_boot(
574673 . args ( [ & PathBuf :: from ( & esp_device) , & mounted_efi. clone ( ) ] )
575674 . run ( ) ?;
576675
577- let boot_label = match entry {
578- ComposefsBootEntry :: Type1 ( ..) => unimplemented ! ( ) ,
579- ComposefsBootEntry :: UsrLibModulesVmLinuz ( ..) => unimplemented ! ( ) ,
580-
581- ComposefsBootEntry :: Type2 ( type2_entry) => {
582- let uki = read_file ( & type2_entry. file , & repo) . context ( "Reading UKI" ) ?;
583- let cmdline = uki:: get_cmdline ( & uki) . context ( "Getting UKI cmdline" ) ?;
584- let ( composefs_cmdline, insecure) = get_cmdline_composefs :: < Sha256HashValue > ( cmdline) ?;
585-
586- // If the UKI cmdline does not match what the user has passed as cmdline option
587- // NOTE: This will only be checked for new installs and now upgrades/switches
588- if let Some ( is_insecure_from_opts) = is_insecure_from_opts {
589- match is_insecure_from_opts {
590- true => {
591- if !insecure {
592- tracing:: warn!(
593- "--insecure passed as option but UKI cmdline does not support it"
594- )
595- }
596- }
676+ let mut boot_label = String :: new ( ) ;
597677
598- false => {
599- if insecure {
600- tracing:: warn!( "UKI cmdline has composefs set as insecure" )
601- }
602- }
603- }
678+ for entry in entries {
679+ match entry {
680+ ComposefsBootEntry :: Type1 ( ..) => tracing:: debug!( "Skipping Type1 Entry" ) ,
681+ ComposefsBootEntry :: UsrLibModulesVmLinuz ( ..) => {
682+ tracing:: debug!( "Skipping vmlinuz in /usr/lib/modules" )
604683 }
605684
606- let boot_label = uki:: get_boot_label ( & uki) . context ( "Getting UKI boot label" ) ?;
685+ ComposefsBootEntry :: Type2 ( entry) => {
686+ let ret = write_pe_to_esp (
687+ & repo,
688+ & entry. file ,
689+ & entry. file_path ,
690+ entry. pe_type ,
691+ & id. to_hex ( ) ,
692+ is_insecure_from_opts,
693+ & mounted_efi,
694+ ) ?;
607695
608- if composefs_cmdline != * id {
609- anyhow:: bail!(
610- "The UKI has the wrong composefs= parameter (is '{composefs_cmdline:?}', should be {id:?})"
611- ) ;
696+ if let Some ( label) = ret {
697+ boot_label = label;
698+ }
612699 }
613-
614- // Write the UKI to ESP
615- let efi_linux_path = mounted_efi. join ( EFI_LINUX ) ;
616- create_dir_all ( & efi_linux_path) . context ( "Creating EFI/Linux" ) ?;
617-
618- let efi_linux =
619- cap_std:: fs:: Dir :: open_ambient_dir ( & efi_linux_path, cap_std:: ambient_authority ( ) )
620- . with_context ( || format ! ( "Opening {efi_linux_path:?}" ) ) ?;
621-
622- efi_linux
623- . atomic_write ( format ! ( "{}.efi" , id. to_hex( ) ) , uki)
624- . context ( "Writing UKI" ) ?;
625-
626- rustix:: fs:: fsync (
627- efi_linux
628- . reopen_as_ownedfd ( )
629- . context ( "Reopening as owned fd" ) ?,
630- )
631- . context ( "fsync" ) ?;
632-
633- boot_label
634- }
635- } ;
700+ } ;
701+ }
636702
637703 Command :: new ( "umount" )
638704 . arg ( & mounted_efi)
@@ -751,11 +817,11 @@ pub(crate) fn setup_composefs_boot(
751817 let entries = fs. transform_for_boot ( & repo) ?;
752818 let id = fs. commit_image ( & repo, None ) ?;
753819
754- let Some ( entry) = entries. into_iter ( ) . next ( ) else {
820+ let Some ( entry) = entries. iter ( ) . next ( ) else {
755821 anyhow:: bail!( "No boot entries!" ) ;
756822 } ;
757823
758- let boot_type = BootType :: from ( & entry) ;
824+ let boot_type = BootType :: from ( entry) ;
759825 let mut boot_digest: Option < String > = None ;
760826
761827 match boot_type {
@@ -773,7 +839,7 @@ pub(crate) fn setup_composefs_boot(
773839 BootSetupType :: Setup ( ( & root_setup, & state, & fs) ) ,
774840 repo,
775841 & id,
776- entry ,
842+ entries ,
777843 ) ?,
778844 } ;
779845
0 commit comments