Skip to content

Commit 2e4a47b

Browse files
composefs-backend/boot: Handle staged systemd-boot deployments
Add logic for upgrading/switching to a deployment with systemd-boot as the bootloader. Also update finalize-staged service to handle systemd-boot bootloader entries for UKIs Signed-off-by: Pragyan Poudyal <[email protected]>
1 parent 95fe0dc commit 2e4a47b

File tree

4 files changed

+42
-28
lines changed

4 files changed

+42
-28
lines changed

crates/lib/src/bootc_composefs/boot.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,9 @@ pub(crate) fn setup_composefs_bls_boot(
503503
let loader_path = entry_paths.config_path.join("loader");
504504

505505
let (config_path, booted_bls) = if is_upgrade {
506-
let mut booted_bls = get_booted_bls()?;
506+
let boot_dir = Dir::open_ambient_dir(&entry_paths.config_path, ambient_authority())?;
507+
508+
let mut booted_bls = get_booted_bls(&boot_dir)?;
507509
booted_bls.sort_key = Some("0".into()); // entries are sorted by their filename in reverse order
508510

509511
// This will be atomically renamed to 'loader/entries' on shutdown/reboot
@@ -751,23 +753,27 @@ fn write_systemd_uki_config(
751753
efi: format!("/{SYSTEMD_UKI_DIR}/{}{}", id.to_hex(), EFI_EXT),
752754
})
753755
.with_sort_key(default_sort_key.into())
756+
// TODO (Johan-Liebert1): Get version from UKI like we get boot label
754757
.with_version(default_sort_key.into());
755758

756-
let entries_dir = match setup_type {
759+
let (entries_dir, booted_bls) = match setup_type {
757760
BootSetupType::Setup(..) => {
758761
esp_dir
759762
.create_dir_all(TYPE1_ENT_PATH)
760763
.with_context(|| format!("Creating {TYPE1_ENT_PATH}"))?;
761764

762-
esp_dir.open_dir(TYPE1_ENT_PATH)?
765+
(esp_dir.open_dir(TYPE1_ENT_PATH)?, None)
763766
}
764767

765768
BootSetupType::Upgrade(_) => {
766769
esp_dir
767770
.create_dir_all(TYPE1_ENT_PATH_STAGED)
768771
.with_context(|| format!("Creating {TYPE1_ENT_PATH_STAGED}"))?;
769772

770-
esp_dir.open_dir(TYPE1_ENT_PATH_STAGED)?
773+
let mut booted_bls = get_booted_bls(&esp_dir)?;
774+
booted_bls.sort_key = Some("1".into());
775+
776+
(esp_dir.open_dir(TYPE1_ENT_PATH_STAGED)?, Some(booted_bls))
771777
}
772778
};
773779

@@ -778,6 +784,14 @@ fn write_systemd_uki_config(
778784
)
779785
.context("Writing conf file")?;
780786

787+
if let Some(booted_bls) = booted_bls {
788+
entries_dir.atomic_write(
789+
// SAFETY: We set sort_key above
790+
type1_entry_conf_file_name(booted_bls.sort_key.as_ref().unwrap()),
791+
booted_bls.to_string().as_bytes(),
792+
)?;
793+
}
794+
781795
// Write the timeout for bootloader menu if not exists
782796
if !esp_dir.exists(SYSTEMD_LOADER_CONF_PATH) {
783797
esp_dir

crates/lib/src/bootc_composefs/finalize.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,12 @@ pub(crate) async fn composefs_native_finalize() -> Result<()> {
8080
let entries_dir = esp_mount.fd.open_dir("loader")?;
8181
rename_exchange_bls_entries(&entries_dir)?;
8282
}
83-
BootType::Uki => rename_staged_uki_entries(&esp_mount.fd)?,
83+
BootType::Uki => {
84+
rename_staged_uki_entries(&esp_mount.fd)?;
85+
86+
let entries_dir = esp_mount.fd.open_dir("loader")?;
87+
rename_exchange_bls_entries(&entries_dir)?;
88+
}
8489
},
8590
};
8691

crates/lib/src/bootc_composefs/rollback.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,9 @@ pub(crate) fn rename_exchange_bls_entries(entries_dir: &Dir) -> Result<()> {
5353
.context("renameat")?;
5454

5555
tracing::debug!("Removing {STAGED_BOOT_LOADER_ENTRIES}");
56-
rustix::fs::unlinkat(&entries_dir, STAGED_BOOT_LOADER_ENTRIES, AtFlags::REMOVEDIR)
57-
.context("unlinkat")?;
56+
entries_dir
57+
.remove_dir_all(STAGED_BOOT_LOADER_ENTRIES)
58+
.context("Removing staged dir")?;
5859

5960
tracing::debug!("Syncing to disk");
6061
let entries_dir = entries_dir

crates/lib/src/bootc_composefs/state.rs

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ use bootc_kernel_cmdline::utf8::Cmdline;
66
use bootc_mount::tempmount::TempMount;
77
use bootc_utils::CommandRunExt;
88
use camino::Utf8PathBuf;
9-
use cap_std_ext::{cap_std, dirext::CapStdExtDirExt};
9+
use cap_std_ext::cap_std::ambient_authority;
10+
use cap_std_ext::{cap_std::fs::Dir, dirext::CapStdExtDirExt};
1011
use composefs::fsverity::{FsVerityHashValue, Sha256HashValue};
1112
use fn_error_context::context;
1213

@@ -17,41 +18,36 @@ use rustix::{
1718
};
1819

1920
use crate::bootc_composefs::boot::BootType;
21+
use crate::bootc_composefs::status::get_sorted_type1_boot_entries;
2022
use crate::parsers::bls_config::BLSConfigType;
2123
use crate::{
2224
composefs_consts::{
2325
COMPOSEFS_CMDLINE, COMPOSEFS_STAGED_DEPLOYMENT_FNAME, COMPOSEFS_TRANSIENT_STATE_DIR,
2426
ORIGIN_KEY_BOOT, ORIGIN_KEY_BOOT_DIGEST, ORIGIN_KEY_BOOT_TYPE, SHARED_VAR_PATH,
2527
STATE_DIR_RELATIVE,
2628
},
27-
parsers::bls_config::{parse_bls_config, BLSConfig},
29+
parsers::bls_config::BLSConfig,
2830
spec::ImageReference,
2931
utils::path_relative_to,
3032
};
3133

32-
pub(crate) fn get_booted_bls() -> Result<BLSConfig> {
34+
pub(crate) fn get_booted_bls(boot_dir: &Dir) -> Result<BLSConfig> {
3335
let cmdline = Cmdline::from_proc()?;
3436
let booted = cmdline
3537
.find(COMPOSEFS_CMDLINE)
3638
.ok_or_else(|| anyhow::anyhow!("Failed to find composefs parameter in kernel cmdline"))?;
3739

38-
for entry in std::fs::read_dir("/sysroot/boot/loader/entries")? {
39-
let entry = entry?;
40+
let sorted_entries = get_sorted_type1_boot_entries(boot_dir, true)?;
4041

41-
if !entry.file_name().as_str()?.ends_with(".conf") {
42-
continue;
43-
}
44-
45-
let bls = parse_bls_config(&std::fs::read_to_string(&entry.path())?)?;
46-
47-
match &bls.cfg_type {
42+
for entry in sorted_entries {
43+
match &entry.cfg_type {
4844
BLSConfigType::EFI { efi } => {
4945
let composfs_param_value = booted.value().ok_or(anyhow::anyhow!(
5046
"Failed to get composefs kernel cmdline value"
5147
))?;
5248

5349
if efi.contains(composfs_param_value) {
54-
return Ok(bls);
50+
return Ok(entry);
5551
}
5652
}
5753

@@ -63,7 +59,7 @@ pub(crate) fn get_booted_bls() -> Result<BLSConfig> {
6359
let opts = Cmdline::from(opts);
6460

6561
if opts.iter().any(|v| v == booted) {
66-
return Ok(bls);
62+
return Ok(entry);
6763
}
6864
}
6965

@@ -151,8 +147,8 @@ pub(crate) fn write_composefs_state(
151147
.item(ORIGIN_KEY_BOOT_DIGEST, boot_digest);
152148
}
153149

154-
let state_dir = cap_std::fs::Dir::open_ambient_dir(&state_path, cap_std::ambient_authority())
155-
.context("Opening state dir")?;
150+
let state_dir =
151+
Dir::open_ambient_dir(&state_path, ambient_authority()).context("Opening state dir")?;
156152

157153
state_dir
158154
.atomic_write(
@@ -165,11 +161,9 @@ pub(crate) fn write_composefs_state(
165161
std::fs::create_dir_all(COMPOSEFS_TRANSIENT_STATE_DIR)
166162
.with_context(|| format!("Creating {COMPOSEFS_TRANSIENT_STATE_DIR}"))?;
167163

168-
let staged_depl_dir = cap_std::fs::Dir::open_ambient_dir(
169-
COMPOSEFS_TRANSIENT_STATE_DIR,
170-
cap_std::ambient_authority(),
171-
)
172-
.with_context(|| format!("Opening {COMPOSEFS_TRANSIENT_STATE_DIR}"))?;
164+
let staged_depl_dir =
165+
Dir::open_ambient_dir(COMPOSEFS_TRANSIENT_STATE_DIR, ambient_authority())
166+
.with_context(|| format!("Opening {COMPOSEFS_TRANSIENT_STATE_DIR}"))?;
173167

174168
staged_depl_dir
175169
.atomic_write(

0 commit comments

Comments
 (0)