Skip to content

Commit 10b4b82

Browse files
Johan-Liebert1cgwalters
authored andcommitted
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 <pragyanpoudyal41999@gmail.com> Signed-off-by: Colin Walters <walters@verbum.org>
1 parent 19801c3 commit 10b4b82

4 files changed

Lines changed: 41 additions & 28 deletions

File tree

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
@@ -104,7 +104,12 @@ pub(crate) async fn composefs_native_finalize() -> Result<()> {
104104
let entries_dir = esp_mount.fd.open_dir("loader")?;
105105
rename_exchange_bls_entries(&entries_dir)?;
106106
}
107-
BootType::Uki => rename_staged_uki_entries(&esp_mount.fd)?,
107+
BootType::Uki => {
108+
rename_staged_uki_entries(&esp_mount.fd)?;
109+
110+
let entries_dir = esp_mount.fd.open_dir("loader")?;
111+
rename_exchange_bls_entries(&entries_dir)?;
112+
}
108113
},
109114
};
110115

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: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use bootc_utils::CommandRunExt;
99
use camino::Utf8PathBuf;
1010
use cap_std_ext::cap_std::ambient_authority;
1111
use cap_std_ext::cap_std::fs::Dir;
12-
use cap_std_ext::{cap_std, dirext::CapStdExtDirExt};
12+
use cap_std_ext::dirext::CapStdExtDirExt;
1313
use composefs::fsverity::{FsVerityHashValue, Sha256HashValue};
1414
use fn_error_context::context;
1515

@@ -20,41 +20,36 @@ use rustix::{
2020
};
2121

2222
use crate::bootc_composefs::boot::BootType;
23+
use crate::bootc_composefs::status::get_sorted_type1_boot_entries;
2324
use crate::parsers::bls_config::BLSConfigType;
2425
use crate::{
2526
composefs_consts::{
2627
COMPOSEFS_CMDLINE, COMPOSEFS_STAGED_DEPLOYMENT_FNAME, COMPOSEFS_TRANSIENT_STATE_DIR,
2728
ORIGIN_KEY_BOOT, ORIGIN_KEY_BOOT_DIGEST, ORIGIN_KEY_BOOT_TYPE, SHARED_VAR_PATH,
2829
STATE_DIR_RELATIVE,
2930
},
30-
parsers::bls_config::{parse_bls_config, BLSConfig},
31+
parsers::bls_config::BLSConfig,
3132
spec::ImageReference,
3233
utils::path_relative_to,
3334
};
3435

35-
pub(crate) fn get_booted_bls() -> Result<BLSConfig> {
36+
pub(crate) fn get_booted_bls(boot_dir: &Dir) -> Result<BLSConfig> {
3637
let cmdline = Cmdline::from_proc()?;
3738
let booted = cmdline
3839
.find(COMPOSEFS_CMDLINE)
3940
.ok_or_else(|| anyhow::anyhow!("Failed to find composefs parameter in kernel cmdline"))?;
4041

41-
for entry in std::fs::read_dir("/sysroot/boot/loader/entries")? {
42-
let entry = entry?;
42+
let sorted_entries = get_sorted_type1_boot_entries(boot_dir, true)?;
4343

44-
if !entry.file_name().as_str()?.ends_with(".conf") {
45-
continue;
46-
}
47-
48-
let bls = parse_bls_config(&std::fs::read_to_string(&entry.path())?)?;
49-
50-
match &bls.cfg_type {
44+
for entry in sorted_entries {
45+
match &entry.cfg_type {
5146
BLSConfigType::EFI { efi } => {
5247
let composfs_param_value = booted.value().ok_or(anyhow::anyhow!(
5348
"Failed to get composefs kernel cmdline value"
5449
))?;
5550

5651
if efi.contains(composfs_param_value) {
57-
return Ok(bls);
52+
return Ok(entry);
5853
}
5954
}
6055

@@ -66,7 +61,7 @@ pub(crate) fn get_booted_bls() -> Result<BLSConfig> {
6661
let opts = Cmdline::from(opts);
6762

6863
if opts.iter().any(|v| v == booted) {
69-
return Ok(bls);
64+
return Ok(entry);
7065
}
7166
}
7267

@@ -154,8 +149,8 @@ pub(crate) fn write_composefs_state(
154149
.item(ORIGIN_KEY_BOOT_DIGEST, boot_digest);
155150
}
156151

157-
let state_dir = cap_std::fs::Dir::open_ambient_dir(&state_path, cap_std::ambient_authority())
158-
.context("Opening state dir")?;
152+
let state_dir =
153+
Dir::open_ambient_dir(&state_path, ambient_authority()).context("Opening state dir")?;
159154

160155
state_dir
161156
.atomic_write(
@@ -168,11 +163,9 @@ pub(crate) fn write_composefs_state(
168163
std::fs::create_dir_all(COMPOSEFS_TRANSIENT_STATE_DIR)
169164
.with_context(|| format!("Creating {COMPOSEFS_TRANSIENT_STATE_DIR}"))?;
170165

171-
let staged_depl_dir = cap_std::fs::Dir::open_ambient_dir(
172-
COMPOSEFS_TRANSIENT_STATE_DIR,
173-
cap_std::ambient_authority(),
174-
)
175-
.with_context(|| format!("Opening {COMPOSEFS_TRANSIENT_STATE_DIR}"))?;
166+
let staged_depl_dir =
167+
Dir::open_ambient_dir(COMPOSEFS_TRANSIENT_STATE_DIR, ambient_authority())
168+
.with_context(|| format!("Opening {COMPOSEFS_TRANSIENT_STATE_DIR}"))?;
176169

177170
staged_depl_dir
178171
.atomic_write(

0 commit comments

Comments
 (0)