Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 14 additions & 14 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ anstream = "1.0"
anyhow = "1.0.82"
camino = "1.1.6"
canon-json = "0.2.1"
cap-std-ext = "5.1.1"
cap-std-ext = "5.1.2"
cfg-if = "1.0"
chrono = { version = "0.4.38", default-features = false }
clap = "4.5.4"
Expand Down
31 changes: 30 additions & 1 deletion crates/blockdev/src/blockdev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,10 +382,39 @@ pub fn list_dev(dev: &Utf8Path) -> Result<Device> {
.ok_or_else(|| anyhow!("no device output from lsblk for {dev}"))
}

#[context("Finding block device for ZFS dataset {dataset}")]
fn list_dev_for_zfs_dataset(dataset: &str) -> Result<Device> {
let dataset = dataset.strip_prefix("ZFS=").unwrap_or(dataset);
let pool = dataset
.split('/')
.next()
.ok_or_else(|| anyhow!("Invalid ZFS dataset: {dataset}"))?;

let output = Command::new("zpool")
.args(["list", "-H", "-v", "-P", pool])
.run_get_string()
.with_context(|| format!("Querying ZFS pool {pool}"))?;

for line in output.lines() {
if line.starts_with('\t') || line.starts_with(' ') {
let dev_path = line.trim_start().split('\t').next().unwrap_or("").trim();
if dev_path.starts_with('/') {
return list_dev(Utf8Path::new(dev_path));
}
}
}

anyhow::bail!("Could not find a block device backing ZFS pool {pool}")
}

/// List the device containing the filesystem mounted at the given directory.
pub fn list_dev_by_dir(dir: &Dir) -> Result<Device> {
let fsinfo = bootc_mount::inspect_filesystem_of_dir(dir)?;
list_dev(&Utf8PathBuf::from(&fsinfo.source))
let source = &fsinfo.source;
if fsinfo.fstype == "zfs" || source.starts_with("ZFS=") {
return list_dev_for_zfs_dataset(source);
}
list_dev(&Utf8PathBuf::from(source))
}

pub struct LoopbackDevice {
Expand Down
2 changes: 2 additions & 0 deletions crates/lib/src/discoverable_partition_specification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,8 @@ pub const fn this_arch_root() -> &'static str {
ROOT_PPC64
} else if #[cfg(all(target_arch = "powerpc64", target_endian = "little"))] {
ROOT_PPC64_LE
} else if #[cfg(target_arch = "riscv64")] {
ROOT_RISCV64
} else {
compile_error!("Unsupported architecture")
}
Expand Down
46 changes: 32 additions & 14 deletions crates/lib/src/podstorage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use bootc_utils::{AsyncCommandRunExt, CommandRunExt, ExitStatusExt};
use camino::{Utf8Path, Utf8PathBuf};
use cap_std_ext::cap_std::fs::Dir;
use cap_std_ext::cap_tempfile::TempDir;
use cap_std_ext::cmdext::CapStdExtCommandExt;
use cap_std_ext::cmdext::{CapStdExtCommandExt, CmdFds};
use cap_std_ext::dirext::CapStdExtDirExt;
use cap_std_ext::{cap_std, cap_tempfile};
use fn_error_context::context;
Expand Down Expand Up @@ -80,7 +80,12 @@ pub(crate) enum PullMode {

#[allow(unsafe_code)]
#[context("Binding storage roots")]
fn bind_storage_roots(cmd: &mut Command, storage_root: &Dir, run_root: &Dir) -> Result<()> {
pub(crate) fn bind_storage_roots(
cmd: &mut Command,
fds: &mut CmdFds,
storage_root: &Dir,
run_root: &Dir,
) -> Result<()> {
// podman requires an absolute path, for two reasons right now:
// - It writes the file paths into `db.sql`, a sqlite database for unknown reasons
// - It forks helper binaries, so just giving it /proc/self/fd won't work as
Expand Down Expand Up @@ -121,19 +126,16 @@ fn bind_storage_roots(cmd: &mut Command, storage_root: &Dir, run_root: &Dir) ->
Ok(())
})
};
cmd.take_fd_n(run_root, STORAGE_RUN_FD);
fds.take_fd_n(run_root, STORAGE_RUN_FD);
Ok(())
}

