@@ -45,7 +45,7 @@ use ostree_ext::composefs::{
4545    util:: Sha256Digest , 
4646} ; 
4747use  ostree_ext:: composefs_boot:: { 
48-     write_boot:: write_boot_simple as  composefs_write_boot_simple,  BootOps , 
48+     bootloader :: BootEntry ,   write_boot:: write_boot_simple as  composefs_write_boot_simple,  BootOps , 
4949} ; 
5050use  ostree_ext:: composefs_oci:: { 
5151    image:: create_filesystem as  create_composefs_filesystem,  pull as  composefs_oci_pull, 
@@ -240,7 +240,8 @@ pub(crate) enum BootType {
240240} 
241241
242242#[ derive( Debug ,  Clone ,  clap:: Parser ,  Serialize ,  Deserialize ,  PartialEq ,  Eq ) ]  
243- pub ( crate )  struct  InstallComposefsOptions  { 
243+ pub ( crate )  struct  InstallComposefsOpts  { 
244+     #[ clap( long,  value_enum,  default_value_t) ]  
244245    pub ( crate )  boot :  BootType , 
245246} 
246247
@@ -269,10 +270,10 @@ pub(crate) struct InstallToDiskOpts {
269270    pub ( crate )  via_loopback :  bool , 
270271
271272    #[ clap( long) ]  
272-     pub ( crate )  composefs_experimental :  bool , 
273+     pub ( crate )  composefs_native :  bool , 
273274
274275    #[ clap( flatten) ]  
275-     pub ( crate )  composefs_opts :  InstallComposefsOptions , 
276+     pub ( crate )  composefs_opts :  InstallComposefsOpts , 
276277} 
277278
278279#[ derive( ValueEnum ,  Debug ,  Copy ,  Clone ,  PartialEq ,  Eq ,  Serialize ,  Deserialize ) ]  
@@ -413,6 +414,9 @@ pub(crate) struct State {
413414    /// The root filesystem of the running container 
414415pub ( crate )  container_root :  Dir , 
415416    pub ( crate )  tempdir :  TempDir , 
417+ 
418+     // If Some, then --composefs_native is passed 
419+     pub ( crate )  composefs_options :  Option < InstallComposefsOpts > , 
416420} 
417421
418422impl  State  { 
@@ -558,7 +562,7 @@ impl FromStr for MountSpec {
558562
559563impl  InstallToDiskOpts  { 
560564    pub ( crate )  fn  validate ( & self )  { 
561-         if  !self . composefs_experimental  { 
565+         if  !self . composefs_native  { 
562566            // Reject using --boot without --composefs 
563567            if  self . composefs_opts . boot  != BootType :: default ( )  { 
564568                panic ! ( "--boot must not be provided without --composefs" ) ; 
@@ -1226,6 +1230,7 @@ async fn prepare_install(
12261230    config_opts :  InstallConfigOpts , 
12271231    source_opts :  InstallSourceOpts , 
12281232    target_opts :  InstallTargetOpts , 
1233+     composefs_opts :  Option < InstallComposefsOpts > , 
12291234)  -> Result < Arc < State > >  { 
12301235    tracing:: trace!( "Preparing install" ) ; 
12311236    let  rootfs = cap_std:: fs:: Dir :: open_ambient_dir ( "/" ,  cap_std:: ambient_authority ( ) ) 
@@ -1370,6 +1375,7 @@ async fn prepare_install(
13701375        container_root :  rootfs, 
13711376        tempdir, 
13721377        host_is_container, 
1378+         composefs_options :  composefs_opts, 
13731379    } ) ; 
13741380
13751381    Ok ( state) 
@@ -1494,37 +1500,14 @@ async fn initialize_composefs_repository(
14941500    composefs_oci_pull ( & Arc :: new ( repo) ,  & format ! ( "{transport}{name}" , ) ,  None ) . await 
14951501} 
14961502
1497- #[ context( "Setting up composefs boot" ) ]  
1498- fn  setup_composefs_boot ( root_setup :  & RootSetup ,  state :  & State ,  image_id :  & str )  -> Result < ( ) >  { 
1499-     let  boot_uuid = root_setup
1500-         . get_boot_uuid ( ) ?
1501-         . or ( root_setup. rootfs_uuid . as_deref ( ) ) 
1502-         . ok_or_else ( || anyhow ! ( "No uuid for boot/root" ) ) ?; 
1503- 
1504-     if  cfg ! ( target_arch = "s390x" )  { 
1505-         // TODO: Integrate s390x support into install_via_bootupd 
1506-         crate :: bootloader:: install_via_zipl ( & root_setup. device_info ,  boot_uuid) ?; 
1507-     }  else  { 
1508-         crate :: bootloader:: install_via_bootupd ( 
1509-             & root_setup. device_info , 
1510-             & root_setup. physical_root_path , 
1511-             & state. config_opts , 
1512-         ) ?; 
1513-     } 
1514- 
1515-     let  repo = open_composefs_repo ( & root_setup. physical_root ) ?; 
1516- 
1517-     let  mut  fs = create_composefs_filesystem ( & repo,  image_id,  None ) ?; 
1518- 
1519-     let  entries = fs. transform_for_boot ( & repo) ?; 
1520-     let  id = fs. commit_image ( & repo,  None ) ?; 
1521- 
1522-     println ! ( "{entries:#?}" ) ; 
1523- 
1524-     let  Some ( entry)  = entries. into_iter ( ) . next ( )  else  { 
1525-         anyhow:: bail!( "No boot entries!" ) ; 
1526-     } ; 
1527- 
1503+ #[ context( "Setting up BLS boot" ) ]  
1504+ fn  setup_composefs_bls_boot ( 
1505+     root_setup :  & RootSetup , 
1506+     // TODO: Make this generic 
1507+     repo :  ComposefsRepository < Sha256HashValue > , 
1508+     id :  & Sha256HashValue , 
1509+     entry :  BootEntry < Sha256HashValue > , 
1510+ )  -> Result < ( ) >  { 
15281511    let  rootfs_uuid = match  & root_setup. rootfs_uuid  { 
15291512        Some ( u)  => u, 
15301513        None  => anyhow:: bail!( "Expected rootfs to have a UUID by now" ) , 
@@ -1536,6 +1519,32 @@ fn setup_composefs_boot(root_setup: &RootSetup, state: &State, image_id: &str) -
15361519        "rw" , 
15371520    ] ; 
15381521
1522+     composefs_write_boot_simple ( 
1523+         & repo, 
1524+         entry, 
1525+         & id, 
1526+         root_setup. physical_root_path . as_std_path ( ) ,  // /run/mounts/bootc/boot 
1527+         Some ( "boot" ) , 
1528+         Some ( & format ! ( "{}" ,  id. to_hex( ) ) ) , 
1529+         & cmdline_refs, 
1530+     ) ?; 
1531+ 
1532+     Ok ( ( ) ) 
1533+ } 
1534+ 
1535+ #[ context( "Setting up UKI boot" ) ]  
1536+ fn  setup_composefs_uki_boot ( 
1537+     root_setup :  & RootSetup , 
1538+     // TODO: Make this generic 
1539+     repo :  ComposefsRepository < Sha256HashValue > , 
1540+     id :  & Sha256HashValue , 
1541+     entry :  BootEntry < Sha256HashValue > , 
1542+ )  -> Result < ( ) >  { 
1543+     let  rootfs_uuid = match  & root_setup. rootfs_uuid  { 
1544+         Some ( u)  => u, 
1545+         None  => anyhow:: bail!( "Expected rootfs to have a UUID by now" ) , 
1546+     } ; 
1547+ 
15391548    let  boot_dir = root_setup. physical_root_path . join ( "boot" ) ; 
15401549    create_dir_all ( & boot_dir) . context ( "Failed to create boot dir" ) ?; 
15411550
@@ -1544,28 +1553,71 @@ fn setup_composefs_boot(root_setup: &RootSetup, state: &State, image_id: &str) -
15441553        entry, 
15451554        & id, 
15461555        boot_dir. as_std_path ( ) , 
1556+         None , 
15471557        Some ( & format ! ( "{}" ,  id. to_hex( ) ) ) , 
1548-         Some ( "/boot" ) , 
1549-         & cmdline_refs, 
1558+         & [ ] , 
15501559    ) ?; 
15511560
15521561    // Add the user grug cfg 
15531562    // TODO: We don't need this for BLS. Have a flag for BLS vs UKI, or maybe we can figure it out 
15541563    // via the boot entries above 
15551564    let  grub_user_config = format ! ( 
15561565        r#" 
1557- menuentry "Some  Fedora" {{ 
1566+ menuentry "Fedora Bootc UKI " {{ 
15581567    insmod fat 
15591568    insmod chain 
15601569    search --no-floppy --set=root --fs-uuid {rootfs_uuid} 
1561-     chainloader /boot/EFI/Linux/uki .efi 
1570+     chainloader /boot/EFI/Linux/{uki_id} .efi 
15621571}} 
1563- "# 
1572+ "# ,  uki_id=id . to_hex ( ) 
15641573    ) ; 
15651574
15661575    std:: fs:: write ( boot_dir. join ( "grub2/user.cfg" ) ,  grub_user_config) 
15671576        . context ( "Failed to write grub2/user.cfg" ) ?; 
15681577
1578+     Ok ( ( ) ) 
1579+ } 
1580+ 
1581+ #[ context( "Setting up composefs boot" ) ]  
1582+ fn  setup_composefs_boot ( root_setup :  & RootSetup ,  state :  & State ,  image_id :  & str )  -> Result < ( ) >  { 
1583+     let  boot_uuid = root_setup
1584+         . get_boot_uuid ( ) ?
1585+         . or ( root_setup. rootfs_uuid . as_deref ( ) ) 
1586+         . ok_or_else ( || anyhow ! ( "No uuid for boot/root" ) ) ?; 
1587+ 
1588+     if  cfg ! ( target_arch = "s390x" )  { 
1589+         // TODO: Integrate s390x support into install_via_bootupd 
1590+         crate :: bootloader:: install_via_zipl ( & root_setup. device_info ,  boot_uuid) ?; 
1591+     }  else  { 
1592+         crate :: bootloader:: install_via_bootupd ( 
1593+             & root_setup. device_info , 
1594+             & root_setup. physical_root_path , 
1595+             & state. config_opts , 
1596+         ) ?; 
1597+     } 
1598+ 
1599+     let  repo = open_composefs_repo ( & root_setup. physical_root ) ?; 
1600+ 
1601+     let  mut  fs = create_composefs_filesystem ( & repo,  image_id,  None ) ?; 
1602+ 
1603+     let  entries = fs. transform_for_boot ( & repo) ?; 
1604+     let  id = fs. commit_image ( & repo,  None ) ?; 
1605+ 
1606+     println ! ( "{entries:#?}" ) ; 
1607+ 
1608+     let  Some ( entry)  = entries. into_iter ( ) . next ( )  else  { 
1609+         anyhow:: bail!( "No boot entries!" ) ; 
1610+     } ; 
1611+ 
1612+     let  Some ( composefs_opts)  = & state. composefs_options  else  { 
1613+         anyhow:: bail!( "Could not find options for composefs" ) 
1614+     } ; 
1615+ 
1616+     match  composefs_opts. boot  { 
1617+         BootType :: Bls  => setup_composefs_bls_boot ( root_setup,  repo,  & id,  entry) ?, 
1618+         BootType :: Uki  => setup_composefs_uki_boot ( root_setup,  repo,  & id,  entry) ?, 
1619+     } ; 
1620+ 
15691621    let  state_path = root_setup
15701622        . physical_root_path 
15711623        . join ( format ! ( "state/{}" ,  id. to_hex( ) ) ) ; 
@@ -1581,7 +1633,6 @@ async fn install_to_filesystem_impl(
15811633    state :  & State , 
15821634    rootfs :  & mut  RootSetup , 
15831635    cleanup :  Cleanup , 
1584-     composefs :  bool , 
15851636)  -> Result < ( ) >  { 
15861637    if  matches ! ( state. selinux_state,  SELinuxFinalState :: ForceTargetDisabled )  { 
15871638        rootfs. kargs . push ( "selinux=0" . to_string ( ) ) ; 
@@ -1610,7 +1661,7 @@ async fn install_to_filesystem_impl(
16101661
16111662    let  bound_images = BoundImages :: from_state ( state) . await ?; 
16121663
1613-     if  composefs  { 
1664+     if  state . composefs_options . is_some ( )  { 
16141665        // Load a fd for the mounted target physical root 
16151666        let  ( id,  verity)  = initialize_composefs_repository ( state,  rootfs) . await ?; 
16161667
@@ -1694,7 +1745,17 @@ pub(crate) async fn install_to_disk(mut opts: InstallToDiskOpts) -> Result<()> {
16941745    }  else  if  !target_blockdev_meta. file_type ( ) . is_block_device ( )  { 
16951746        anyhow:: bail!( "Not a block device: {}" ,  block_opts. device) ; 
16961747    } 
1697-     let  state = prepare_install ( opts. config_opts ,  opts. source_opts ,  opts. target_opts ) . await ?; 
1748+     let  state = prepare_install ( 
1749+         opts. config_opts , 
1750+         opts. source_opts , 
1751+         opts. target_opts , 
1752+         if  opts. composefs_native  { 
1753+             Some ( opts. composefs_opts ) 
1754+         }  else  { 
1755+             None 
1756+         } , 
1757+     ) 
1758+     . await ?; 
16981759
16991760    // This is all blocking stuff 
17001761    let  ( mut  rootfs,  loopback)  = { 
@@ -1715,7 +1776,7 @@ pub(crate) async fn install_to_disk(mut opts: InstallToDiskOpts) -> Result<()> {
17151776        ( rootfs,  loopback_dev) 
17161777    } ; 
17171778
1718-     install_to_filesystem_impl ( & state,  & mut  rootfs,  Cleanup :: Skip ,  opts . composefs_experimental ) . await ?; 
1779+     install_to_filesystem_impl ( & state,  & mut  rootfs,  Cleanup :: Skip ) . await ?; 
17191780
17201781    // Drop all data about the root except the bits we need to ensure any file descriptors etc. are closed. 
17211782    let  ( root_path,  luksdev)  = rootfs. into_storage ( ) ; 
@@ -1902,7 +1963,7 @@ pub(crate) async fn install_to_filesystem(
19021963    // IMPORTANT: and hence anything that is done before MUST BE IDEMPOTENT. 
19031964    // IMPORTANT: In practice, we should only be gathering information before this point, 
19041965    // IMPORTANT: and not performing any mutations at all. 
1905-     let  state = prepare_install ( opts. config_opts ,  opts. source_opts ,  opts. target_opts ) . await ?; 
1966+     let  state = prepare_install ( opts. config_opts ,  opts. source_opts ,  opts. target_opts ,   None ) . await ?; 
19061967    // And the last bit of state here is the fsopts, which we also destructure now. 
19071968    let  mut  fsopts = opts. filesystem_opts ; 
19081969
@@ -2101,7 +2162,7 @@ pub(crate) async fn install_to_filesystem(
21012162        skip_finalize, 
21022163    } ; 
21032164
2104-     install_to_filesystem_impl ( & state,  & mut  rootfs,  cleanup,   false ) . await ?; 
2165+     install_to_filesystem_impl ( & state,  & mut  rootfs,  cleanup) . await ?; 
21052166
21062167    // Drop all data about the root except the path to ensure any file descriptors etc. are closed. 
21072168    drop ( rootfs) ; 
0 commit comments