mirror of
https://github.com/containers/bootc.git
synced 2026-02-05 06:45:13 +01:00
lib: Fix bootc status on non-bootc systems
Previously, `BootedStorage::new()` unconditionally tried to open `/sysroot` before checking the environment type. This caused `bootc status` to fail on non-ostree/composefs systems. (We did work in containers and we had tests for that; but the container case is special cased even earlier) Fixes: https://issues.redhat.com/browse/RHEL-135687 Assisted-by: Claude Code (Opus 4.5) Signed-off-by: Colin Walters <walters@verbum.org>
This commit is contained in:
@@ -145,28 +145,27 @@ pub(crate) enum BootedStorageKind<'a> {
|
|||||||
Composefs(BootedComposefs),
|
Composefs(BootedComposefs),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Open the physical root (/sysroot) and /run directories for a booted system.
|
||||||
|
fn get_physical_root_and_run() -> Result<(Dir, Dir)> {
|
||||||
|
let physical_root = {
|
||||||
|
let d = Dir::open_ambient_dir("/sysroot", cap_std::ambient_authority())
|
||||||
|
.context("Opening /sysroot")?;
|
||||||
|
open_dir_remount_rw(&d, ".".into())?
|
||||||
|
};
|
||||||
|
let run =
|
||||||
|
Dir::open_ambient_dir("/run", cap_std::ambient_authority()).context("Opening /run")?;
|
||||||
|
Ok((physical_root, run))
|
||||||
|
}
|
||||||
|
|
||||||
impl BootedStorage {
|
impl BootedStorage {
|
||||||
/// Create a new booted storage accessor for the given environment.
|
/// Create a new booted storage accessor for the given environment.
|
||||||
///
|
///
|
||||||
/// The caller must have already called `prepare_for_write()` if
|
/// The caller must have already called `prepare_for_write()` if
|
||||||
/// `env.needs_mount_namespace()` is true.
|
/// `env.needs_mount_namespace()` is true.
|
||||||
pub(crate) async fn new(env: Environment) -> Result<Option<Self>> {
|
pub(crate) async fn new(env: Environment) -> Result<Option<Self>> {
|
||||||
let physical_root = {
|
|
||||||
let d = Dir::open_ambient_dir("/sysroot", cap_std::ambient_authority())
|
|
||||||
.context("Opening /sysroot")?;
|
|
||||||
// Remount /sysroot rw only if we are in a new mount ns
|
|
||||||
if env.needs_mount_namespace() {
|
|
||||||
open_dir_remount_rw(&d, ".".into())?
|
|
||||||
} else {
|
|
||||||
d
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let run =
|
|
||||||
Dir::open_ambient_dir("/run", cap_std::ambient_authority()).context("Opening /run")?;
|
|
||||||
|
|
||||||
let r = match &env {
|
let r = match &env {
|
||||||
Environment::ComposefsBooted(cmdline) => {
|
Environment::ComposefsBooted(cmdline) => {
|
||||||
|
let (physical_root, run) = get_physical_root_and_run()?;
|
||||||
let mut composefs = ComposefsRepository::open_path(&physical_root, COMPOSEFS)?;
|
let mut composefs = ComposefsRepository::open_path(&physical_root, COMPOSEFS)?;
|
||||||
if cmdline.insecure {
|
if cmdline.insecure {
|
||||||
composefs.set_insecure(true);
|
composefs.set_insecure(true);
|
||||||
@@ -204,6 +203,7 @@ impl BootedStorage {
|
|||||||
// remount /sysroot as writable, and we call set_mount_namespace_in_use()
|
// remount /sysroot as writable, and we call set_mount_namespace_in_use()
|
||||||
// to indicate we're in a mount namespace. Without actually being in a
|
// to indicate we're in a mount namespace. Without actually being in a
|
||||||
// mount namespace, this would leave the global /sysroot writable.
|
// mount namespace, this would leave the global /sysroot writable.
|
||||||
|
let (physical_root, run) = get_physical_root_and_run()?;
|
||||||
|
|
||||||
let sysroot = ostree::Sysroot::new_default();
|
let sysroot = ostree::Sysroot::new_default();
|
||||||
sysroot.set_mount_namespace_in_use();
|
sysroot.set_mount_namespace_in_use();
|
||||||
@@ -223,6 +223,7 @@ impl BootedStorage {
|
|||||||
|
|
||||||
Some(Self { storage })
|
Some(Self { storage })
|
||||||
}
|
}
|
||||||
|
// For container or non-bootc environments, there's no storage
|
||||||
Environment::Container | Environment::Other => None,
|
Environment::Container | Environment::Other => None,
|
||||||
};
|
};
|
||||||
Ok(r)
|
Ok(r)
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ set -exuo pipefail
|
|||||||
# Check environment
|
# Check environment
|
||||||
printenv
|
printenv
|
||||||
|
|
||||||
|
# This must work outside of a container too
|
||||||
|
bootc status
|
||||||
|
|
||||||
# temp folder to save building files and folders
|
# temp folder to save building files and folders
|
||||||
BOOTC_TEMPDIR=$(mktemp -d)
|
BOOTC_TEMPDIR=$(mktemp -d)
|
||||||
trap 'rm -rf -- "$BOOTC_TEMPDIR"' EXIT
|
trap 'rm -rf -- "$BOOTC_TEMPDIR"' EXIT
|
||||||
|
|||||||
30
tests/container/status-outside-container/run
Executable file
30
tests/container/status-outside-container/run
Executable file
@@ -0,0 +1,30 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Test that `bootc status` works on a non-bootc-deployed system.
|
||||||
|
#
|
||||||
|
# This simulates a "package mode" environment where bootc is installed
|
||||||
|
# via RPM on a traditional system (not deployed via ostree/composefs).
|
||||||
|
# The key is hiding /run/.containerenv so bootc doesn't think it's in a container.
|
||||||
|
#
|
||||||
|
# xref: https://issues.redhat.com/browse/RHEL-135687
|
||||||
|
set -euo pipefail
|
||||||
|
image=$1
|
||||||
|
|
||||||
|
# Run the container with:
|
||||||
|
# - A tmpfs over /run to hide .containerenv (simulates bare metal)
|
||||||
|
# - Unset the 'container' environment variable
|
||||||
|
# - No /sysroot (simulates package mode)
|
||||||
|
# Use --format=humanreadable to get consistent output
|
||||||
|
output=$(podman run --rm \
|
||||||
|
--tmpfs /run \
|
||||||
|
--env container= \
|
||||||
|
"$image" \
|
||||||
|
bootc status --format=humanreadable 2>&1)
|
||||||
|
|
||||||
|
# Verify the output indicates this is not a bootc-deployed system
|
||||||
|
if echo "$output" | grep -q "System is not deployed via bootc"; then
|
||||||
|
echo "ok status-outside-container: correctly reports non-bootc system"
|
||||||
|
else
|
||||||
|
echo "FAIL: unexpected output from bootc status:" >&2
|
||||||
|
echo "$output" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user