diff --git a/Cargo.lock b/Cargo.lock index 76b8b764a..c89964a27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -253,6 +253,7 @@ dependencies = [ "anstream", "anstyle", "anyhow", + "bootc-initramfs-setup", "bootc-internal-blockdev", "bootc-internal-utils", "bootc-kernel-cmdline", diff --git a/crates/lib/Cargo.toml b/crates/lib/Cargo.toml index a555f19ad..13d24c790 100644 --- a/crates/lib/Cargo.toml +++ b/crates/lib/Cargo.toml @@ -22,6 +22,7 @@ bootc-sysusers = { path = "../sysusers" } bootc-tmpfiles = { path = "../tmpfiles" } bootc-utils = { package = "bootc-internal-utils", path = "../utils", version = "0.0.0" } ostree-ext = { path = "../ostree-ext", features = ["bootc"] } +bootc-initramfs-setup = { path = "../initramfs" } # Workspace dependencies anstream = { workspace = true } diff --git a/crates/lib/src/bootc_composefs/mod.rs b/crates/lib/src/bootc_composefs/mod.rs new file mode 100644 index 000000000..33e14d22a --- /dev/null +++ b/crates/lib/src/bootc_composefs/mod.rs @@ -0,0 +1 @@ +pub(crate) mod state; diff --git a/crates/lib/src/bootc_composefs/state.rs b/crates/lib/src/bootc_composefs/state.rs new file mode 100644 index 000000000..23e0aa95e --- /dev/null +++ b/crates/lib/src/bootc_composefs/state.rs @@ -0,0 +1,47 @@ +use std::process::Command; + +use anyhow::{Context, Result}; +use bootc_utils::CommandRunExt; +use camino::Utf8PathBuf; +use fn_error_context::context; + +use rustix::{ + fs::{open, Mode, OFlags, CWD}, + mount::{unmount, UnmountFlags}, + path::Arg, +}; + +/// Mounts an EROFS image and copies the pristine /etc to the deployment's /etc +#[context("Copying etc")] +pub(crate) fn copy_etc_to_state( + sysroot_path: &Utf8PathBuf, + erofs_id: &String, + state_path: &Utf8PathBuf, +) -> Result<()> { + let sysroot_fd = open( + sysroot_path.as_std_path(), + OFlags::PATH | OFlags::DIRECTORY | OFlags::CLOEXEC, + Mode::empty(), + ) + .context("Opening sysroot")?; + + let composefs_fd = bootc_initramfs_setup::mount_composefs_image(&sysroot_fd, &erofs_id, false)?; + + let tempdir = tempfile::tempdir().context("Creating tempdir")?; + + bootc_initramfs_setup::mount_at_wrapper(composefs_fd, CWD, tempdir.path())?; + + // TODO: Replace this with a function to cap_std_ext + let cp_ret = Command::new("cp") + .args([ + "-a", + &format!("{}/etc/.", tempdir.path().as_str()?), + &format!("{state_path}/etc/."), + ]) + .run_capture_stderr(); + + // Unmount regardless of copy succeeding + unmount(tempdir.path(), UnmountFlags::DETACH).context("Unmounting composefs")?; + + cp_ret +} diff --git a/crates/lib/src/install.rs b/crates/lib/src/install.rs index 1caf95efd..123c856fa 100644 --- a/crates/lib/src/install.rs +++ b/crates/lib/src/install.rs @@ -74,6 +74,7 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "install-to-disk")] use self::baseline::InstallBlockDeviceOpts; +use crate::bootc_composefs::state::copy_etc_to_state; use crate::boundimage::{BoundImage, ResolvedBoundImage}; use crate::composefs_consts::{ BOOT_LOADER_ENTRIES, COMPOSEFS_CMDLINE, COMPOSEFS_STAGED_DEPLOYMENT_FNAME, @@ -2208,8 +2209,9 @@ pub(crate) fn write_composefs_state( ) -> Result<()> { let state_path = root_path.join(format!("{STATE_DIR_RELATIVE}/{}", deployment_id.to_hex())); - create_dir_all(state_path.join("etc/upper"))?; - create_dir_all(state_path.join("etc/work"))?; + create_dir_all(state_path.join("etc"))?; + + copy_etc_to_state(&root_path, &deployment_id.to_hex(), &state_path)?; let actual_var_path = root_path.join(SHARED_VAR_PATH); create_dir_all(&actual_var_path)?; diff --git a/crates/lib/src/lib.rs b/crates/lib/src/lib.rs index fb7adeeb4..e2fbf0f98 100644 --- a/crates/lib/src/lib.rs +++ b/crates/lib/src/lib.rs @@ -4,6 +4,7 @@ //! to provide a fully "container native" tool for using //! bootable container images. +mod bootc_composefs; pub(crate) mod bootc_kargs; mod bootloader; mod boundimage;