Skip to content

Commit d888cd1

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 682535e commit d888cd1

File tree

3 files changed

+198
-23
lines changed

3 files changed

+198
-23
lines changed

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+
}

lib/src/install.rs

Lines changed: 109 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ use ostree_ext::composefs::{
4747
repository::Repository as ComposefsRepository,
4848
util::Sha256Digest,
4949
};
50+
use ostree_ext::composefs_boot::bootloader::read_file;
5051
use ostree_ext::composefs_boot::{
5152
bootloader::BootEntry as ComposefsBootEntry,
5253
write_boot::write_boot_simple as composefs_write_boot_simple, BootOps,
@@ -71,6 +72,7 @@ use schemars::JsonSchema;
7172

7273
#[cfg(feature = "install-to-disk")]
7374
use self::baseline::InstallBlockDeviceOpts;
75+
use crate::bls_config::{parse_bls_config, BLSConfig};
7476
use crate::boundimage::{BoundImage, ResolvedBoundImage};
7577
use crate::containerenv::ContainerExecutionInfo;
7678
use crate::deploy::{prepare_for_pull, pull_from_prepared, PreparedImportMeta, PreparedPullResult};
@@ -1552,6 +1554,31 @@ async fn initialize_composefs_repository(
15521554
composefs_oci_pull(&Arc::new(repo), &format!("{transport}{image_name}"), None).await
15531555
}
15541556

1557+
fn get_booted_bls() -> Result<BLSConfig> {
1558+
let cmdline = crate::kernel::parse_cmdline()?;
1559+
let booted = cmdline.iter().find_map(|x| x.strip_prefix("composefs="));
1560+
1561+
let Some(booted) = booted else {
1562+
anyhow::bail!("Failed to find composefs parameter in kernel cmdline");
1563+
};
1564+
1565+
for entry in std::fs::read_dir("/sysroot/boot/loader/entries")? {
1566+
let entry = entry?;
1567+
1568+
if !entry.file_name().as_str()?.ends_with(".conf") {
1569+
continue;
1570+
}
1571+
1572+
let bls = parse_bls_config(&std::fs::read_to_string(&entry.path())?)?;
1573+
1574+
if bls.options.contains(booted) {
1575+
return Ok(bls);
1576+
}
1577+
}
1578+
1579+
Err(anyhow::anyhow!("Booted BLS not found"))
1580+
}
1581+
15551582
pub(crate) enum BootSetupType<'a> {
15561583
/// For initial setup, i.e. install to-disk
15571584
Setup(&'a RootSetup),
@@ -1565,38 +1592,97 @@ pub(crate) fn setup_composefs_bls_boot(
15651592
// TODO: Make this generic
15661593
repo: ComposefsRepository<Sha256HashValue>,
15671594
id: &Sha256HashValue,
1568-
entry: BootEntry<Sha256HashValue>,
1595+
entry: ComposefsBootEntry<Sha256HashValue>,
15691596
) -> Result<()> {
1570-
let (root_path, cmdline_refs, entry_id) = match setup_type {
1571-
BootSetupType::Setup(root_setup) => (
1572-
root_setup.physical_root_path.clone(),
1597+
let id_hex = id.to_hex();
1598+
1599+
let (root_path, cmdline_refs) = match setup_type {
1600+
BootSetupType::Setup(root_setup) => {
15731601
// root_setup.kargs has [root=UUID=<UUID>, "rw"]
1574-
&root_setup.kargs,
1575-
format!("{}", id.to_hex()),
1576-
),
1602+
let mut cmdline_options = String::from(root_setup.kargs.join(" "));
1603+
cmdline_options.push_str(&format!(" composefs={id_hex}"));
1604+
1605+
(root_setup.physical_root_path.clone(), cmdline_options)
1606+
}
15771607

15781608
BootSetupType::Upgrade => (
15791609
Utf8PathBuf::from("/sysroot"),
1580-
&vec![format!("root=UUID={DPS_UUID}"), RW_KARG.to_string()],
1581-
format!("{}.staged", id.to_hex()),
1610+
vec![
1611+
format!("root=UUID={DPS_UUID}"),
1612+
RW_KARG.to_string(),
1613+
format!("composefs={id_hex}"),
1614+
]
1615+
.join(" "),
15821616
),
15831617
};
15841618

1585-
let str_slice = cmdline_refs
1586-
.iter()
1587-
.map(|x| x.as_str())
1588-
.collect::<Vec<&str>>();
1619+
let boot_dir = root_path.join("boot");
15891620

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

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

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)