# bootc Installation Source Code Analysis ## Overview This document provides a detailed analysis of the bootc installation process based on the source code examination. The analysis covers the key components, data structures, and execution flow of the installation system. ## Core Data Structures ### 1. State Management ```rust // From install.rs:373-390 pub(crate) struct State { pub(crate) source: SourceInfo, pub(crate) selinux_state: SELinuxFinalState, pub(crate) config_opts: InstallConfigOpts, pub(crate) target_imgref: ostree_container::OstreeImageReference, pub(crate) prepareroot_config: HashMap, pub(crate) install_config: Option, pub(crate) root_ssh_authorized_keys: Option, pub(crate) host_is_container: bool, pub(crate) container_root: Dir, pub(crate) tempdir: TempDir, } ``` **Key Components**: - `source`: Container image information and metadata - `selinux_state`: SELinux configuration state - `target_imgref`: Target image reference for updates - `prepareroot_config`: OSTree prepareroot configuration - `install_config`: Installation-specific configuration ### 2. Source Information ```rust // From install.rs:360-370 pub(crate) struct SourceInfo { pub(crate) imageref: ostree_container::ImageReference, pub(crate) digest: Option, pub(crate) selinux: bool, pub(crate) in_host_mountns: bool, } ``` **Purpose**: Encapsulates information about the source container image **Key Fields**: - `imageref`: Container image reference - `digest`: Image digest for verification - `selinux`: SELinux policy presence - `in_host_mountns`: Host mount namespace access ### 3. Root Setup ```rust // From install.rs:928-942 pub(crate) struct RootSetup { #[cfg(feature = "install-to-disk")] luks_device: Option, device_info: bootc_blockdev::PartitionTable, physical_root_path: Utf8PathBuf, physical_root: Dir, rootfs_uuid: Option, skip_finalize: bool, boot: Option, kargs: Vec, } ``` **Purpose**: Manages target filesystem setup and configuration **Key Fields**: - `device_info`: Partition table information - `physical_root`: Target filesystem directory - `rootfs_uuid`: Root filesystem UUID - `boot`: Boot filesystem mount specification - `kargs`: Kernel arguments ## Installation Flow Analysis ### 1. Preparation Phase #### Container Environment Detection ```rust // From install.rs:520-538 pub(crate) fn from_container( root: &Dir, container_info: &ContainerExecutionInfo, ) -> Result { if !container_info.engine.starts_with("podman") { anyhow::bail!("Currently this command only supports being executed via podman"); } if container_info.imageid.is_empty() { anyhow::bail!("Invalid empty imageid"); } let imageref = ostree_container::ImageReference { transport: ostree_container::Transport::ContainerStorage, name: container_info.image.clone(), }; let digest = crate::podman::imageid_to_digest(&container_info.imageid)?; Self::new(imageref, Some(digest), root, true) } ``` **Key Operations**: 1. Validate podman runtime 2. Extract image reference from container environment 3. Resolve image digest 4. Detect SELinux policy presence #### Privilege Validation ```rust // From install.rs:1061-1082 fn require_host_pidns() -> Result<()> { if rustix::process::getpid().is_init() { anyhow::bail!("This command must be run with the podman --pid=host flag") } tracing::trace!("OK: we're not pid 1"); Ok(()) } fn require_host_userns() -> Result<()> { let proc1 = "/proc/1"; let pid1_uid = Path::new(proc1) .metadata() .with_context(|| format!("Querying {proc1}"))? .uid(); ensure!(pid1_uid == 0, "{proc1} is owned by {pid1_uid}, not zero; this command must be run in the root user namespace"); tracing::trace!("OK: we're in a matching user namespace with pid1"); Ok(()) } ``` **Validation Steps**: 1. Check process ID (not PID 1) 2. Verify host user namespace access 3. Validate root privileges ### 2. OSTree Initialization #### Repository Setup ```rust // From install.rs:591-694 async fn initialize_ostree_root(state: &State, root_setup: &RootSetup) -> Result<(Storage, bool)> { let sepolicy = state.load_policy()?; let sepolicy = sepolicy.as_ref(); let rootfs_dir = &root_setup.physical_root; let cancellable = gio::Cancellable::NONE; let stateroot = state.stateroot(); let has_ostree = rootfs_dir.try_exists("ostree/repo")?; if !has_ostree { Task::new("Initializing ostree layout", "ostree") .args(["admin", "init-fs", "--modern", "."]) .cwd(rootfs_dir)? .run()?; } else { println!("Reusing extant ostree layout"); let path = ".".into(); let _ = crate::utils::open_dir_remount_rw(rootfs_dir, path) .context("remounting target as read-write")?; crate::utils::remove_immutability(rootfs_dir, path)?; } // ... repository configuration } ``` **Key Operations**: 1. Check for existing OSTree repository 2. Initialize repository if needed 3. Configure repository settings 4. Set up stateroot 5. Configure SELinux labeling #### Repository Configuration ```rust // From install.rs:624-629 for (k, v) in DEFAULT_REPO_CONFIG.iter() { Command::new("ostree") .args(["config", "--repo", "ostree/repo", "set", k, v]) .cwd_dir(rootfs_dir.try_clone()?) .run_capture_stderr()?; } ``` **Default Configuration**: - `sysroot.bootloader=none` - `sysroot.bootprefix=true` - `sysroot.readonly=true` ### 3. Container Image Deployment #### Image Pulling ```rust // From install.rs:755-769 let pulled_image = match prepare_for_pull(repo, &spec_imgref, Some(&state.target_imgref)) .await? { PreparedPullResult::AlreadyPresent(existing) => existing, PreparedPullResult::Ready(image_meta) => { check_disk_space(root_setup.physical_root.as_fd(), &image_meta, &spec_imgref)?; pull_from_prepared(&spec_imgref, false, ProgressWriter::default(), *image_meta).await? } }; ``` **Process**: 1. Prepare image for pulling 2. Check disk space requirements 3. Pull image into OSTree repository 4. Handle already present images #### Deployment ```rust // From install.rs:826-836 let mut options = ostree_container::deploy::DeployOpts::default(); options.kargs = Some(kargs.as_slice()); options.target_imgref = Some(&state.target_imgref); options.proxy_cfg = proxy_cfg; options.skip_completion = true; options.no_clean = has_ostree; let imgstate = crate::utils::async_task_with_spinner( "Deploying container image", ostree_container::deploy::deploy(&sysroot, stateroot, &src_imageref, Some(options)), ) .await?; ``` **Deployment Options**: - Kernel arguments configuration - Target image reference - Proxy configuration - Completion skipping - Cleanup control ### 4. Bootloader Installation #### Bootupd Integration ```rust // From install.rs:1337-1343 crate::bootloader::install_via_bootupd( &rootfs.device_info, &rootfs.physical_root_path, &state.config_opts, &deployment_path.as_str(), )?; ``` **Architecture Support**: - x86_64/aarch64: GRUB2 via bootupd - s390x: zipl implementation - Other: Platform-specific ### 5. Kernel Argument Processing #### Argument Collection ```rust // From install.rs:773-825 let kargsd = crate::bootc_kargs::get_kargs_from_ostree_root( &sysroot.repo(), merged_ostree_root.downcast_ref().unwrap(), std::env::consts::ARCH, )?; let kargsd = kargsd.iter().map(|s| s.as_str()); let install_config_kargs = state .install_config .as_ref() .and_then(|c| c.kargs.as_ref()) .into_iter() .flatten() .map(|s| s.as_str()); let kargs = root_setup .kargs .iter() .map(|v| v.as_str()) .chain(install_config_kargs) .chain(kargsd) .chain(state.config_opts.karg.iter().flatten().map(|v| v.as_str())) .collect::>(); ``` **Argument Sources (Priority Order)**: 1. Root filesystem kargs 2. Install configuration kargs 3. Container image kargs.d files 4. CLI-specified kargs ### 6. Filesystem Finalization #### Optimization Process ```rust // From install.rs:1033-1058 pub(crate) fn finalize_filesystem( fsname: &str, root: &Dir, path: impl AsRef, ) -> Result<()> { let path = path.as_ref(); // fstrim ensures the underlying block device knows about unused space Task::new(format!("Trimming {fsname}"), "fstrim") .args(["--quiet-unsupported", "-v", path.as_str()]) .cwd(root)? .run()?; // Remounting readonly will flush outstanding writes Task::new(format!("Finalizing filesystem {fsname}"), "mount") .cwd(root)? .args(["-o", "remount,ro", path.as_str()]) .run()?; // Finally, freezing (and thawing) the filesystem will flush the journal for a in ["-f", "-u"] { Command::new("fsfreeze") .cwd_dir(root.try_clone()?) .args([a, path.as_str()]) .run_capture_stderr()?; } Ok(()) } ``` **Finalization Steps**: 1. Trim filesystem (fstrim) 2. Remount read-only 3. Freeze and thaw filesystem 4. Flush journal ## Error Handling Patterns ### 1. Contextual Error Handling ```rust // From install.rs:393-404 #[context("Loading SELinux policy")] pub(crate) fn load_policy(&self) -> Result> { if !self.selinux_state.enabled() { return Ok(None); } let r = lsm::new_sepolicy_at(&self.container_root)? .ok_or_else(|| anyhow::anyhow!("SELinux enabled, but no policy found in root"))?; tracing::debug!("Loaded SELinux policy: {}", r.csum().unwrap()); Ok(Some(r)) } ``` ### 2. Resource Validation ```rust // From install.rs:696-715 fn check_disk_space( repo_fd: impl AsFd, image_meta: &PreparedImportMeta, imgref: &ImageReference, ) -> Result<()> { let stat = rustix::fs::fstatvfs(repo_fd)?; let bytes_avail: u64 = stat.f_bsize * stat.f_bavail; if image_meta.bytes_to_fetch > bytes_avail { anyhow::bail!( "Insufficient free space for {image} (available: {bytes_avail} required: {bytes_to_fetch})", bytes_avail = ostree_ext::glib::format_size(bytes_avail), bytes_to_fetch = ostree_ext::glib::format_size(image_meta.bytes_to_fetch), image = imgref.image, ); } Ok(()) } ``` ### 3. Graceful Degradation ```rust // From install.rs:1001-1029 pub(crate) fn reexecute_self_for_selinux_if_needed( srcdata: &SourceInfo, override_disable_selinux: bool, ) -> Result { if srcdata.selinux { let host_selinux = crate::lsm::selinux_enabled()?; let r = if override_disable_selinux { println!("notice: Target has SELinux enabled, overriding to disable"); SELinuxFinalState::ForceTargetDisabled } else if host_selinux { setup_sys_mount("selinuxfs", SELINUXFS)?; let g = crate::lsm::selinux_ensure_install_or_setenforce()?; SELinuxFinalState::Enabled(g) } else { SELinuxFinalState::HostDisabled }; Ok(r) } else { Ok(SELinuxFinalState::Disabled) } } ``` ## Performance Optimizations ### 1. Async Operations ```rust // From install.rs:1538-1543 let rootfs = tokio::task::spawn_blocking(move || { baseline::install_create_rootfs(&state, block_opts) }) .await??; ``` ### 2. Parallel Processing - Container image pulling - Filesystem operations - Bootloader installation ### 3. Resource Management - Temporary directory cleanup - File descriptor management - Memory usage optimization ## Security Considerations ### 1. SELinux Integration - Policy detection and loading - Context preservation - Labeling operations ### 2. Privilege Management - Minimal privilege requirements - Capability dropping - Namespace isolation ### 3. Input Validation - Command argument validation - Path sanitization - Resource limit enforcement ## Testing and Validation ### 1. Unit Tests ```rust // From install.rs:2064-2153 #[cfg(test)] mod tests { use super::*; #[test] fn install_opts_serializable() { let c: InstallToDiskOpts = serde_json::from_value(serde_json::json!({ "device": "/dev/vda" })) .unwrap(); assert_eq!(c.block_opts.device, "/dev/vda"); } } ``` ### 2. Integration Tests - End-to-end installation testing - Error condition testing - Performance testing ### 3. Validation Steps - Container image integrity - Filesystem compatibility - Bootloader support - Kernel compatibility This analysis provides a comprehensive understanding of the bootc installation process from a source code perspective, covering the key components, execution flow, and implementation details.