Skip to content

Commit d806a97

Browse files
install/composefs: Remove dependency on composefs write_boot_simple
Now we get the vmlinuz and initrd from the boot entry and write them to /boot ourselves not relying on composefs lib's provided helper function. Allows more granularity while modifying BLS entries Signed-off-by: Johan-Liebert1 <[email protected]>
1 parent 0e6ce9d commit d806a97

File tree

3 files changed

+198
-23
lines changed

3 files changed

+198
-23
lines changed

crates/lib/src/bls_config.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
use serde::{Deserialize, Deserializer};
2+
use serde::de::Error;
3+
use std::collections::HashMap;
4+
use anyhow::Result;
5+
6+
#[derive(Debug, Deserialize, Eq)]
7+
pub(crate) struct BLSConfig {
8+
pub(crate) title: Option<String>,
9+
#[serde(deserialize_with = "deserialize_version")]
10+
pub(crate) version: u32,
11+
pub(crate) linux: String,
12+
pub(crate) initrd: String,
13+
pub(crate) options: String,
14+
15+
#[serde(flatten)]
16+
pub(crate) extra: HashMap<String, String>,
17+
}
18+
19+
impl PartialEq for BLSConfig {
20+
fn eq(&self, other: &Self) -> bool {
21+
self.version == other.version
22+
}
23+
}
24+
25+
impl PartialOrd for BLSConfig {
26+
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
27+
self.version.partial_cmp(&other.version)
28+
}
29+
}
30+
31+
impl Ord for BLSConfig {
32+
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
33+
self.version.cmp(&other.version)
34+
}
35+
}
36+
37+
impl BLSConfig {
38+
pub(crate) fn to_string(&self) -> String {
39+
let mut out = String::new();
40+
41+
if let Some(title) = &self.title {
42+
out += &format!("title {}\n", title);
43+
}
44+
45+
out += &format!("version {}\n", self.version);
46+
out += &format!("linux {}\n", self.linux);
47+
out += &format!("initrd {}\n", self.initrd);
48+
out += &format!("options {}\n", self.options);
49+
50+
for (key, value) in &self.extra {
51+
out += &format!("{} {}\n", key, value);
52+
}
53+
54+
out
55+
}
56+
}
57+
58+
fn deserialize_version<'de, D>(deserializer: D) -> Result<u32, D::Error>
59+
where
60+
D: Deserializer<'de>,
61+
{
62+
let s: Option<String> = Option::deserialize(deserializer)?;
63+
64+
match s {
65+
Some(s) => Ok(s.parse::<u32>().map_err(D::Error::custom)?),
66+
None => Err(D::Error::custom("Version not found")),
67+
}
68+
}
69+
70+
pub(crate) fn parse_bls_config(input: &str) -> Result<BLSConfig> {
71+
let mut map = HashMap::new();
72+
73+
for line in input.lines() {
74+
let line = line.trim();
75+
if line.is_empty() || line.starts_with('#') {
76+
continue;
77+
}
78+
79+
if let Some((key, value)) = line.split_once(' ') {
80+
map.insert(key.to_string(), value.trim().to_string());
81+
}
82+
}
83+
84+
let value = serde_json::to_value(map)?;
85+
let parsed: BLSConfig = serde_json::from_value(value)?;
86+
87+
Ok(parsed)
88+
}

crates/lib/src/install.rs

