From 3e6ea489b703fcee723bd697c2caa1a3dc738dbd Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Thu, 19 Dec 2024 13:22:27 -0500 Subject: [PATCH] `install` feature is always on, add `install-to-disk` I consider `bootc install to-filesystem` support a key feature of bootc. In theory today one can still set up a system directly with `ostree` and we will continue to support that. But things like logically bound images we do want to be initialized from the start and that's with `bootc install to-filesystem`. Maintaining the feature just has a logistical annoyance any time one touches the install code as we often end up needing to carefully `#[cfg(feature = "install")]` in many places in an infectious way. Also as we head towards enabling factory reset https://github.com/containers/bootc/issues/404 we really do want some of the install code enabled there. However, `to-disk` is much more of a "demo". I don't want bootc to grow too much knowledge around block devices. Complex setups (LVM, LUKS) etc. are the domain of external installers and provisioning tools. So the feature gate is now on that (which is still on by default). We ended up with more `#[cfg(feature = "install-to-disk")]` than I'd have liked, but some of that can be fixed subsequently. Signed-off-by: Colin Walters --- lib/Cargo.toml | 8 +++++--- lib/src/blockdev.rs | 16 +++++++++++++++- lib/src/bootloader.rs | 3 +++ lib/src/boundimage.rs | 3 --- lib/src/cli.rs | 9 ++------- lib/src/install.rs | 16 +++++++++++++--- lib/src/install/baseline.rs | 18 ++++-------------- lib/src/install/config.rs | 27 +++++++++++++++++++++++---- lib/src/kargs.rs | 1 - lib/src/lib.rs | 6 ------ lib/src/lsm.rs | 23 ++--------------------- lib/src/mount.rs | 4 ++++ lib/src/podman.rs | 8 -------- lib/src/status.rs | 1 - lib/src/utils.rs | 8 -------- 15 files changed, 71 insertions(+), 80 deletions(-) diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 01bc92176..9ccee100b 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -53,9 +53,11 @@ similar-asserts = { workspace = true } static_assertions = { workspace = true } [features] -default = ["install"] -# This feature enables `bootc install`. Disable if you always want to use an external installer. -install = [] +default = ["install-to-disk"] +# This feature enables `bootc install to-disk`, which is considered just a "demo" +# or reference installer; we expect most nontrivial use cases to be using +# `bootc install to-filesystem`. +install-to-disk = [] # This featuares enables `bootc internals publish-rhsm-facts` to integrate with # Red Hat Subscription Manager rhsm = [] diff --git a/lib/src/blockdev.rs b/lib/src/blockdev.rs index c086868db..d4b4ed657 100644 --- a/lib/src/blockdev.rs +++ b/lib/src/blockdev.rs @@ -1,15 +1,20 @@ use std::collections::HashMap; +#[cfg(feature = "install-to-disk")] use std::env; +#[cfg(feature = "install-to-disk")] use std::path::Path; use std::process::Command; use std::sync::OnceLock; use anyhow::{anyhow, Context, Result}; -use camino::{Utf8Path, Utf8PathBuf}; +use camino::Utf8Path; +#[cfg(feature = "install-to-disk")] +use camino::Utf8PathBuf; use fn_error_context::context; use regex::Regex; use serde::Deserialize; +#[cfg(feature = "install-to-disk")] use crate::install::run_in_host_mountns; use crate::task::Task; use bootc_utils::CommandRunExt; @@ -47,6 +52,7 @@ impl Device { self.path.clone().unwrap_or(format!("/dev/{}", &self.name)) } + #[allow(dead_code)] pub(crate) fn has_children(&self) -> bool { self.children.as_ref().map_or(false, |v| !v.is_empty()) } @@ -86,6 +92,7 @@ impl Device { } #[context("Failed to wipe {dev}")] +#[cfg(feature = "install-to-disk")] pub(crate) fn wipefs(dev: &Utf8Path) -> Result<()> { Task::new_and_run( format!("Wiping device {dev}"), @@ -161,6 +168,7 @@ impl PartitionTable { } // Find the partition with the given offset (starting at 1) + #[allow(dead_code)] pub(crate) fn find_partno(&self, partno: u32) -> Result<&Partition> { let r = self .partitions @@ -171,6 +179,7 @@ impl PartitionTable { } impl Partition { + #[allow(dead_code)] pub(crate) fn path(&self) -> &Utf8Path { self.node.as_str().into() } @@ -185,10 +194,12 @@ pub(crate) fn partitions_of(dev: &Utf8Path) -> Result { Ok(o.partitiontable) } +#[cfg(feature = "install-to-disk")] pub(crate) struct LoopbackDevice { pub(crate) dev: Option, } +#[cfg(feature = "install-to-disk")] impl LoopbackDevice { // Create a new loopback block device targeting the provided file path. pub(crate) fn new(path: &Path) -> Result { @@ -243,6 +254,7 @@ impl LoopbackDevice { } } +#[cfg(feature = "install-to-disk")] impl Drop for LoopbackDevice { fn drop(&mut self) { // Best effort to unmount if we're dropped without invoking `close` @@ -250,6 +262,7 @@ impl Drop for LoopbackDevice { } } +#[cfg(feature = "install-to-disk")] pub(crate) fn udev_settle() -> Result<()> { // There's a potential window after rereading the partition table where // udevd hasn't yet received updates from the kernel, settle will return @@ -311,6 +324,7 @@ pub(crate) fn find_parent_devices(device: &str) -> Result> { } /// Parse a string into mibibytes +#[cfg(feature = "install-to-disk")] pub(crate) fn parse_size_mib(mut s: &str) -> Result { let suffixes = [ ("MiB", 1u64), diff --git a/lib/src/bootloader.rs b/lib/src/bootloader.rs index 2a696f1fd..c079552ab 100644 --- a/lib/src/bootloader.rs +++ b/lib/src/bootloader.rs @@ -7,8 +7,11 @@ use crate::task::Task; /// The name of the mountpoint for efi (as a subdirectory of /boot, or at the toplevel) pub(crate) const EFI_DIR: &str = "efi"; +#[cfg(feature = "install-to-disk")] pub(crate) const ESP_GUID: &str = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"; +#[cfg(feature = "install-to-disk")] pub(crate) const PREPBOOT_GUID: &str = "9E1A2D38-C612-4316-AA26-8B49521E5A8B"; +#[cfg(feature = "install-to-disk")] pub(crate) const PREPBOOT_LABEL: &str = "PowerPC-PReP-boot"; #[cfg(target_arch = "powerpc64")] /// We make a best-effort to support MBR partitioning too. diff --git a/lib/src/boundimage.rs b/lib/src/boundimage.rs index 24fe8cb90..20e744e7d 100644 --- a/lib/src/boundimage.rs +++ b/lib/src/boundimage.rs @@ -10,7 +10,6 @@ use camino::Utf8Path; use cap_std_ext::cap_std::fs::Dir; use cap_std_ext::dirext::CapStdExtDirExt; use fn_error_context::context; -#[cfg(feature = "install")] use ostree_ext::containers_image_proxy; use ostree_ext::ostree::Deployment; @@ -33,7 +32,6 @@ pub(crate) struct BoundImage { } #[derive(Debug, PartialEq, Eq)] -#[cfg(feature = "install")] pub(crate) struct ResolvedBoundImage { pub(crate) image: String, pub(crate) digest: String, @@ -104,7 +102,6 @@ pub(crate) fn query_bound_images(root: &Dir) -> Result> { Ok(bound_images) } -#[cfg(feature = "install")] impl ResolvedBoundImage { #[context("resolving bound image {}", src.image)] pub(crate) async fn from_image(src: &BoundImage) -> Result { diff --git a/lib/src/cli.rs b/lib/src/cli.rs index c3b441893..78669edd8 100644 --- a/lib/src/cli.rs +++ b/lib/src/cli.rs @@ -184,7 +184,6 @@ pub(crate) struct StatusOpts { pub(crate) booted: bool, } -#[cfg(feature = "install")] #[derive(Debug, clap::Subcommand, PartialEq, Eq)] pub(crate) enum InstallOpts { /// Install to the target block device. @@ -197,6 +196,7 @@ pub(crate) enum InstallOpts { /// in the container image, alongside any required system partitions such as /// the EFI system partition. Use `install to-filesystem` for anything more /// complex such as RAID, LVM, LUKS etc. + #[cfg(feature = "install-to-disk")] ToDisk(crate::install::InstallToDiskOpts), /// Install to an externally created filesystem structure. /// @@ -384,7 +384,6 @@ pub(crate) enum InternalsOpts { #[clap(allow_hyphen_values = true)] args: Vec, }, - #[cfg(feature = "install")] /// Invoked from ostree-ext to complete an installation. BootcInstallCompletion { /// Path to the sysroot @@ -525,7 +524,6 @@ pub(crate) enum Opt { /// An installation is not simply a copy of the container filesystem, but includes /// other setup and metadata. #[clap(subcommand)] - #[cfg(feature = "install")] Install(InstallOpts), /// Operations which can be executed as part of a container build. #[clap(subcommand)] @@ -537,7 +535,6 @@ pub(crate) enum Opt { #[clap(subcommand, hide = true)] Image(ImageOpts), /// Execute the given command in the host mount namespace - #[cfg(feature = "install")] #[clap(hide = true)] ExecInHostMountNamespace { #[clap(trailing_var_arg = true, allow_hyphen_values = true)] @@ -1053,8 +1050,8 @@ async fn run_from_opt(opt: Opt) -> Result<()> { } } }, - #[cfg(feature = "install")] Opt::Install(opts) => match opts { + #[cfg(feature = "install-to-disk")] InstallOpts::ToDisk(opts) => crate::install::install_to_disk(opts).await, InstallOpts::ToFilesystem(opts) => { crate::install::install_to_filesystem(opts, false).await @@ -1068,7 +1065,6 @@ async fn run_from_opt(opt: Opt) -> Result<()> { crate::install::completion::run_from_anaconda(rootfs).await } }, - #[cfg(feature = "install")] Opt::ExecInHostMountNamespace { args } => { crate::install::exec_in_host_mountns(args.as_slice()) } @@ -1104,7 +1100,6 @@ async fn run_from_opt(opt: Opt) -> Result<()> { let sysroot = get_storage().await?; crate::deploy::cleanup(&sysroot).await } - #[cfg(feature = "install")] InternalsOpts::BootcInstallCompletion { sysroot, stateroot } => { let rootfs = &Dir::open_ambient_dir("/", cap_std::ambient_authority())?; crate::install::completion::run_from_ostree(rootfs, &sysroot, &stateroot).await diff --git a/lib/src/install.rs b/lib/src/install.rs index d591672b2..20cd71082 100644 --- a/lib/src/install.rs +++ b/lib/src/install.rs @@ -6,6 +6,7 @@ // This sub-module is the "basic" installer that handles creating basic block device // and filesystem setup. +#[cfg(feature = "install-to-disk")] pub(crate) mod baseline; pub(crate) mod completion; pub(crate) mod config; @@ -40,9 +41,12 @@ use ostree_ext::oci_spec; use ostree_ext::ostree; use ostree_ext::prelude::Cast; use ostree_ext::sysroot::SysrootLock; -use rustix::fs::{FileTypeExt, MetadataExt as _}; +#[cfg(feature = "install-to-disk")] +use rustix::fs::FileTypeExt; +use rustix::fs::MetadataExt as _; use serde::{Deserialize, Serialize}; +#[cfg(feature = "install-to-disk")] use self::baseline::InstallBlockDeviceOpts; use crate::boundimage::{BoundImage, ResolvedBoundImage}; use crate::containerenv::ContainerExecutionInfo; @@ -57,6 +61,7 @@ use crate::utils::sigpolicy_from_opts; /// The toplevel boot directory const BOOT: &str = "boot"; /// Directory for transient runtime state +#[cfg(feature = "install-to-disk")] const RUN_BOOTC: &str = "/run/bootc"; /// The default path for the host rootfs const ALONGSIDE_ROOT_MOUNT: &str = "/target"; @@ -65,10 +70,8 @@ const LOST_AND_FOUND: &str = "lost+found"; /// The filename of the composefs EROFS superblock; TODO move this into ostree const OSTREE_COMPOSEFS_SUPER: &str = ".ostree.cfs"; /// The mount path for selinux -#[cfg(feature = "install")] const SELINUXFS: &str = "/sys/fs/selinux"; /// The mount path for uefi -#[cfg(feature = "install")] const EFIVARFS: &str = "/sys/firmware/efi/efivars"; pub(crate) const ARCH_USES_EFI: bool = cfg!(any(target_arch = "x86_64", target_arch = "aarch64")); @@ -202,6 +205,7 @@ pub(crate) struct InstallConfigOpts { pub(crate) stateroot: Option, } +#[cfg(feature = "install-to-disk")] #[derive(Debug, Clone, clap::Parser, Serialize, Deserialize, PartialEq, Eq)] pub(crate) struct InstallToDiskOpts { #[clap(flatten)] @@ -375,6 +379,7 @@ impl State { } #[context("Finalizing state")] + #[allow(dead_code)] pub(crate) fn consume(self) -> Result<()> { self.tempdir.close()?; // If we had invoked `setenforce 0`, then let's re-enable it. @@ -880,6 +885,7 @@ pub(crate) fn exec_in_host_mountns(args: &[std::ffi::OsString]) -> Result<()> { } pub(crate) struct RootSetup { + #[cfg(feature = "install-to-disk")] luks_device: Option, device_info: crate::blockdev::PartitionTable, /// Absolute path to the location where we've mounted the physical @@ -907,12 +913,14 @@ impl RootSetup { } // Drop any open file descriptors and return just the mount path and backing luks device, if any + #[cfg(feature = "install-to-disk")] fn into_storage(self) -> (Utf8PathBuf, Option) { (self.physical_root_path, self.luks_device) } } #[derive(Debug)] +#[allow(dead_code)] pub(crate) enum SELinuxFinalState { /// Host and target both have SELinux, but user forced it off for target ForceTargetDisabled, @@ -1449,6 +1457,7 @@ fn installation_complete() { /// Implementation of the `bootc install to-disk` CLI command. #[context("Installing to disk")] +#[cfg(feature = "install-to-disk")] pub(crate) async fn install_to_disk(mut opts: InstallToDiskOpts) -> Result<()> { let mut block_opts = opts.block_opts; let target_blockdev_meta = block_opts @@ -1845,6 +1854,7 @@ pub(crate) async fn install_to_filesystem( let skip_finalize = matches!(fsopts.replace, Some(ReplaceMode::Alongside)) || fsopts.skip_finalize; let mut rootfs = RootSetup { + #[cfg(feature = "install-to-disk")] luks_device: None, device_info, physical_root_path: fsopts.root_path, diff --git a/lib/src/install/baseline.rs b/lib/src/install/baseline.rs index 5db2e221b..66b4557ca 100644 --- a/lib/src/install/baseline.rs +++ b/lib/src/install/baseline.rs @@ -21,12 +21,14 @@ use clap::ValueEnum; use fn_error_context::context; use serde::{Deserialize, Serialize}; +use super::config::Filesystem; use super::MountSpec; use super::RootSetup; use super::State; use super::RUN_BOOTC; use super::RW_KARG; use crate::mount; +#[cfg(feature = "install-to-disk")] use crate::mount::is_mounted_in_pid1_mountns; use crate::task::Task; @@ -36,20 +38,6 @@ pub(crate) const EFIPN_SIZE_MB: u32 = 512; /// The GPT type for "linux" pub(crate) const LINUX_PARTTYPE: &str = "0FC63DAF-8483-4772-8E79-3D69D8477DE4"; -#[derive(clap::ValueEnum, Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub(crate) enum Filesystem { - Xfs, - Ext4, - Btrfs, -} - -impl Display for Filesystem { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.to_possible_value().unwrap().get_name().fmt(f) - } -} - #[derive(clap::ValueEnum, Default, Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub(crate) enum BlockSetup { @@ -104,6 +92,7 @@ impl BlockSetup { } } +#[cfg(feature = "install-to-disk")] fn mkfs<'a>( dev: &str, fs: Filesystem, @@ -143,6 +132,7 @@ fn mkfs<'a>( } #[context("Creating rootfs")] +#[cfg(feature = "install-to-disk")] pub(crate) fn install_create_rootfs( state: &State, opts: InstallBlockDeviceOpts, diff --git a/lib/src/install/config.rs b/lib/src/install/config.rs index b8c870fff..4736ca692 100644 --- a/lib/src/install/config.rs +++ b/lib/src/install/config.rs @@ -3,9 +3,11 @@ //! This module handles the TOML configuration file for `bootc install`. use anyhow::{Context, Result}; +use clap::ValueEnum; use fn_error_context::context; use serde::{Deserialize, Serialize}; +#[cfg(feature = "install-to-disk")] use super::baseline::BlockSetup; /// Properties of the environment, such as the system architecture @@ -14,6 +16,21 @@ pub(crate) struct EnvProperties { pub(crate) sys_arch: String, } +/// A well known filesystem type. +#[derive(clap::ValueEnum, Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub(crate) enum Filesystem { + Xfs, + Ext4, + Btrfs, +} + +impl std::fmt::Display for Filesystem { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.to_possible_value().unwrap().get_name().fmt(f) + } +} + /// The toplevel config entry for installation configs stored /// in bootc/install (e.g. /etc/bootc/install/05-custom.toml) #[derive(Debug, Clone, Serialize, Deserialize, Default)] @@ -27,7 +44,7 @@ pub(crate) struct InstallConfigurationToplevel { #[serde(deny_unknown_fields)] pub(crate) struct RootFS { #[serde(rename = "type")] - pub(crate) fstype: Option, + pub(crate) fstype: Option, } /// This structure should only define "system" or "basic" filesystems; we are @@ -46,8 +63,9 @@ pub(crate) struct BasicFilesystems { #[serde(rename = "install", rename_all = "kebab-case", deny_unknown_fields)] pub(crate) struct InstallConfiguration { /// Root filesystem type - pub(crate) root_fs_type: Option, + pub(crate) root_fs_type: Option, /// Enabled block storage configurations + #[cfg(feature = "install-to-disk")] pub(crate) block: Option>, pub(crate) filesystem: Option, /// Kernel arguments, applied at installation time @@ -112,6 +130,7 @@ impl Mergeable for InstallConfiguration { .unwrap_or(true) { merge_basic(&mut self.root_fs_type, other.root_fs_type, env); + #[cfg(feature = "install-to-disk")] merge_basic(&mut self.block, other.block, env); self.filesystem.merge(other.filesystem, env); if let Some(other_kargs) = other.kargs { @@ -139,6 +158,7 @@ impl InstallConfiguration { root.fstype = Some(*rootfs); } + #[cfg(feature = "install-to-disk")] if self.block.is_none() { self.block = Some(vec![BlockSetup::Direct]); } @@ -154,6 +174,7 @@ impl InstallConfiguration { self.kargs.take(); } + #[cfg(feature = "install-to-disk")] pub(crate) fn get_block_setup(&self, default: Option) -> Result { let valid_block_setups = self.block.as_deref().unwrap_or_default(); let default_block = valid_block_setups.iter().next().ok_or_else(|| { @@ -217,8 +238,6 @@ pub(crate) fn load_config() -> Result> { mod tests { use super::*; - use super::super::baseline::Filesystem; - #[test] /// Verify that we can parse our default config file fn test_parse_config() { diff --git a/lib/src/kargs.rs b/lib/src/kargs.rs index af4410e8b..5df1497c1 100644 --- a/lib/src/kargs.rs +++ b/lib/src/kargs.rs @@ -53,7 +53,6 @@ pub(crate) fn get_kargs_in_root(d: &Dir, sys_arch: &str) -> Result> } /// Load kargs.d files from the target ostree commit root -#[cfg(feature = "install")] pub(crate) fn get_kargs_from_ostree_root( repo: &ostree::Repo, root: &ostree::RepoFile, diff --git a/lib/src/lib.rs b/lib/src/lib.rs index daa4bfc43..a661ba355 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -30,17 +30,11 @@ mod utils; #[cfg(feature = "docgen")] mod docgen; -#[cfg(feature = "install")] mod blockdev; -#[cfg(feature = "install")] mod bootloader; -#[cfg(feature = "install")] mod containerenv; -#[cfg(feature = "install")] mod install; -#[cfg(feature = "install")] mod kernel; -#[cfg(feature = "install")] pub(crate) mod mount; #[cfg(feature = "rhsm")] diff --git a/lib/src/lsm.rs b/lib/src/lsm.rs index c2deaea33..9365c7fcb 100644 --- a/lib/src/lsm.rs +++ b/lib/src/lsm.rs @@ -1,4 +1,3 @@ -#[cfg(feature = "install")] use std::io::Write; use std::os::fd::AsRawFd; use std::os::unix::process::CommandExt; @@ -9,14 +8,10 @@ use anyhow::{Context, Result}; use bootc_utils::CommandRunExt; use camino::{Utf8Path, Utf8PathBuf}; use cap_std::fs::Dir; -#[cfg(feature = "install")] use cap_std::fs::{DirBuilder, OpenOptions}; -#[cfg(feature = "install")] use cap_std::io_lifetimes::AsFilelike; use cap_std_ext::cap_std; -#[cfg(feature = "install")] use cap_std_ext::cap_std::fs::{Metadata, MetadataExt}; -#[cfg(feature = "install")] use cap_std_ext::dirext::CapStdExtDirExt; use fn_error_context::context; use ostree_ext::gio; @@ -24,10 +19,8 @@ use ostree_ext::ostree; use rustix::fd::AsFd; /// The mount path for selinux -#[cfg(feature = "install")] const SELINUXFS: &str = "/sys/fs/selinux"; /// The SELinux xattr -#[cfg(feature = "install")] const SELINUX_XATTR: &[u8] = b"security.selinux\0"; const SELF_CURRENT: &str = "/proc/self/attr/current"; @@ -99,7 +92,6 @@ pub(crate) fn selinux_ensure_install() -> Result { } /// Query whether SELinux is apparently enabled in the target root -#[cfg(feature = "install")] pub(crate) fn have_selinux_policy(root: &Dir) -> Result { // TODO use ostree::SePolicy and query policy name root.try_exists("etc/selinux/config").map_err(Into::into) @@ -108,17 +100,17 @@ pub(crate) fn have_selinux_policy(root: &Dir) -> Result { /// A type which will reset SELinux back to enforcing mode when dropped. /// This is a workaround for the deep difficulties in trying to reliably /// gain the `mac_admin` permission (install_t). -#[cfg(feature = "install")] #[must_use] #[derive(Debug)] +#[allow(dead_code)] pub(crate) struct SetEnforceGuard(Option<()>); -#[cfg(feature = "install")] impl SetEnforceGuard { pub(crate) fn new() -> Self { SetEnforceGuard(Some(())) } + #[allow(dead_code)] pub(crate) fn consume(mut self) -> Result<()> { // SAFETY: The option cannot have been consumed until now self.0.take().unwrap(); @@ -127,7 +119,6 @@ impl SetEnforceGuard { } } -#[cfg(feature = "install")] impl Drop for SetEnforceGuard { fn drop(&mut self) { // A best-effort attempt to re-enable enforcement on drop (installation failure) @@ -140,7 +131,6 @@ impl Drop for SetEnforceGuard { /// Try to enter the install_t domain, but if we can't do that, then /// just setenforce 0. #[context("Ensuring selinux install_t type")] -#[cfg(feature = "install")] pub(crate) fn selinux_ensure_install_or_setenforce() -> Result> { // If the process already has install_t, exit early // Note that this may re-exec the entire process @@ -160,7 +150,6 @@ pub(crate) fn selinux_ensure_install_or_setenforce() -> Result Result<()> { let enforce_path = &Utf8Path::new(SELINUXFS).join("enforce"); if !enforce_path.exists() { @@ -179,7 +168,6 @@ pub(crate) fn selinux_set_permissive(permissive: bool) -> Result<()> { Ok(()) } -#[cfg(feature = "install")] /// Check if the ostree-formatted extended attributes include a security.selinux value. pub(crate) fn xattrs_have_selinux(xattrs: &ostree::glib::Variant) -> bool { let n = xattrs.n_children(); @@ -223,7 +211,6 @@ pub(crate) fn set_security_selinux(fd: std::os::fd::BorrowedFd, label: &[u8]) -> /// The labeling state; "unsupported" is distinct as we need to handle /// cases like the ESP which don't support labeling. -#[cfg(feature = "install")] pub(crate) enum SELinuxLabelState { Unlabeled, Unsupported, @@ -231,7 +218,6 @@ pub(crate) enum SELinuxLabelState { } /// Query the SELinux labeling for a particular path -#[cfg(feature = "install")] pub(crate) fn has_security_selinux(root: &Dir, path: &Utf8Path) -> Result { // TODO: avoid hardcoding a max size here let mut buf = [0u8; 2048]; @@ -244,7 +230,6 @@ pub(crate) fn has_security_selinux(root: &Dir, path: &Utf8Path) -> Result Result<()> { // TODO: avoid hardcoding a max size here let fdpath = format!("/proc/self/fd/{}/", root.as_raw_fd()); @@ -258,7 +243,6 @@ pub(crate) fn set_security_selinux_path(root: &Dir, path: &Utf8Path, label: &[u8 Ok(()) } -#[cfg(feature = "install")] pub(crate) fn ensure_labeled( root: &Dir, path: &Utf8Path, @@ -277,7 +261,6 @@ pub(crate) fn ensure_labeled( /// A wrapper for creating a directory, also optionally setting a SELinux label. /// The provided `skip` parameter is a device/inode that we will ignore (and not traverse). -#[cfg(feature = "install")] pub(crate) fn ensure_dir_labeled_recurse( root: &Dir, path: &mut Utf8PathBuf, @@ -340,7 +323,6 @@ pub(crate) fn ensure_dir_labeled_recurse( } /// A wrapper for creating a directory, also optionally setting a SELinux label. -#[cfg(feature = "install")] pub(crate) fn ensure_dir_labeled( root: &Dir, destname: impl AsRef, @@ -387,7 +369,6 @@ pub(crate) fn ensure_dir_labeled( } /// A wrapper for atomically writing a file, also optionally setting a SELinux label. -#[cfg(feature = "install")] pub(crate) fn atomic_replace_labeled( root: &Dir, destname: impl AsRef, diff --git a/lib/src/mount.rs b/lib/src/mount.rs index a1ad00e63..6c10165ba 100644 --- a/lib/src/mount.rs +++ b/lib/src/mount.rs @@ -21,6 +21,7 @@ use rustix::{ }; use serde::Deserialize; +#[cfg(feature = "install-to-disk")] use crate::task::Task; /// Well known identifier for pid 1 @@ -90,6 +91,7 @@ pub(crate) fn inspect_filesystem_by_uuid(uuid: &str) -> Result { // Check if a specified device contains an already mounted filesystem // in the root mount namespace +#[cfg(feature = "install-to-disk")] pub(crate) fn is_mounted_in_pid1_mountns(path: &str) -> Result { let o = run_findmnt(&["-N"], "1")?; @@ -99,6 +101,7 @@ pub(crate) fn is_mounted_in_pid1_mountns(path: &str) -> Result { } // Recursively check a given filesystem to see if it contains an already mounted source +#[cfg(feature = "install-to-disk")] pub(crate) fn is_source_mounted(path: &str, mounted_fs: &Filesystem) -> bool { if mounted_fs.source.contains(path) { return true; @@ -116,6 +119,7 @@ pub(crate) fn is_source_mounted(path: &str, mounted_fs: &Filesystem) -> bool { } /// Mount a device to the target path. +#[cfg(feature = "install-to-disk")] pub(crate) fn mount(dev: &str, target: &Utf8Path) -> Result<()> { Task::new_and_run( format!("Mounting {target}"), diff --git a/lib/src/podman.rs b/lib/src/podman.rs index 058984ee5..1731f5862 100644 --- a/lib/src/podman.rs +++ b/lib/src/podman.rs @@ -1,19 +1,14 @@ -#[cfg(feature = "install")] use anyhow::Result; -#[cfg(feature = "install")] use camino::Utf8Path; -#[cfg(feature = "install")] use cap_std_ext::cap_std::fs::Dir; use serde::Deserialize; /// Where we look inside our container to find our own image /// for use with `bootc install`. -#[cfg(feature = "install")] pub(crate) const CONTAINER_STORAGE: &str = "/var/lib/containers"; #[derive(Deserialize)] #[serde(rename_all = "PascalCase")] -#[cfg(feature = "install")] pub(crate) struct Inspect { pub(crate) digest: String, } @@ -27,7 +22,6 @@ pub(crate) struct ImageListEntry { } /// Given an image ID, return its manifest digest -#[cfg(feature = "install")] pub(crate) fn imageid_to_digest(imgid: &str) -> Result { use bootc_utils::CommandRunExt; let o: Vec = crate::install::run_in_host_mountns("podman") @@ -41,7 +35,6 @@ pub(crate) fn imageid_to_digest(imgid: &str) -> Result { } /// Return true if there is apparently an active container store at the target path. -#[cfg(feature = "install")] pub(crate) fn storage_exists(root: &Dir, path: impl AsRef) -> Result { fn impl_storage_exists(root: &Dir, path: &Utf8Path) -> Result { let lock = "storage.lock"; @@ -55,7 +48,6 @@ pub(crate) fn storage_exists(root: &Dir, path: impl AsRef) -> Result Result { storage_exists(root, CONTAINER_STORAGE.trim_start_matches('/')) } diff --git a/lib/src/status.rs b/lib/src/status.rs index 8bc598ebf..7f3e8290a 100644 --- a/lib/src/status.rs +++ b/lib/src/status.rs @@ -102,7 +102,6 @@ pub(crate) struct Deployments { pub(crate) other: VecDeque, } -#[cfg(feature = "install")] pub(crate) fn try_deserialize_timestamp(t: &str) -> Option> { match chrono::DateTime::parse_from_rfc3339(t).context("Parsing timestamp") { Ok(t) => Some(t.into()), diff --git a/lib/src/utils.rs b/lib/src/utils.rs index 8e33ceef3..42fbd1654 100644 --- a/lib/src/utils.rs +++ b/lib/src/utils.rs @@ -7,14 +7,10 @@ use std::time::Duration; use anyhow::{Context, Result}; use bootc_utils::CommandRunExt; -#[cfg(feature = "install")] use camino::Utf8Path; use cap_std_ext::cap_std::fs::Dir; -#[cfg(feature = "install")] use cap_std_ext::dirext::CapStdExtDirExt; -#[cfg(feature = "install")] use cap_std_ext::prelude::CapStdExtCommandExt; -#[cfg(feature = "install")] use fn_error_context::context; use indicatif::HumanDuration; use libsystemd::logging::journal_print; @@ -88,7 +84,6 @@ pub fn openat2_with_retry( /// Given an mount option string list like foo,bar=baz,something=else,ro parse it and find /// the first entry like $optname= /// This will not match a bare `optname` without an equals. -#[cfg(feature = "install")] pub(crate) fn find_mount_option<'a>( option_string_list: &'a str, optname: &'_ str, @@ -102,7 +97,6 @@ pub(crate) fn find_mount_option<'a>( /// Given a target directory, if it's a read-only mount, then remount it writable #[context("Opening {target} with writable mount")] -#[cfg(feature = "install")] pub(crate) fn open_dir_remount_rw(root: &Dir, target: &Utf8Path) -> Result { if matches!(root.is_mountpoint(target), Ok(Some(true))) { tracing::debug!("Target {target} is a mountpoint, remounting rw"); @@ -118,7 +112,6 @@ pub(crate) fn open_dir_remount_rw(root: &Dir, target: &Utf8Path) -> Result /// Given a target path, remove its immutability if present #[context("Removing immutable flag from {target}")] -#[cfg(feature = "install")] pub(crate) fn remove_immutability(root: &Dir, target: &Utf8Path) -> Result<()> { use anyhow::ensure; @@ -175,7 +168,6 @@ pub(crate) fn sigpolicy_from_opts( /// Output a warning message that we want to be quite visible. /// The process (thread) execution will be delayed for a short time. -#[cfg(feature = "install")] pub(crate) fn medium_visibility_warning(s: &str) { anstream::eprintln!( "{}{s}{}",