feat(bls): read the extended boot loader partition in the BLS generator

Add an xbootldr option to the BLS generator. When it is enabled, the
partition with the XBOOTLDR type on the same disk as Sprout's partition
is read as well, and its entries and unified kernel images are sorted
with the others. As their files are on that partition, every entry has
an entry-root value, which is the device of the partition or nothing for
Sprout's own, to use in a path like $entry-root\$chainload. It is off
by default, as existing actions would look for the files on the wrong
partition.
This commit is contained in:
alex authored and Alex Zenla committed 2026-10-03 20:23:57 -07:00
1 parent 50f62f5bb6
commit 1658ce0bef
3 files changed
+120 -18

No files matched your search

+28 -4
View File
@@ -26,6 +26,12 @@ pub struct BlsConfiguration {
/// with the same names, so they should not both scan it.
#[serde(default, rename = "uki-path")]
pub uki_path: Option<String>,
/// Whether to also read the Extended Boot Loader Partition, which is the partition with the
/// XBOOTLDR type on the same disk as the partition Sprout was loaded from. Its entries are
/// sorted with the others, and their paths are on that partition, so an action has to use
/// the `$entry-root` value to find them, such as `$entry-root\\$chainload`.
#[serde(default)]
pub xbootldr: bool,
/// Whether generated entries keep the name of the BLS entry file as-is.
/// When enabled, the generator name is not prepended, so the entry names match
/// the BLS entry ids used by tools like `bootctl set-default`. Variants still append
@@ -38,6 +44,12 @@ pub struct BlsConfiguration {
}
impl BlsConfiguration {
/// The device of the stamped BLS path `bls_path`, which is everything up to the last slash,
/// and which is empty for a path on the partition Sprout was loaded from.
pub fn root_of(bls_path: &str) -> &str {
bls_path.rfind('/').map_or("", |index| &bls_path[..=index])
}
/// The directory of unified kernel images for the stamped BLS path `bls_path`,
/// or None if unified kernel images are disabled.
pub fn uki_path_for(&self, bls_path: &str) -> Option<String> {
@@ -45,10 +57,7 @@ impl BlsConfiguration {
Some("") => None,
Some(path) => Some(path.to_string()),
// Keep the device of the BLS path, which is everything up to the last slash.
None => {
let device = bls_path.rfind('/').map_or("", |index| &bls_path[..=index]);
Some(format!("{}{}", device, BLS_UKI_DIRECTORY))
}
None => Some(format!("{}{}", Self::root_of(bls_path), BLS_UKI_DIRECTORY)),
}
}
}
@@ -60,6 +69,7 @@ impl Default for BlsConfiguration {
entry: Default::default(),
path: default_bls_path(),
uki_path: None,
xbootldr: false,
pin_names: default_pin_names(),
}
}
@@ -77,6 +87,20 @@ fn default_bls_path() -> String {
mod tests {
use super::*;
#[test]
fn root_is_the_device_of_the_bls_path() {
assert_eq!(BlsConfiguration::root_of("\\loader"), "");
assert_eq!(
BlsConfiguration::root_of("PciRoot(0x0)/HD(2,GPT,abc)/\\loader"),
"PciRoot(0x0)/HD(2,GPT,abc)/"
);
}
#[test]
fn xbootldr_is_off_by_default() {
assert!(!BlsConfiguration::default().xbootldr);
}
#[test]
fn uki_path_is_next_to_the_default_bls_path() {
let bls = BlsConfiguration::default();