// Initialize a `podman` subprocess with:
// - storage overridden to point to to storage_root
// - Authentication (auth.json) using the bootc/ostree owned auth
fn new_podman_cmd_in(sysroot: &Dir, storage_root: &Dir, run_root: &Dir) -> Result<Command> {
let mut cmd = Command::new("podman");
bind_storage_roots(&mut cmd, storage_root, run_root)?;
let run_root = format!("/proc/self/fd/{STORAGE_RUN_FD}");
cmd.args(["--root", STORAGE_ALIAS_DIR, "--runroot", run_root.as_str()]);

/// Set up `REGISTRY_AUTH_FILE` on a command, passing the bootc/ostree
/// auth file via an anonymous tmpfile fd.
///
/// If no bootc-owned auth is configured, an empty `{}` is passed to
/// prevent podman from falling back to user-owned auth paths.
pub(crate) fn setup_auth(cmd: &mut Command, fds: &mut CmdFds, sysroot: &Dir) -> Result<()> {
let tmpd = &cap_std::fs::Dir::open_ambient_dir("/tmp", cap_std::ambient_authority())?;
let mut tempfile = cap_tempfile::TempFile::new_anonymous(tmpd).map(std::io::BufWriter::new)?;

Expand All @@ -154,9 +156,23 @@ fn new_podman_cmd_in(sysroot: &Dir, storage_root: &Dir, run_root: &Dir) -> Resul
.into_std();
let fd: Arc<OwnedFd> = std::sync::Arc::new(tempfile.into());
let target_fd = fd.as_fd().as_raw_fd();
cmd.take_fd_n(fd, target_fd);
fds.take_fd_n(fd, target_fd);
cmd.env("REGISTRY_AUTH_FILE", format!("/proc/self/fd/{target_fd}"));

Ok(())
}

// Initialize a `podman` subprocess with:
// - storage overridden to point to to storage_root
// - Authentication (auth.json) using the bootc/ostree owned auth
fn new_podman_cmd_in(sysroot: &Dir, storage_root: &Dir, run_root: &Dir) -> Result<Command> {
let mut cmd = Command::new("podman");
let mut fds = CmdFds::new();
bind_storage_roots(&mut cmd, &mut fds, storage_root, run_root)?;
let run_root = format!("/proc/self/fd/{STORAGE_RUN_FD}");
cmd.args(["--root", STORAGE_ALIAS_DIR, "--runroot", run_root.as_str()]);
setup_auth(&mut cmd, &mut fds, sysroot)?;
cmd.take_fds(fds);
Ok(cmd)
}

Expand Down Expand Up @@ -435,7 +451,9 @@ impl CStorage {
cmd.stdout(Stdio::null());
// An ephemeral place for the transient state;
let temp_runroot = TempDir::new(cap_std::ambient_authority())?;
bind_storage_roots(&mut cmd, &self.storage_root, &temp_runroot)?;
let mut fds = CmdFds::new();
bind_storage_roots(&mut cmd, &mut fds, &self.storage_root, &temp_runroot)?;
cmd.take_fds(fds);

// The destination (target stateroot) + container storage dest
let storage_dest = &format!(
Expand Down
6 changes: 4 additions & 2 deletions crates/ostree-ext/src/container/skopeo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use super::ImageReference;
use anyhow::{Context, Result};
use cap_std_ext::cmdext::CapStdExtCommandExt;
use cap_std_ext::cmdext::{CapStdExtCommandExt, CmdFds};
use containers_image_proxy::oci_spec::image as oci_image;
use fn_error_context::context;
use io_lifetimes::OwnedFd;
Expand Down Expand Up @@ -80,7 +80,9 @@ pub async fn copy(
cmd.arg("--digestfile");
cmd.arg(digestfile.path());
if let Some((add_fd, n)) = add_fd {
cmd.take_fd_n(add_fd, n);
let mut fds = CmdFds::new();
fds.take_fd_n(add_fd, n);
cmd.take_fds(fds);
}
if let Some(authfile) = authfile {
cmd.arg("--authfile");
Expand Down
6 changes: 4 additions & 2 deletions crates/ostree-ext/src/tar/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use camino::{Utf8Component, Utf8Path, Utf8PathBuf};

use cap_std::io_lifetimes;
use cap_std_ext::cap_std::fs::Dir;
use cap_std_ext::cmdext::CapStdExtCommandExt;
use cap_std_ext::cmdext::{CapStdExtCommandExt, CmdFds};
use cap_std_ext::{cap_std, cap_tempfile};
use containers_image_proxy::oci_spec::image as oci_image;
use fn_error_context::context;
Expand Down Expand Up @@ -423,7 +423,9 @@ pub async fn write_tar(
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.args(["commit"]);
c.take_fd_n(repofd.clone(), 3);
let mut fds = CmdFds::new();
fds.take_fd_n(repofd.clone(), 3);
c.take_fds(fds);
c.arg("--repo=/proc/self/fd/3");
if let Some(sepolicy) = sepolicy.as_ref() {
c.arg("--selinux-policy");
Expand Down
18 changes: 17 additions & 1 deletion hack/provision-derived.sh
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,23 @@ repo_gpgcheck=0
enabled=1
enabled_metadata=1
REPOEOF
dnf -y install bootupd-0.2.32.43.g38208d3

# This unfortunately has "older" versions with higher NEVRA:
#
# # dnf --disablerepo=* --enablerepo=copr:copr.fedorainfracloud.org:group_CoreOS:continuous repoquery bootupd 2> /dev/null
# bootupd-0:0.2.32.45.gb483a63-1.fc45.x86_64
# bootupd-0:202501200321.0.2.25.65.ge296f82-1.fc42.src
# bootupd-0:202501200321.0.2.25.65.ge296f82-1.fc42.x86_64
# bootupd-0:202501210627.0.2.25.67.gefe41b6-1.fc42.src
#
# So we need to be more selective, but also be dynamic to grab newer
# versions
#
# The subscription-manager plugin needs to be disabled because it
# likes to write warnings to stdout which corrupts the NEVRA output
# we're going for here...
bootupd_nevra=$(dnf --disableplugin=subscription-manager --disablerepo=* --enablerepo=copr:copr.fedorainfracloud.org:group_CoreOS:continuous repoquery --latest-limit 1 --arch "$(uname -m)" "bootupd-0.2.*")
dnf -y install ${bootupd_nevra}
rm -f /etc/yum.repos.d/coreos-continuous.repo

dnf clean all
Expand Down
Loading