Lines changed: 109 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ use ostree_ext::composefs::{
4848
repository::Repository as ComposefsRepository,
4949
util::Sha256Digest,
5050
};
51+
use ostree_ext::composefs_boot::bootloader::read_file;
5152
use ostree_ext::composefs_boot::{
5253
bootloader::BootEntry as ComposefsBootEntry,
5354
write_boot::write_boot_simple as composefs_write_boot_simple, BootOps,
@@ -72,6 +73,7 @@ use schemars::JsonSchema;
7273

7374
#[cfg(feature = "install-to-disk")]
7475
use self::baseline::InstallBlockDeviceOpts;
76+
use crate::bls_config::{parse_bls_config, BLSConfig};
7577
use crate::boundimage::{BoundImage, ResolvedBoundImage};
7678
use crate::containerenv::ContainerExecutionInfo;
7779
use crate::deploy::{prepare_for_pull, pull_from_prepared, PreparedImportMeta, PreparedPullResult};
@@ -1543,6 +1545,31 @@ async fn initialize_composefs_repository(
15431545
composefs_oci_pull(&Arc::new(repo), &format!("{transport}{image_name}"), None).await
15441546
}
15451547

1548+
fn get_booted_bls() -> Result<BLSConfig> {
1549+
let cmdline = crate::kernel::parse_cmdline()?;
1550+
let booted = cmdline.iter().find_map(|x| x.strip_prefix("composefs="));
1551+
1552+
let Some(booted) = booted else {
1553+
anyhow::bail!("Failed to find composefs parameter in kernel cmdline");
1554+
};
1555+
1556+
for entry in std::fs::read_dir("/sysroot/boot/loader/entries")? {
1557+
let entry = entry?;
1558+
1559+
if !entry.file_name().as_str()?.ends_with(".conf") {
1560+
continue;
1561+
}
1562+
1563+
let bls = parse_bls_config(&std::fs::read_to_string(&entry.path())?)?;
1564+
1565+
if bls.options.contains(booted) {
1566+
return Ok(bls);
1567+
}
1568+
}
1569+
1570+
Err(anyhow::anyhow!("Booted BLS not found"))
1571+
}
1572+
15461573
pub(crate) enum BootSetupType<'a> {
15471574
/// For initial setup, i.e. install to-disk
15481575
Setup(&'a RootSetup),
@@ -1556,38 +1583,97 @@ pub(crate) fn setup_composefs_bls_boot(
15561583
// TODO: Make this generic
15571584
repo: ComposefsRepository<Sha256HashValue>,
15581585
id: &Sha256HashValue,
1559-
entry: BootEntry<Sha256HashValue>,
1586+
entry: ComposefsBootEntry<Sha256HashValue>,
15601587
) -> Result<()> {
1561-
let (root_path, cmdline_refs, entry_id) = match setup_type {
1562-
BootSetupType::Setup(root_setup) => (
1563-
root_setup.physical_root_path.clone(),
1588+
let id_hex = id.to_hex();
1589+
1590+
let (root_path, cmdline_refs) = match setup_type {
1591+
BootSetupType::Setup(root_setup) => {
15641592
// root_setup.kargs has [root=UUID=<UUID>, "rw"]
1565-
&root_setup.kargs,
1566-
format!("{}", id.to_hex()),
1567-
),
1593+
let mut cmdline_options = String::from(root_setup.kargs.join(" "));
1594+
cmdline_options.push_str(&format!(" composefs={id_hex}"));
1595+
1596+
(root_setup.physical_root_path.clone(), cmdline_options)
1597+
}
15681598

15691599
BootSetupType::Upgrade => (
15701600
Utf8PathBuf::from("/sysroot"),
1571-
&vec![format!("root=UUID={DPS_UUID}"), RW_KARG.to_string()],
1572-
format!("{}.staged", id.to_hex()),
1601+
vec![
1602+
format!("root=UUID={DPS_UUID}"),
1603+
RW_KARG.to_string(),
1604+
format!("composefs={id_hex}"),
1605+
]
1606+
.join(" "),
15731607
),
15741608
};
15751609

1576-
let str_slice = cmdline_refs
1577-
.iter()
1578-
.map(|x| x.as_str())
1579-
.collect::<Vec<&str>>();
1610+
let boot_dir = root_path.join("boot");
15801611

1581-
composefs_write_boot_simple(
1582-
&repo,
1583-
entry,
1584-
&id,
1585-
false,
1586-
root_path.as_std_path(),
1587-
Some("boot"),
1588-
Some(&entry_id),
1589-
&str_slice,
1590-
)
1612+
let bls_config = match &entry {
1613+
ComposefsBootEntry::Type1(..) => todo!(),
1614+
ComposefsBootEntry::Type2(..) => todo!(),
1615+
ComposefsBootEntry::UsrLibModulesUki(..) => todo!(),
1616+
1617+
ComposefsBootEntry::UsrLibModulesVmLinuz(usr_lib_modules_vmlinuz) => {
1618+
// Write the initrd and vmlinuz at /boot/<id>/
1619+
let path = boot_dir.join(&id_hex);
1620+
create_dir_all(&path)?;
1621+
1622+
let vmlinuz_path = path.join("vmlinuz");
1623+
let initrd_path = path.join("initrd");
1624+
1625+
std::fs::write(
1626+
&vmlinuz_path,
1627+
read_file(&usr_lib_modules_vmlinuz.vmlinuz, &repo).context("Reading vmlinuz")?,
1628+
)
1629+
.context("Writing vmlinuz to path")?;
1630+
1631+
if let Some(initramfs) = &usr_lib_modules_vmlinuz.initramfs {
1632+
std::fs::write(
1633+
&initrd_path,
1634+
read_file(initramfs, &repo).context("Reading initramfs")?,
1635+
)
1636+
.context("Writing initrd to path")?;
1637+
} else {
1638+
anyhow::bail!("initramfs not found");
1639+
};
1640+
1641+
BLSConfig {
1642+
title: Some(id_hex.clone()),
1643+
version: 1,
1644+
linux: format!("/boot/{id_hex}/vmlinuz"),
1645+
initrd: format!("/boot/{id_hex}/initrd"),
1646+
options: cmdline_refs,
1647+
extra: HashMap::new(),
1648+
}
1649+
}
1650+
};
1651+
1652+
let (entries_path, booted_bls) = if matches!(setup_type, BootSetupType::Upgrade) {
1653+
let mut booted_bls = get_booted_bls()?;
1654+
booted_bls.version = 0; // entries are sorted by their filename in reverse order
1655+
1656+
// This will be atomically renamed to 'loader/entries' on shutdown/reboot
1657+
(boot_dir.join("loader/entries.staged"), Some(booted_bls))
1658+
} else {
1659+
(boot_dir.join("loader/entries"), None)
1660+
};
1661+
1662+
create_dir_all(&entries_path).with_context(|| format!("Creating {:?}", entries_path))?;
1663+
1664+
std::fs::write(
1665+
entries_path.join(format!("bootc-composefs-{}.conf", bls_config.version)),
1666+
bls_config.to_string().as_bytes(),
1667+
)?;
1668+
1669+
if let Some(booted_bls) = booted_bls {
1670+
std::fs::write(
1671+
entries_path.join(format!("bootc-composefs-{}.conf", booted_bls.version)),
1672+
booted_bls.to_string().as_bytes(),
1673+
)?;
1674+
}
1675+
1676+
Ok(())
15911677
}
15921678

15931679
pub fn get_esp_partition(device: &str) -> Result<(String, Option<String>)> {

crates/lib/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ mod status;
2727
mod store;
2828
mod task;
2929
mod utils;
30+
mod bls_config;
3031

3132
#[cfg(feature = "docgen")]
3233
mod docgen;

0 commit comments

Comments
 (0)