From 3a4f7403c0e36a0fc32c7f12e354894c35c22610 Mon Sep 17 00:00:00 2001 From: Joseph Marrero Corchado Date: Tue, 22 Oct 2024 11:52:07 -0400 Subject: [PATCH] core: stop wrapping kernel-install when layout=ostree is set We also correctly parse the arguments passed on kernel-install. --- docs/treefile.md | 3 ++- rust/src/core.rs | 43 ++++++++++++++++++++++++++++---------- rust/src/kernel_install.rs | 33 +++++++++++++++++++++++++++-- 3 files changed, 65 insertions(+), 14 deletions(-) diff --git a/docs/treefile.md b/docs/treefile.md index 46c61f32f5..1055c80edc 100644 --- a/docs/treefile.md +++ b/docs/treefile.md @@ -57,7 +57,8 @@ It supports the following parameters: upgrading from very old versions of libostree. * "modules": Kernel data goes just in `/usr/lib/modules`. Use this for new systems, and systems that don't need to be upgraded - from very old libostree versions. + from very old libostree versions. This is the default for editions 2024 + and above. * "kernel-install": The system is integrated with `/sbin/kernel-install` from systemd. You likely want to additionally pair this with configuring `layout=ostree` in `/usr/lib/kernel/install.conf`, and adding a wrapper script to diff --git a/rust/src/core.rs b/rust/src/core.rs index 69ded654c5..0bbb16f4b4 100644 --- a/rust/src/core.rs +++ b/rust/src/core.rs @@ -5,6 +5,7 @@ use crate::cxxrsutil::*; use crate::ffiutil; +use crate::kernel_install::is_ostree_layout; use anyhow::Context; use anyhow::{anyhow, Result}; use camino::Utf8Path; @@ -48,6 +49,8 @@ const USERMOD_WRAPPER: &[u8] = include_bytes!("../../src/libpriv/usermod-wrapper const KERNEL_INSTALL_PATH: &str = "usr/bin/kernel-install"; const KERNEL_INSTALL_WRAPPER: &[u8] = include_bytes!("../../src/libpriv/kernel-install-wrapper.sh"); +// ## Check for layout and wrap if =ostree + const RPMOSTREE_CORE_STAGED_RPMS_DIR: &str = "rpm-ostree/staged-rpms"; pub(crate) const OSTREE_BOOTED: &str = "/run/ostree-booted"; @@ -166,9 +169,11 @@ impl FilesystemScriptPrep { (SYSTEMCTL_PATH, SYSTEMCTL_WRAPPER), (USERADD_PATH, USERADD_WRAPPER), (USERMOD_PATH, USERMOD_WRAPPER), - (KERNEL_INSTALL_PATH, KERNEL_INSTALL_WRAPPER), ]; + const REPLACE_KERNEL_PATHS: &'static [(&'static str, &'static [u8])] = + &[(KERNEL_INSTALL_PATH, KERNEL_INSTALL_WRAPPER)]; + fn saved_name(name: &str) -> String { format!("{}.rpmostreesave", name) } @@ -188,6 +193,16 @@ impl FilesystemScriptPrep { rootfs.atomic_write_with_perms(path, contents, mode)?; } } + if std::path::Path::new(OSTREE_BOOTED).exists() && !is_ostree_layout()? { + for &(path, contents) in Self::REPLACE_KERNEL_PATHS { + let mode = Permissions::from_mode(0o755); + let saved = &Self::saved_name(path); + if rootfs.try_exists(path)? { + rootfs.rename(path, &rootfs, saved)?; + rootfs.atomic_write_with_perms(path, contents, mode)?; + } + } + } Ok(Box::new(Self { rootfs, enabled: true, @@ -472,16 +487,22 @@ mod test { } // Replaced kernel-install. { - let original_kernel_install = "original kernel_install"; - d.atomic_write_with_perms(super::KERNEL_INSTALL_PATH, original_kernel_install, mode)?; - let contents = d.read_to_string(super::KERNEL_INSTALL_PATH)?; - assert_eq!(contents, original_kernel_install); - let mut g = super::prepare_filesystem_script_prep(d.as_raw_fd())?; - let contents = d.read_to_string(super::KERNEL_INSTALL_PATH)?; - assert_eq!(contents.as_bytes(), super::KERNEL_INSTALL_WRAPPER); - g.undo()?; - let contents = d.read_to_string(super::KERNEL_INSTALL_PATH)?; - assert_eq!(contents, original_kernel_install); + if std::path::Path::new(OSTREE_BOOTED).exists() && !is_ostree_layout()? { + let original_kernel_install = "original kernel_install"; + d.atomic_write_with_perms( + super::KERNEL_INSTALL_PATH, + original_kernel_install, + mode, + )?; + let contents = d.read_to_string(super::KERNEL_INSTALL_PATH)?; + assert_eq!(contents, original_kernel_install); + let mut g = super::prepare_filesystem_script_prep(d.as_raw_fd())?; + let contents = d.read_to_string(super::KERNEL_INSTALL_PATH)?; + assert_eq!(contents.as_bytes(), super::KERNEL_INSTALL_WRAPPER); + g.undo()?; + let contents = d.read_to_string(super::KERNEL_INSTALL_PATH)?; + assert_eq!(contents, original_kernel_install); + } } Ok(()) } diff --git a/rust/src/kernel_install.rs b/rust/src/kernel_install.rs index f97b24a17a..cedd21b7a5 100644 --- a/rust/src/kernel_install.rs +++ b/rust/src/kernel_install.rs @@ -11,6 +11,9 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +use std::fs::File; +use std::io::{BufRead, BufReader}; +use std::path::Path; use std::process::Command; use anyhow::{Context, Result}; @@ -29,6 +32,28 @@ const SKIP: u8 = 77; const MODULES: &str = "usr/lib/modules"; /// The default name for the initramfs. const INITRAMFS: &str = "initramfs.img"; +/// The path to the instal.conf that sets layout. +const KERNEL_INSTALL_CONF: &str = "/usr/lib/kernel/install.conf"; + +#[context("Verifying kernel-install layout file")] +pub fn is_ostree_layout() -> Result { + let install_conf = Path::new(KERNEL_INSTALL_CONF); + if !install_conf.is_file() { + println!("can not read /usr/lib/kernel/install.conf"); + return Ok(false); + } + let buff = BufReader::new( + File::open(install_conf).context("Failed to open /usr/lib/kernel/install.conf")?, + ); + // Check for "layout=ostree" in the file + for line in buff.lines() { + let line = line.context("Failed to read line")?; + if line.trim() == "layout=ostree" { + return Ok(true); + } + } + Ok(false) +} #[context("Adding kernel")] fn add(root: &Dir, argv: &[&str]) -> Result<()> { @@ -36,6 +61,7 @@ fn add(root: &Dir, argv: &[&str]) -> Result<()> { let Some(kver) = argv_it.next() else { anyhow::bail!("No kernel version provided"); }; + tracing::debug!("Installing kernel kver={kver}"); println!("Generating initramfs"); crate::initramfs::run_dracut(root, &kver)?; println!("Running depmod"); @@ -51,6 +77,7 @@ fn add(root: &Dir, argv: &[&str]) -> Result<()> { #[context("Removing kernel")] fn remove(root: &Dir, kver: &str) -> Result<()> { + tracing::debug!("Removing kernel kver={kver}"); let kdir = format!("{MODULES}/{kver}"); let Some(kernel_dir) = root.open_dir_optional(&kdir)? else { return Ok(()); @@ -66,6 +93,7 @@ pub fn main(argv: &[&str]) -> Result { let Some(layout) = std::env::var_os(LAYOUT_VAR) else { return Ok(0); }; + tracing::debug!("The LAYOUT_OSTREE is: {:?}", layout.to_str()); if !matches!(layout.to_str(), Some(LAYOUT_OSTREE)) { return Ok(0); } @@ -76,14 +104,15 @@ pub fn main(argv: &[&str]) -> Result { return Ok(0); } let root = &Dir::open_ambient_dir("/", cap_std::ambient_authority())?; + tracing::debug!("argv={argv:?}"); match argv { - ["add", rest @ ..] => { + [_, _, "add", rest @ ..] => { add(root, rest)?; // In the case of adding a new kernel, we intercept everything else // today. In the future we can try to ensure we reuse what bits are there. Ok(SKIP) } - ["remove", kver] => { + [_, _, "remove", kver, ..] => { remove(root, kver)?; Ok(0) }