@@ -11,7 +11,8 @@ use camino::{Utf8Path, Utf8PathBuf};
11
11
use cap_std_ext:: { cap_std, dirext:: CapStdExtDirExt } ;
12
12
use clap:: ValueEnum ;
13
13
use 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 } ;
15
16
use composefs_boot:: BootOps ;
16
17
use fn_error_context:: context;
17
18
use ostree_ext:: composefs:: {
@@ -283,7 +284,7 @@ pub(crate) fn setup_composefs_bls_boot(
283
284
// TODO: Make this generic
284
285
repo : ComposefsRepository < Sha256HashValue > ,
285
286
id : & Sha256HashValue ,
286
- entry : ComposefsBootEntry < Sha256HashValue > ,
287
+ entry : & ComposefsBootEntry < Sha256HashValue > ,
287
288
) -> Result < String > {
288
289
let id_hex = id. to_hex ( ) ;
289
290
@@ -527,13 +528,107 @@ pub(crate) fn setup_composefs_bls_boot(
527
528
Ok ( boot_digest)
528
529
}
529
530
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
+
530
625
#[ context( "Setting up UKI boot" ) ]
531
626
pub ( crate ) fn setup_composefs_uki_boot (
532
627
setup_type : BootSetupType ,
533
628
// TODO: Make this generic
534
629
repo : ComposefsRepository < Sha256HashValue > ,
535
630
id : & Sha256HashValue ,
536
- entry : ComposefsBootEntry < Sha256HashValue > ,
631
+ entries : Vec < ComposefsBootEntry < Sha256HashValue > > ,
537
632
) -> Result < ( ) > {
538
633
let ( root_path, esp_device, is_insecure_from_opts) = match setup_type {
539
634
BootSetupType :: Setup ( ( root_setup, state, ..) ) => {
@@ -553,15 +648,19 @@ pub(crate) fn setup_composefs_uki_boot(
553
648
(
554
649
root_setup. physical_root_path . clone ( ) ,
555
650
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 ) ,
557
656
)
558
657
}
559
658
560
659
BootSetupType :: Upgrade ( ..) => {
561
660
let sysroot = Utf8PathBuf :: from ( "/sysroot" ) ;
562
661
let sysroot_parent = get_sysroot_parent_dev ( ) ?;
563
662
564
- ( sysroot, get_esp_partition ( & sysroot_parent) ?. 0 , None )
663
+ ( sysroot, get_esp_partition ( & sysroot_parent) ?. 0 , false )
565
664
}
566
665
} ;
567
666
@@ -573,65 +672,32 @@ pub(crate) fn setup_composefs_uki_boot(
573
672
. args ( [ & PathBuf :: from ( & esp_device) , & mounted_efi. clone ( ) ] )
574
673
. run ( ) ?;
575
674
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 ( ) ;
596
676
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" )
603
682
}
604
683
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
+ ) ?;
606
694
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
+ }
611
698
}
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
+ }
635
701
636
702
Command :: new ( "umount" )
637
703
. arg ( & mounted_efi)
@@ -750,11 +816,11 @@ pub(crate) fn setup_composefs_boot(
750
816
let entries = fs. transform_for_boot ( & repo) ?;
751
817
let id = fs. commit_image ( & repo, None ) ?;
752
818
753
- let Some ( entry) = entries. into_iter ( ) . next ( ) else {
819
+ let Some ( entry) = entries. iter ( ) . next ( ) else {
754
820
anyhow:: bail!( "No boot entries!" ) ;
755
821
} ;
756
822
757
- let boot_type = BootType :: from ( & entry) ;
823
+ let boot_type = BootType :: from ( entry) ;
758
824
let mut boot_digest: Option < String > = None ;
759
825
760
826
match boot_type {
@@ -772,7 +838,7 @@ pub(crate) fn setup_composefs_boot(
772
838
BootSetupType :: Setup ( ( & root_setup, & state, & fs) ) ,
773
839
repo,
774
840
& id,
775
- entry ,
841
+ entries ,
776
842
) ?,
777
843
} ;
778
844
0 commit comments