# bootc composefs-finalize-staged - Technical Guide ## Overview `bootc composefs-finalize-staged` is a hidden command specific to the `composefs-backend` branch that finalizes staged composefs deployments. This command is executed early in the boot process by a systemd service to complete the deployment of staged composefs images. ## Purpose The composefs-finalize-staged command serves several critical functions: 1. **Staged Deployment Finalization**: Completes the deployment of staged composefs images 2. **Boot Process Integration**: Executes early in the boot process via systemd service 3. **Filesystem Operations**: Performs EROFS mounting and /etc merging operations 4. **Bootloader Management**: Updates bootloader entries for staged deployments 5. **System State Management**: Manages composefs deployment state transitions ## Command Structure ```rust #[cfg(feature = "composefs-backend")] ComposefsFinalizeStaged, ``` The command is conditionally compiled only when the `composefs-backend` feature is enabled. ## Core Functionality ### Purpose The command finalizes staged composefs deployments by: - Mounting the booted EROFS image to access pristine /etc configuration - Performing 3-way merge of /etc configurations (pristine, current, new) - Updating bootloader entries for staged deployments - Managing bootloader-specific operations (GRUB vs systemd-boot) ### Usage ```bash bootc composefs-finalize-staged ``` ### Implementation ```rust pub(crate) async fn composefs_native_finalize() -> Result<()> { let host = composefs_deployment_status().await?; let booted_composefs = host.require_composefs_booted()?; let Some(staged_depl) = host.status.staged.as_ref() else { tracing::debug!("No staged deployment found"); return Ok(()); }; let staged_composefs = staged_depl.composefs.as_ref().ok_or(anyhow::anyhow!( "Staged deployment is not a composefs deployment" ))?; // Mount the booted EROFS image to get pristine etc let sysroot = open_dir(CWD, "/sysroot")?; let composefs_fd = mount_composefs_image(&sysroot, &booted_composefs.verity, false)?; let erofs_tmp_mnt = TempMount::mount_fd(&composefs_fd)?; // Perform the /etc merge let pristine_etc = Dir::open_ambient_dir(erofs_tmp_mnt.dir.path().join("etc"), ambient_authority())?; let current_etc = Dir::open_ambient_dir("/etc", ambient_authority())?; let new_etc_path = Path::new(STATE_DIR_ABS) .join(&staged_composefs.verity) .join("etc"); let new_etc = Dir::open_ambient_dir(new_etc_path, ambient_authority())?; let (pristine_files, current_files, new_files) = traverse_etc(&pristine_etc, ¤t_etc, &new_etc)?; let diff = compute_diff(&pristine_files, ¤t_files)?; merge(¤t_etc, ¤t_files, &new_etc, &new_files, diff)?; // Unmount EROFS drop(erofs_tmp_mnt); let sysroot_parent = get_sysroot_parent_dev()?; // NOTE: Assumption here that ESP will always be present let (esp_part, ..) = get_esp_partition(&sysroot_parent)?; let esp_mount = TempMount::mount_dev(&esp_part)?; let boot_dir = Dir::open_ambient_dir("/sysroot/boot", ambient_authority()) .context("Opening sysroot/boot")?; // NOTE: Assuming here we won't have two bootloaders at the same time match booted_composefs.bootloader { Bootloader::Grub => match staged_composefs.boot_type { BootType::Bls => { let entries_dir = boot_dir.open_dir("loader")?; rename_exchange_bls_entries(&entries_dir)?; } BootType::Uki => finalize_staged_grub_uki(&esp_mount.fd, &boot_dir)?, }, Bootloader::Systemd => match staged_composefs.boot_type { BootType::Bls => { let entries_dir = esp_mount.fd.open_dir("loader")?; rename_exchange_bls_entries(&entries_dir)?; } BootType::Uki => rename_staged_uki_entries(&esp_mount.fd)?, }, }; Ok(()) } ``` ## Technical Details ### 1. Deployment Status Retrieval The command first retrieves the current composefs deployment status: ```rust let host = composefs_deployment_status().await?; let booted_composefs = host.require_composefs_booted()?; ``` ### 2. Staged Deployment Validation The command validates that a staged deployment exists and is a composefs deployment: ```rust let Some(staged_depl) = host.status.staged.as_ref() else { tracing::debug!("No staged deployment found"); return Ok(()); }; let staged_composefs = staged_depl.composefs.as_ref().ok_or(anyhow::anyhow!( "Staged deployment is not a composefs deployment" ))?; ``` ### 3. EROFS Image Mounting The command mounts the booted EROFS image to access pristine /etc configuration: ```rust let sysroot = open_dir(CWD, "/sysroot")?; let composefs_fd = mount_composefs_image(&sysroot, &booted_composefs.verity, false)?; let erofs_tmp_mnt = TempMount::mount_fd(&composefs_fd)?; ``` ### 4. /etc Configuration Merging The command performs a 3-way merge of /etc configurations: ```rust let pristine_etc = Dir::open_ambient_dir(erofs_tmp_mnt.dir.path().join("etc"), ambient_authority())?; let current_etc = Dir::open_ambient_dir("/etc", ambient_authority())?; let new_etc_path = Path::new(STATE_DIR_ABS) .join(&staged_composefs.verity) .join("etc"); let new_etc = Dir::open_ambient_dir(new_etc_path, ambient_authority())?; let (pristine_files, current_files, new_files) = traverse_etc(&pristine_etc, ¤t_etc, &new_etc)?; let diff = compute_diff(&pristine_files, ¤t_files)?; merge(¤t_etc, ¤t_files, &new_etc, &new_files, diff)?; ``` ### 5. Bootloader Management The command updates bootloader entries based on the bootloader type and boot type: ```rust match booted_composefs.bootloader { Bootloader::Grub => match staged_composefs.boot_type { BootType::Bls => { let entries_dir = boot_dir.open_dir("loader")?; rename_exchange_bls_entries(&entries_dir)?; } BootType::Uki => finalize_staged_grub_uki(&esp_mount.fd, &boot_dir)?, }, Bootloader::Systemd => match staged_composefs.boot_type { BootType::Bls => { let entries_dir = esp_mount.fd.open_dir("loader")?; rename_exchange_bls_entries(&entries_dir)?; } BootType::Uki => rename_staged_uki_entries(&esp_mount.fd)?, }, } ``` ## Command Routing The command is routed through the main CLI dispatcher: ```rust #[cfg(feature = "composefs-backend")] Opt::ComposefsFinalizeStaged => composefs_native_finalize().await, ``` ## Systemd Integration ### Service Definition The command is executed by a systemd service: ```ini [Unit] Description=Composefs Finalize Staged Deployment Documentation=man:bootc(1) DefaultDependencies=no RequiresMountsFor=/sysroot After=local-fs.target Before=basic.target final.target After=systemd-journal-flush.service Conflicts=final.target [Service] Type=oneshot RemainAfterExit=yes ExecStop=/usr/bin/bootc composefs-finalize-staged TimeoutStopSec=5m ProtectHome=yes ReadOnlyPaths=/etc ``` ### Service Characteristics - **Type**: oneshot - runs once and exits - **RemainAfterExit**: yes - service remains active after completion - **ExecStop**: executes the composefs-finalize-staged command - **TimeoutStopSec**: 5 minutes - long timeout for slow media - **ProtectHome**: yes - sandboxing for security - **ReadOnlyPaths**: /etc - prevents modification of current /etc ## Bootloader Operations ### GRUB Bootloader #### BLS (Boot Loader Specification) Entries ```rust BootType::Bls => { let entries_dir = boot_dir.open_dir("loader")?; rename_exchange_bls_entries(&entries_dir)?; } ``` #### UKI (Unified Kernel Image) Entries ```rust BootType::Uki => finalize_staged_grub_uki(&esp_mount.fd, &boot_dir)?, ``` ### systemd-boot Bootloader #### BLS Entries ```rust BootType::Bls => { let entries_dir = esp_mount.fd.open_dir("loader")?; rename_exchange_bls_entries(&entries_dir)?; } ``` #### UKI Entries ```rust BootType::Uki => rename_staged_uki_entries(&esp_mount.fd)?, ``` ## Filesystem Operations ### 1. EROFS Mounting The command mounts EROFS images for access to pristine configuration: ```rust let composefs_fd = mount_composefs_image(&sysroot, &booted_composefs.verity, false)?; let erofs_tmp_mnt = TempMount::mount_fd(&composefs_fd)?; ``` ### 2. ESP Partition Mounting The command mounts the ESP partition for bootloader operations: ```rust let sysroot_parent = get_sysroot_parent_dev()?; let (esp_part, ..) = get_esp_partition(&sysroot_parent)?; let esp_mount = TempMount::mount_dev(&esp_part)?; ``` ### 3. /etc Configuration Merging The command performs 3-way merge of /etc configurations: - **Pristine**: Original configuration from EROFS image - **Current**: Current system configuration - **New**: New configuration from staged deployment ## Error Handling ### 1. Common Error Scenarios #### No Staged Deployment ```rust let Some(staged_depl) = host.status.staged.as_ref() else { tracing::debug!("No staged deployment found"); return Ok(()); }; ``` #### Non-Composefs Deployment ```rust let staged_composefs = staged_depl.composefs.as_ref().ok_or(anyhow::anyhow!( "Staged deployment is not a composefs deployment" ))?; ``` #### Filesystem Access Errors ```rust let sysroot = open_dir(CWD, "/sysroot")?; let composefs_fd = mount_composefs_image(&sysroot, &booted_composefs.verity, false)?; ``` ### 2. Error Recovery The command provides comprehensive error context: ```rust #[context("Getting composefs deployment status")] pub(crate) async fn composefs_deployment_status() -> Result { // Implementation with automatic error context } ``` ## Performance Characteristics ### 1. Execution Time - **Fast**: Optimized for early boot execution - **Efficient**: Minimal overhead for staging operations - **Atomic**: Single atomic operation ### 2. Resource Usage - **Low CPU**: Minimal CPU usage - **Low Memory**: Minimal memory usage - **Disk I/O**: Efficient filesystem operations ### 3. System Impact - **Early Boot**: Executes early in boot process - **Filesystem Access**: Accesses EROFS and ESP partitions - **Bootloader Updates**: Updates bootloader entries ## Security Considerations ### 1. Privilege Requirements The command requires appropriate privileges for: - Filesystem mounting operations - Bootloader entry modifications - System state management ### 2. Sandboxing The systemd service provides sandboxing: - **ProtectHome**: yes - restricts home directory access - **ReadOnlyPaths**: /etc - prevents /etc modification ### 3. Access Control The command accesses: - **EROFS images**: For pristine configuration - **ESP partition**: For bootloader operations - **System state**: For deployment management ## Integration Points ### 1. Composefs Backend The command integrates with the composefs backend: ```rust #[cfg(feature = "composefs-backend")] use crate::bootc_composefs::{ finalize::composefs_native_finalize, rollback::composefs_rollback, status::composefs_booted, switch::switch_composefs, update::upgrade_composefs, }; ``` ### 2. Systemd Service The command integrates with systemd for early boot execution: ```ini ExecStop=/usr/bin/bootc composefs-finalize-staged ``` ### 3. Bootloader Management The command integrates with bootloader management: ```rust match booted_composefs.bootloader { Bootloader::Grub => { /* GRUB operations */ } Bootloader::Systemd => { /* systemd-boot operations */ } } ``` ## Use Cases ### 1. Staged Deployment Finalization The primary use case is finalizing staged composefs deployments: ```bash # Executed by systemd service during boot systemctl start composefs-finalize-staged.service ``` ### 2. Boot Process Integration The command integrates with the boot process: ```bash # Service runs early in boot process systemctl enable composefs-finalize-staged.service ``` ### 3. Configuration Management The command manages /etc configuration merging: ```bash # Performs 3-way merge of /etc configurations # - Pristine: Original from EROFS # - Current: Current system # - New: Staged deployment ``` ### 4. Bootloader Updates The command updates bootloader entries: ```bash # Updates GRUB or systemd-boot entries # - BLS entries for Boot Loader Specification # - UKI entries for Unified Kernel Image ``` ## Testing and Validation ### 1. Unit Tests ```rust #[cfg(test)] mod tests { use super::*; #[tokio::test] async fn test_composefs_native_finalize() { // Test finalization process let result = composefs_native_finalize().await; assert!(result.is_ok()); } } ``` ### 2. Integration Tests ```rust #[tokio::test] async fn test_composefs_finalize_integration() { // Test with staged deployment let test_env = TestEnvironment::new().await.unwrap(); // Create staged deployment test_env.create_staged_deployment().await.unwrap(); // Test finalization let result = composefs_native_finalize().await; assert!(result.is_ok()); } ``` ## Best Practices ### 1. Usage Guidelines - **Systemd Integration**: Use systemd service for execution - **Early Boot**: Execute early in boot process - **Error Handling**: Implement proper error handling - **Logging**: Use appropriate logging levels ### 2. Security Considerations - **Privilege Requirements**: Ensure appropriate privileges - **Sandboxing**: Use systemd sandboxing features - **Access Control**: Limit filesystem access - **Error Recovery**: Implement proper error recovery ### 3. Performance Optimization - **Efficient Operations**: Use efficient filesystem operations - **Resource Management**: Manage resources appropriately - **Timeout Handling**: Handle timeouts gracefully - **Error Recovery**: Implement proper error recovery ## Future Enhancements ### 1. Enhanced Error Handling Enhanced error handling and recovery: ```rust pub(crate) struct FinalizeOptions { pub retry_attempts: u32, pub timeout_seconds: u64, pub rollback_on_failure: bool, } ``` ### 2. Performance Monitoring Performance monitoring and metrics: ```rust pub(crate) struct FinalizeMetrics { pub execution_time: Duration, pub files_processed: u64, pub merge_operations: u64, } ``` ### 3. Configuration Options Configuration options for finalization: ```rust pub(crate) struct FinalizeConfig { pub enable_etc_merge: bool, pub enable_bootloader_update: bool, pub backup_original: bool, } ``` This technical guide provides comprehensive understanding of the bootc composefs-finalize-staged system's functionality, implementation, and usage patterns.