Skip to content

Commit 71de32c

Browse files
composefs/install: Write entries as staged
On upgrade/switch write UKI and BLS entries with the suffix .staged This should be atomically renamed by the equivalent of `ostree-finalize.service` for composefs. In case of grub menuentries for UKI case, rewrite the entire file by reading /sysroot/state/deploy/<deployment_id> Signed-off-by: Pragyan Poudyal <[email protected]>
1 parent 5887dbf commit 71de32c

File tree

1 file changed

+57
-46
lines changed

1 file changed

+57
-46
lines changed

crates/lib/src/install.rs

Lines changed: 57 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1531,15 +1531,18 @@ pub(crate) fn setup_composefs_bls_boot(
15311531
id: &Sha256HashValue,
15321532
entry: BootEntry<Sha256HashValue>,
15331533
) -> Result<()> {
1534-
let (root_path, cmdline_refs) = match setup_type {
1535-
BootSetupType::Setup(root_setup) => {
1534+
let (root_path, cmdline_refs, entry_id) = match setup_type {
1535+
BootSetupType::Setup(root_setup) => (
1536+
root_setup.physical_root_path.clone(),
15361537
// root_setup.kargs has [root=UUID=<UUID>, "rw"]
1537-
(root_setup.physical_root_path.clone(), &root_setup.kargs)
1538-
}
1538+
&root_setup.kargs,
1539+
format!("{}", id.to_hex()),
1540+
),
15391541

15401542
BootSetupType::Upgrade => (
15411543
Utf8PathBuf::from("/sysroot"),
15421544
&vec![format!("root=UUID={DPS_UUID}"), RW_KARG.to_string()],
1545+
format!("{}.staged", id.to_hex()),
15431546
),
15441547
};
15451548

@@ -1555,7 +1558,7 @@ pub(crate) fn setup_composefs_bls_boot(
15551558
false,
15561559
root_path.as_std_path(),
15571560
Some("boot"),
1558-
Some(&id.to_hex()),
1561+
Some(&entry_id),
15591562
&str_slice,
15601563
)
15611564
}
@@ -1571,6 +1574,24 @@ pub fn get_esp_partition(device: &str) -> Result<(String, Option<String>)> {
15711574
Ok((esp.node, esp.uuid))
15721575
}
15731576

1577+
fn get_user_config(uki_id: &str) -> String {
1578+
let s = format!(
1579+
r#"
1580+
menuentry "Fedora Bootc UKI: ({uki_id})" {{
1581+
insmod fat
1582+
insmod chain
1583+
search --no-floppy --set=root --fs-uuid "${{EFI_PART_UUID}}"
1584+
chainloader /EFI/Linux/{uki_id}.efi
1585+
}}
1586+
"#
1587+
);
1588+
1589+
return s;
1590+
}
1591+
1592+
/// Contains the EFP's filesystem UUID. Used by grub
1593+
const EFI_UUID_FILE: &str = "efiuuid.cfg";
1594+
15741595
#[context("Setting up UKI boot")]
15751596
pub(crate) fn setup_composefs_uki_boot(
15761597
setup_type: BootSetupType,
@@ -1641,66 +1662,63 @@ pub(crate) fn setup_composefs_uki_boot(
16411662

16421663
let is_upgrade = matches!(setup_type, BootSetupType::Upgrade);
16431664

1644-
// Add the user grug cfg
1645-
let grub_user_config = format!(
1665+
let efi_uuid_source = format!(
16461666
r#"
1647-
menuentry "Fedora Bootc UKI: ({uki_id})" {{
1648-
insmod fat
1649-
insmod chain
1650-
search --no-floppy --set=root --fs-uuid "${{EFI_PART_UUID}}"
1651-
chainloader /EFI/Linux/{uki_id}.efi
1652-
}}
1653-
"#,
1654-
uki_id = id.to_hex(),
1667+
if [ -f ${{config_directory}}/{EFI_UUID_FILE} ]; then
1668+
source ${{config_directory}}/{EFI_UUID_FILE}
1669+
fi
1670+
"#
16551671
);
16561672

1657-
let user_cfg_name = "grub2/user.cfg";
1673+
let user_cfg_name = if is_upgrade {
1674+
"grub2/user.cfg.staged"
1675+
} else {
1676+
"grub2/user.cfg"
1677+
};
16581678
let user_cfg_path = boot_dir.join(user_cfg_name);
16591679

1660-
// TODO: Figure out a better way to sort these menuentries. This is a bit scuffed
1661-
//
1662-
// Read the current user.cfg, split at the first menuentry, then stick the new menuentry in
1663-
// between the efiuuid.cfg sourcing code and the previous menuentry
1680+
// Iterate over all available deployments, and generate a menuentry for each
16641681
if is_upgrade {
1665-
let contents =
1666-
std::fs::read_to_string(&user_cfg_path).context(format!("Reading {user_cfg_name}"))?;
1667-
16681682
let mut usr_cfg = std::fs::OpenOptions::new()
16691683
.write(true)
1670-
.truncate(true)
1684+
.create(true)
16711685
.open(user_cfg_path)
16721686
.with_context(|| format!("Opening {user_cfg_name}"))?;
16731687

1674-
let Some((before, after)) = contents.split_once("menuentry") else {
1675-
anyhow::bail!("Did not find menuentry in {user_cfg_name}")
1676-
};
1688+
usr_cfg.write_all(efi_uuid_source.as_bytes())?;
1689+
usr_cfg.write_all(get_user_config(&id.to_hex()).as_bytes())?;
1690+
1691+
// root_path here will be /sysroot
1692+
for entry in std::fs::read_dir(root_path.join(STATE_DIR_RELATIVE))? {
1693+
let entry = entry?;
16771694

1678-
usr_cfg
1679-
.seek(SeekFrom::Start(0))
1680-
.with_context(|| format!("Seek {user_cfg_name}"))?;
1695+
let depl_file_name = entry.file_name();
1696+
// SAFETY: Deployment file name shouldn't containg non UTF-8 chars
1697+
let depl_file_name = depl_file_name.to_string_lossy();
16811698

1682-
usr_cfg
1683-
.write_all(format!("{before} {grub_user_config}\nmenuentry {after}").as_bytes())
1684-
.with_context(|| format!("Writing to {user_cfg_name}"))?;
1699+
usr_cfg.write_all(get_user_config(&depl_file_name).as_bytes())?;
1700+
}
16851701

16861702
return Ok(());
16871703
}
16881704

1689-
// Open grub2/efiuuid.cfg and write the EFI partition UUID in there
1705+
let efi_uuid_file_path = format!("grub2/{EFI_UUID_FILE}");
1706+
1707+
// Open grub2/efiuuid.cfg and write the EFI partition fs-UUID in there
16901708
// This will be sourced by grub2/user.cfg to be used for `--fs-uuid`
16911709
let mut efi_uuid_file = std::fs::OpenOptions::new()
16921710
.write(true)
16931711
.create(true)
1694-
.open(boot_dir.join("grub2/efiuuid.cfg"))
1695-
.context("Opening grub2/efiuuid.cfg")?;
1712+
.open(boot_dir.join(&efi_uuid_file_path))
1713+
.with_context(|| format!("Opening {efi_uuid_file_path}"))?;
16961714

16971715
let esp_uuid = Task::new("blkid for ESP UUID", "blkid")
16981716
.args(["-s", "UUID", "-o", "value", &esp_device])
16991717
.read()?;
17001718

17011719
efi_uuid_file
17021720
.write_all(format!("set EFI_PART_UUID=\"{}\"", esp_uuid.trim()).as_bytes())
1703-
.context("Writing to grub2/efiuuid.cfg")?;
1721+
.with_context(|| format!("Writing to {efi_uuid_file_path}"))?;
17041722

17051723
// Write to grub2/user.cfg
17061724
let mut usr_cfg = std::fs::OpenOptions::new()
@@ -1709,15 +1727,8 @@ menuentry "Fedora Bootc UKI: ({uki_id})" {{
17091727
.open(user_cfg_path)
17101728
.with_context(|| format!("Opening {user_cfg_name}"))?;
17111729

1712-
let efi_uuid_source = r#"
1713-
if [ -f ${config_directory}/efiuuid.cfg ]; then
1714-
source ${config_directory}/efiuuid.cfg
1715-
fi
1716-
"#;
1717-
1718-
usr_cfg
1719-
.write_all(format!("{efi_uuid_source}\n{grub_user_config}").as_bytes())
1720-
.with_context(|| format!("Writing to {user_cfg_name}"))?;
1730+
usr_cfg.write_all(efi_uuid_source.as_bytes())?;
1731+
usr_cfg.write_all(get_user_config(&id.to_hex()).as_bytes())?;
17211732

17221733
Ok(())
17231734
}

0 commit comments

Comments
 (0)