6161//! 1. **Primary**: New/upgraded deployment (default boot target)
6262//! 2. **Secondary**: Currently booted deployment (rollback option)
6363
64- use std:: ffi:: OsStr ;
6564use std:: fs:: create_dir_all;
6665use std:: io:: Write ;
6766use std:: path:: Path ;
67+ use std:: sync:: Arc ;
6868
6969use anyhow:: { Context , Result , anyhow, bail} ;
7070use bootc_kernel_cmdline:: utf8:: { Cmdline , Parameter , ParameterKey } ;
@@ -81,42 +81,27 @@ use clap::ValueEnum;
8181use composefs:: fs:: read_file;
8282use composefs:: fsverity:: { FsVerityHashValue , Sha512HashValue } ;
8383use composefs:: tree:: RegularFile ;
84- use composefs_boot:: BootOps ;
8584use composefs_boot:: bootloader:: {
8685 BootEntry as ComposefsBootEntry , EFI_ADDON_DIR_EXT , EFI_ADDON_FILE_EXT , EFI_EXT , PEType ,
87- UsrLibModulesVmlinuz ,
86+ UsrLibModulesVmlinuz , get_boot_resources ,
8887} ;
8988use composefs_boot:: { cmdline:: get_cmdline_composefs, os_release:: OsReleaseInfo , uki} ;
90- use composefs_oci:: image:: create_filesystem as create_composefs_filesystem;
9189use fn_error_context:: context;
9290use rustix:: { mount:: MountFlags , path:: Arg } ;
9391use schemars:: JsonSchema ;
9492use serde:: { Deserialize , Serialize } ;
9593
96- use crate :: {
97- bootc_composefs:: repo:: get_imgref,
98- composefs_consts:: { TYPE1_ENT_PATH , TYPE1_ENT_PATH_STAGED } ,
99- } ;
100- use crate :: {
101- bootc_composefs:: repo:: open_composefs_repo,
102- store:: { ComposefsFilesystem , Storage } ,
103- } ;
104- use crate :: {
105- bootc_composefs:: state:: { get_booted_bls, write_composefs_state} ,
106- composefs_consts:: TYPE1_BOOT_DIR_PREFIX ,
107- } ;
108- use crate :: { bootc_composefs:: status:: ComposefsCmdline , task:: Task } ;
109- use crate :: {
110- bootc_composefs:: status:: get_container_manifest_and_config, bootc_kargs:: compute_new_kargs,
111- } ;
94+ use crate :: bootc_composefs:: state:: { get_booted_bls, write_composefs_state} ;
95+ use crate :: bootc_composefs:: status:: ComposefsCmdline ;
96+ use crate :: bootc_kargs:: compute_new_kargs;
97+ use crate :: composefs_consts:: { TYPE1_BOOT_DIR_PREFIX , TYPE1_ENT_PATH , TYPE1_ENT_PATH_STAGED } ;
98+ use crate :: parsers:: bls_config:: { BLSConfig , BLSConfigType } ;
99+ use crate :: task:: Task ;
100+ use crate :: { bootc_composefs:: repo:: open_composefs_repo, store:: Storage } ;
112101use crate :: { bootc_composefs:: status:: get_sorted_grub_uki_boot_entries, install:: PostFetchState } ;
113- use crate :: {
114- composefs_consts:: UKI_NAME_PREFIX ,
115- parsers:: bls_config:: { BLSConfig , BLSConfigType } ,
116- } ;
117102use crate :: {
118103 composefs_consts:: {
119- BOOT_LOADER_ENTRIES , STAGED_BOOT_LOADER_ENTRIES , USER_CFG , USER_CFG_STAGED ,
104+ BOOT_LOADER_ENTRIES , STAGED_BOOT_LOADER_ENTRIES , UKI_NAME_PREFIX , USER_CFG , USER_CFG_STAGED ,
120105 } ,
121106 spec:: { Bootloader , Host } ,
122107} ;
@@ -148,23 +133,9 @@ pub(crate) const BOOTC_UKI_DIR: &str = "EFI/Linux/bootc";
148133
149134pub ( crate ) enum BootSetupType < ' a > {
150135 /// For initial setup, i.e. install to-disk
151- Setup (
152- (
153- & ' a RootSetup ,
154- & ' a State ,
155- & ' a PostFetchState ,
156- & ' a ComposefsFilesystem ,
157- ) ,
158- ) ,
136+ Setup ( ( & ' a RootSetup , & ' a State , & ' a PostFetchState ) ) ,
159137 /// For `bootc upgrade`
160- Upgrade (
161- (
162- & ' a Storage ,
163- & ' a BootedComposefs ,
164- & ' a ComposefsFilesystem ,
165- & ' a Host ,
166- ) ,
167- ) ,
138+ Upgrade ( ( & ' a Storage , & ' a BootedComposefs , & ' a Host ) ) ,
168139}
169140
170141#[ derive(
@@ -451,41 +422,20 @@ fn write_bls_boot_entries_to_disk(
451422}
452423
453424/// Parses /usr/lib/os-release and returns (id, title, version)
454- fn parse_os_release (
455- fs : & crate :: store:: ComposefsFilesystem ,
456- repo : & crate :: store:: ComposefsRepository ,
457- ) -> Result < Option < ( String , Option < String > , Option < String > ) > > {
425+ fn parse_os_release ( mounted_fs : & Dir ) -> Result < Option < ( String , Option < String > , Option < String > ) > > {
458426 // Every update should have its own /usr/lib/os-release
459- let ( dir, fname) = fs
460- . root
461- . split ( OsStr :: new ( "/usr/lib/os-release" ) )
462- . context ( "Getting /usr/lib/os-release" ) ?;
463-
464- let os_release = dir
465- . get_file_opt ( fname)
466- . context ( "Getting /usr/lib/os-release" ) ?;
467-
468- let Some ( os_rel_file) = os_release else {
469- return Ok ( None ) ;
470- } ;
471-
472- let file_contents = match read_file ( os_rel_file, repo) {
427+ let file_contents = match mounted_fs. read_to_string ( "usr/lib/os-release" ) {
473428 Ok ( c) => c,
474- Err ( e) => {
475- tracing:: warn!( "Could not read /usr/lib/os-release: {e:?}" ) ;
429+ Err ( e) if e. kind ( ) == std:: io:: ErrorKind :: NotFound => {
476430 return Ok ( None ) ;
477431 }
478- } ;
479-
480- let file_contents = match std:: str:: from_utf8 ( & file_contents) {
481- Ok ( c) => c,
482432 Err ( e) => {
483- tracing:: warn!( "/usr/lib/os-release did not have valid UTF-8 : {e}" ) ;
433+ tracing:: warn!( "Could not read /usr/lib/os-release: {e:? }" ) ;
484434 return Ok ( None ) ;
485435 }
486436 } ;
487437
488- let parsed = OsReleaseInfo :: parse ( file_contents) ;
438+ let parsed = OsReleaseInfo :: parse ( & file_contents) ;
489439
490440 let os_id = parsed
491441 . get_value ( & [ "ID" ] )
@@ -521,8 +471,8 @@ pub(crate) fn setup_composefs_bls_boot(
521471) -> Result < String > {
522472 let id_hex = id. to_hex ( ) ;
523473
524- let ( root_path, esp_device, mut cmdline_refs, fs , bootloader) = match setup_type {
525- BootSetupType :: Setup ( ( root_setup, state, postfetch, fs ) ) => {
474+ let ( root_path, esp_device, mut cmdline_refs, bootloader) = match setup_type {
475+ BootSetupType :: Setup ( ( root_setup, state, postfetch) ) => {
526476 // root_setup.kargs has [root=UUID=<UUID>, "rw"]
527477 let mut cmdline_options = Cmdline :: new ( ) ;
528478
@@ -539,12 +489,11 @@ pub(crate) fn setup_composefs_bls_boot(
539489 root_setup. physical_root_path . clone ( ) ,
540490 esp_part. path ( ) ,
541491 cmdline_options,
542- fs,
543492 postfetch. detected_bootloader . clone ( ) ,
544493 )
545494 }
546495
547- BootSetupType :: Upgrade ( ( storage, booted_cfs, fs , host) ) => {
496+ BootSetupType :: Upgrade ( ( storage, booted_cfs, host) ) => {
548497 let bootloader = host. require_composefs_booted ( ) ?. bootloader . clone ( ) ;
549498
550499 let boot_dir = storage. require_boot_dir ( ) ?;
@@ -579,7 +528,6 @@ pub(crate) fn setup_composefs_bls_boot(
579528 Utf8PathBuf :: from ( "/sysroot" ) ,
580529 esp_dev. path ( ) ,
581530 cmdline,
582- fs,
583531 bootloader,
584532 )
585533 }
@@ -653,7 +601,7 @@ pub(crate) fn setup_composefs_bls_boot(
653601 let boot_digest = compute_boot_digest ( usr_lib_modules_vmlinuz, & repo)
654602 . context ( "Computing boot digest" ) ?;
655603
656- let osrel = parse_os_release ( fs , & repo ) ?;
604+ let osrel = parse_os_release ( mounted_erofs ) ?;
657605
658606 let ( os_id, title, version, sort_key) = match osrel {
659607 Some ( ( id_str, title_opt, version_opt) ) => (
@@ -1078,7 +1026,7 @@ pub(crate) fn setup_composefs_uki_boot(
10781026) -> Result < String > {
10791027 let ( root_path, esp_device, bootloader, missing_fsverity_allowed, uki_addons) = match setup_type
10801028 {
1081- BootSetupType :: Setup ( ( root_setup, state, postfetch, .. ) ) => {
1029+ BootSetupType :: Setup ( ( root_setup, state, postfetch) ) => {
10821030 state. require_no_kargs_for_uki ( ) ?;
10831031
10841032 let esp_part = root_setup. device_info . find_partition_of_esp ( ) ?;
@@ -1092,7 +1040,7 @@ pub(crate) fn setup_composefs_uki_boot(
10921040 )
10931041 }
10941042
1095- BootSetupType :: Upgrade ( ( storage, booted_cfs, _ , host) ) => {
1043+ BootSetupType :: Upgrade ( ( storage, booted_cfs, host) ) => {
10961044 let sysroot = Utf8PathBuf :: from ( "/sysroot" ) ; // Still needed for root_path
10971045 let bootloader = host. require_composefs_booted ( ) ?. bootloader . clone ( ) ;
10981046
@@ -1235,25 +1183,36 @@ fn get_secureboot_keys(fs: &Dir, p: &str) -> Result<Option<SecurebootKeys>> {
12351183pub ( crate ) async fn setup_composefs_boot (
12361184 root_setup : & RootSetup ,
12371185 state : & State ,
1238- image_id : & str ,
1186+ pull_result : & composefs_oci :: skopeo :: PullResult < Sha512HashValue > ,
12391187 allow_missing_fsverity : bool ,
12401188) -> Result < ( ) > {
12411189 const COMPOSEFS_BOOT_SETUP_JOURNAL_ID : & str = "1f0e9d8c7b6a5f4e3d2c1b0a9f8e7d6c5" ;
12421190
12431191 tracing:: info!(
12441192 message_id = COMPOSEFS_BOOT_SETUP_JOURNAL_ID ,
12451193 bootc. operation = "boot_setup" ,
1246- bootc. image_id = image_id ,
1194+ bootc. config_digest = %pull_result . config_digest ,
12471195 bootc. allow_missing_fsverity = allow_missing_fsverity,
12481196 "Setting up composefs boot" ,
12491197 ) ;
12501198
12511199 let mut repo = open_composefs_repo ( & root_setup. physical_root ) ?;
1252- repo. set_insecure ( allow_missing_fsverity) ;
1200+ if allow_missing_fsverity {
1201+ repo. set_insecure ( ) ;
1202+ }
1203+
1204+ let repo = Arc :: new ( repo) ;
1205+
1206+ // Generate the bootable EROFS image (idempotent).
1207+ let id = composefs_oci:: generate_boot_image ( & repo, & pull_result. manifest_digest )
1208+ . context ( "Generating bootable EROFS image" ) ?;
1209+
1210+ // Get boot entries from the OCI filesystem (untransformed).
1211+ let fs = composefs_oci:: image:: create_filesystem ( & * repo, & pull_result. config_digest , None )
1212+ . context ( "Creating composefs filesystem for boot entry discovery" ) ?;
1213+ let entries =
1214+ get_boot_resources ( & fs, & * repo) . context ( "Extracting boot entries from OCI image" ) ?;
12531215
1254- let mut fs = create_composefs_filesystem ( & repo, image_id, None ) ?;
1255- let entries = fs. transform_for_boot ( & repo) ?;
1256- let id = fs. commit_image ( & repo, None ) ?;
12571216 let mounted_fs = Dir :: reopen_dir (
12581217 & repo
12591218 . mount ( & id. to_hex ( ) )
@@ -1296,16 +1255,23 @@ pub(crate) async fn setup_composefs_boot(
12961255
12971256 let boot_type = BootType :: from ( entry) ;
12981257
1258+ // Unwrap Arc to pass owned repo to boot setup functions.
1259+ let repo = Arc :: try_unwrap ( repo) . map_err ( |_| {
1260+ anyhow:: anyhow!(
1261+ "BUG: Arc<Repository> still has other references after boot image generation"
1262+ )
1263+ } ) ?;
1264+
12991265 let boot_digest = match boot_type {
13001266 BootType :: Bls => setup_composefs_bls_boot (
1301- BootSetupType :: Setup ( ( & root_setup, & state, & postfetch, & fs ) ) ,
1267+ BootSetupType :: Setup ( ( & root_setup, & state, & postfetch) ) ,
13021268 repo,
13031269 & id,
13041270 entry,
13051271 & mounted_fs,
13061272 ) ?,
13071273 BootType :: Uki => setup_composefs_uki_boot (
1308- BootSetupType :: Setup ( ( & root_setup, & state, & postfetch, & fs ) ) ,
1274+ BootSetupType :: Setup ( ( & root_setup, & state, & postfetch) ) ,
13091275 repo,
13101276 & id,
13111277 entries,
@@ -1319,11 +1285,7 @@ pub(crate) async fn setup_composefs_boot(
13191285 None ,
13201286 boot_type,
13211287 boot_digest,
1322- & get_container_manifest_and_config ( & get_imgref (
1323- & state. source . imageref . transport . to_string ( ) ,
1324- & state. source . imageref . name ,
1325- ) )
1326- . await ?,
1288+ & pull_result. manifest_digest . to_string ( ) ,
13271289 allow_missing_fsverity,
13281290 )
13291291 . await ?;
0 commit comments