Skip to content

Commit

Permalink
blsforme: Switch to sync() rather than individual install calls
Browse files Browse the repository at this point in the history
This allows us to group the contextual logic and gather necessary details
for future cleanups, as well as ensuring each cmdline representation is
specific to the sysroot it came from.

Signed-off-by: Ikey Doherty <[email protected]>
  • Loading branch information
ikeycode committed Dec 22, 2024
1 parent 94aa044 commit 59aa03d
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 43 deletions.
11 changes: 11 additions & 0 deletions blsforme/src/bootloader/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,17 @@ impl<'a, 'b> Bootloader<'a, 'b> {
}
}

pub fn sync_entries(
&self,
cmdline: impl Iterator<Item = &'a str>,
entries: &[Entry],
excluded_snippets: impl Iterator<Item = &'a str>,
) -> Result<(), Error> {
match &self {
Bootloader::Systemd(s) => s.sync_entries(cmdline, entries, excluded_snippets),
}
}

/// Install a single kernel, create records for it.
pub fn install(&self, cmdline: &str, entry: &Entry) -> Result<(), Error> {
match &self {
Expand Down
39 changes: 32 additions & 7 deletions blsforme/src/bootloader/systemd_boot/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,36 @@ impl<'a, 'b> Loader<'a, 'b> {
Ok(())
}

pub(super) fn sync_entries(
&self,
cmdline: impl Iterator<Item = &'a str>,
entries: &[Entry],
excluded_snippets: impl Iterator<Item = &'a str>,
) -> Result<(), super::Error> {
let base_cmdline = cmdline.map(str::to_string).collect::<Vec<_>>();
let exclusions = excluded_snippets.map(str::to_string).collect::<Vec<_>>();
for entry in entries {
let entry_cmdline = entry
.cmdline
.iter()
.filter(|c| !exclusions.contains(&c.name))
.map(|c| c.snippet.clone())
.collect::<Vec<_>>();
let mut full_cmdline = base_cmdline
.iter()
.chain(entry_cmdline.iter())
.cloned()
.collect::<Vec<_>>();

// kernel specific cmdline
if let Some(k_cmdline) = entry.kernel.cmdline.as_ref() {
full_cmdline.push(k_cmdline.clone());
}
self.install(&full_cmdline.join(" "), entry)?;
}
Ok(())
}

/// Install a kernel to the ESP or XBOOTLDR, write a config for it
pub(super) fn install(&self, cmdline: &str, entry: &Entry) -> Result<(), super::Error> {
let loader_id = self
Expand Down Expand Up @@ -185,17 +215,12 @@ impl<'a, 'b> Loader<'a, 'b> {
format!("{} ({})", self.schema.os_release().name, entry.kernel.version)
};
let vmlinuz = entry.installed_kernel_name(self.schema).expect("linux go boom");
let options = if let Some(k_cmdline) = entry.kernel.cmdline.as_ref() {
format!("{cmdline} {k_cmdline}")
} else {
cmdline.to_string()
};
format!(
r###"title {title}
linux /{asset_dir}/{}{}
options {}
options {cmdline}
"###,
vmlinuz, initrd, options
vmlinuz, initrd
)
}

Expand Down
42 changes: 32 additions & 10 deletions blsforme/src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,17 @@

use std::path::PathBuf;

use crate::{AuxiliaryFile, Kernel, Schema};
use crate::{file_utils::cmdline_snippet, AuxiliaryFile, Configuration, Kernel, Schema};

/// A cmdline entry is found in the `$sysroot/usr/lib/kernel/cmdline.d` directory
#[derive(Debug)]
pub struct CmdlineEntry {
/// Name of the entry, i.e. `00-quiet.cmdline`
pub name: String,

/// Text contents of this cmdline entry
pub snippet: String,
}

/// An entry corresponds to a single kernel, and may have a supplemental
/// cmdline
Expand All @@ -14,30 +24,42 @@ pub struct Entry<'a> {

pub(crate) sysroot: Option<PathBuf>,

// Additional cmdline
#[allow(dead_code)]
cmdline: Option<String>,
pub(crate) cmdline: Vec<CmdlineEntry>,
}

impl<'a> Entry<'a> {
/// New entry for the given kernel
pub fn new(kernel: &'a Kernel) -> Self {
Self {
kernel,
cmdline: None,
cmdline: vec![],
sysroot: None,
}
}

/// With the following cmdline
pub fn with_cmdline(self, cmdline: impl AsRef<str>) -> Self {
Self {
cmdline: Some(cmdline.as_ref().to_string()),
..self
/// Load cmdline snippets from the system root for this entry's sysroot
pub fn load_cmdline_snippets(&mut self, config: &Configuration) -> Result<(), super::Error> {
let sysroot = self.sysroot.clone().unwrap_or(config.root.path().into());
let cmdline_d = sysroot.join("usr").join("lib").join("kernel").join("cmdline.d");

if !cmdline_d.exists() {
return Ok(());
}

let entries = std::fs::read_dir(&cmdline_d)?;

for entry in entries {
let entry = entry?;
let name = entry.file_name().to_string_lossy().to_string();
let snippet = cmdline_snippet(entry.path())?;
self.cmdline.push(CmdlineEntry { name, snippet });
}

Ok(())
}

/// With the given system root
/// This will cause any local snippets to be discovered
pub fn with_sysroot(self, sysroot: impl Into<PathBuf>) -> Self {
Self {
sysroot: Some(sysroot.into()),
Expand Down
34 changes: 8 additions & 26 deletions blsforme/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,32 +211,14 @@ impl<'a> Manager<'a> {
}
// Firstly, get the bootloader updated.
let bootloader = self.bootloader(schema)?;

// Install every kernel that was passed to us
for entry in self.entries.iter() {
let root_dir = entry
.sysroot
.clone()
.unwrap_or_else(|| self.config.root.path().to_path_buf());
let mut cmdline = self.cmdline.clone();

// Merge the system-wide cmdline with the rootfs cmdline
if let Ok(it) = fs::read_dir(root_dir.join("usr").join("lib").join("kernel").join("cmdline.d")) {
log::trace!("reading system cmdline.d entries");
let entries = it
.filter_map(|p| p.ok())
.filter(|d| {
if let Some(name) = d.file_name().to_str() {
!self.system_excluded_snippets.contains(&name.to_string())
} else {
true
}
})
.filter_map(|p| cmdline_snippet(p.path()).ok());
cmdline.extend(entries);
}
bootloader.install(&cmdline.join(" "), entry)?;
}
bootloader.sync()?;

// Sync the entries
bootloader.sync_entries(
self.cmdline.iter().map(String::as_str),
&self.entries,
self.system_excluded_snippets.iter().map(String::as_str),
)?;

Ok(())
}
Expand Down

0 comments on commit 59aa03d

Please sign in to comment.