Skip to content

Commit cec16f4

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 3cfa0b6 commit cec16f4

File tree

1 file changed

+57
-46
lines changed

1 file changed

+57
-46
lines changed

lib/src/install.rs

Lines changed: 57 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,15 +1538,18 @@ pub(crate) fn setup_composefs_bls_boot(
15381538
id: &Sha256HashValue,
15391539
entry: BootEntry<Sha256HashValue>,
15401540
) -> Result<()> {
1541-
let (root_path, cmdline_refs) = match setup_type {
1542-
BootSetupType::Setup(root_setup) => {
1541+
let (root_path, cmdline_refs, entry_id) = match setup_type {
1542+
BootSetupType::Setup(root_setup) => (
1543+
root_setup.physical_root_path.clone(),
15431544
// root_setup.kargs has [root=UUID=<UUID>, "rw"]
1544-
(root_setup.physical_root_path.clone(), &root_setup.kargs)
1545-
}
1545+
&root_setup.kargs,
1546+
format!("{}", id.to_hex()),
1547+
),
15461548

15471549
BootSetupType::Upgrade => (
15481550
Utf8PathBuf::from("/sysroot"),
15491551
&vec![format!("root=UUID={DPS_UUID}"), RW_KARG.to_string()],
1552+
format!("{}.staged", id.to_hex()),
15501553
),
15511554
};
15521555

@@ -1562,7 +1565,7 @@ pub(crate) fn setup_composefs_bls_boot(
15621565
false,
15631566
root_path.as_std_path(),
15641567
Some("boot"),
1565-
Some(&id.to_hex()),
1568+
Some(&entry_id),
15661569
&str_slice,
15671570
)
15681571
}
@@ -1578,6 +1581,24 @@ pub fn get_esp_partition(device: &str) -> Result<(String, Option<String>)> {
15781581
Ok((esp.node, esp.uuid))
15791582
}
15801583

1584+
fn get_user_config(uki_id: &str) -> String {
1585+
let s = format!(
1586+
r#"
1587+
menuentry "Fedora Bootc UKI: ({uki_id})" {{
1588+
insmod fat
1589+
insmod chain
1590+
search --no-floppy --set=root --fs-uuid "${{EFI_PART_UUID}}"
1591+
chainloader /EFI/Linux/{uki_id}.efi
1592+
}}
1593+
"#
1594+
);
1595+
1596+
return s;
1597+
}
1598+
1599+
/// Contains the EFP's filesystem UUID. Used by grub
1600+
const EFI_UUID_FILE: &str = "efiuuid.cfg";
1601+
15811602
#[context("Setting up UKI boot")]
15821603
pub(crate) fn setup_composefs_uki_boot(
15831604
setup_type: BootSetupType,
@@ -1648,66 +1669,63 @@ pub(crate) fn setup_composefs_uki_boot(
16481669

16491670
let is_upgrade = matches!(setup_type, BootSetupType::Upgrade);
16501671

1651-
// Add the user grug cfg
1652-
let grub_user_config = format!(
1672+
let efi_uuid_source = format!(
16531673
r#"
1654-
menuentry "Fedora Bootc UKI: ({uki_id})" {{
1655-
insmod fat
1656-
insmod chain
1657-
search --no-floppy --set=root --fs-uuid "${{EFI_PART_UUID}}"
1658-
chainloader /EFI/Linux/{uki_id}.efi
1659-
}}
1660-
"#,
1661-
uki_id = id.to_hex(),
1674+
if [ -f ${{config_directory}}/{EFI_UUID_FILE} ]; then
1675+
source ${{config_directory}}/{EFI_UUID_FILE}
1676+
fi
1677+
"#
16621678
);
16631679

1664-
let user_cfg_name = "grub2/user.cfg";
1680+
let user_cfg_name = if is_upgrade {
1681+
"grub2/user.cfg.staged"
1682+
} else {
1683+
"grub2/user.cfg"
1684+
};
16651685
let user_cfg_path = boot_dir.join(user_cfg_name);
16661686

1667-
// TODO: Figure out a better way to sort these menuentries. This is a bit scuffed
1668-
//
1669-
// Read the current user.cfg, split at the first menuentry, then stick the new menuentry in
1670-
// between the efiuuid.cfg sourcing code and the previous menuentry
1687+
// Iterate over all available deployments, and generate a menuentry for each
16711688
if is_upgrade {
1672-
let contents =
1673-
std::fs::read_to_string(&user_cfg_path).context(format!("Reading {user_cfg_name}"))?;
1674-
16751689
let mut usr_cfg = std::fs::OpenOptions::new()
16761690
.write(true)
1677-
.truncate(true)
1691+
.create(true)
16781692
.open(user_cfg_path)
16791693
.with_context(|| format!("Opening {user_cfg_name}"))?;
16801694

1681-
let Some((before, after)) = contents.split_once("menuentry") else {
1682-
anyhow::bail!("Did not find menuentry in {user_cfg_name}")
1683-
};
1695+
usr_cfg.write_all(efi_uuid_source.as_bytes())?;
1696+
usr_cfg.write_all(get_user_config(&id.to_hex()).as_bytes())?;
1697+
1698+
// root_path here will be /sysroot
1699+
for entry in std::fs::read_dir(root_path.join(STATE_DIR_RELATIVE))? {
1700+
let entry = entry?;
16841701

1685-
usr_cfg
1686-
.seek(SeekFrom::Start(0))
1687-
.with_context(|| format!("Seek {user_cfg_name}"))?;
1702+
let depl_file_name = entry.file_name();
1703+
// SAFETY: Deployment file name shouldn't containg non UTF-8 chars
1704+
let depl_file_name = depl_file_name.to_string_lossy();
16881705

1689-
usr_cfg
1690-
.write_all(format!("{before} {grub_user_config}\nmenuentry {after}").as_bytes())
1691-
.with_context(|| format!("Writing to {user_cfg_name}"))?;
1706+
usr_cfg.write_all(get_user_config(&depl_file_name).as_bytes())?;
1707+
}
16921708

16931709
return Ok(());
16941710
}
16951711

1696-
// Open grub2/efiuuid.cfg and write the EFI partition UUID in there
1712+
let efi_uuid_file_path = format!("grub2/{EFI_UUID_FILE}");
1713+
1714+
// Open grub2/efiuuid.cfg and write the EFI partition fs-UUID in there
16971715
// This will be sourced by grub2/user.cfg to be used for `--fs-uuid`
16981716
let mut efi_uuid_file = std::fs::OpenOptions::new()
16991717
.write(true)
17001718
.create(true)
1701-
.open(boot_dir.join("grub2/efiuuid.cfg"))
1702-
.context("Opening grub2/efiuuid.cfg")?;
1719+
.open(boot_dir.join(&efi_uuid_file_path))
1720+
.with_context(|| format!("Opening {efi_uuid_file_path}"))?;
17031721

17041722
let esp_uuid = Task::new("blkid for ESP UUID", "blkid")
17051723
.args(["-s", "UUID", "-o", "value", &esp_device])
17061724
.read()?;
17071725

17081726
efi_uuid_file
17091727
.write_all(format!("set EFI_PART_UUID=\"{}\"", esp_uuid.trim()).as_bytes())
1710-
.context("Writing to grub2/efiuuid.cfg")?;
1728+
.with_context(|| format!("Writing to {efi_uuid_file_path}"))?;
17111729

17121730
// Write to grub2/user.cfg
17131731
let mut usr_cfg = std::fs::OpenOptions::new()
@@ -1716,15 +1734,8 @@ menuentry "Fedora Bootc UKI: ({uki_id})" {{
17161734
.open(user_cfg_path)
17171735
.with_context(|| format!("Opening {user_cfg_name}"))?;
17181736

1719-
let efi_uuid_source = r#"
1720-
if [ -f ${config_directory}/efiuuid.cfg ]; then
1721-
source ${config_directory}/efiuuid.cfg
1722-
fi
1723-
"#;
1724-
1725-
usr_cfg
1726-
.write_all(format!("{efi_uuid_source}\n{grub_user_config}").as_bytes())
1727-
.with_context(|| format!("Writing to {user_cfg_name}"))?;
1737+
usr_cfg.write_all(efi_uuid_source.as_bytes())?;
1738+
usr_cfg.write_all(get_user_config(&id.to_hex()).as_bytes())?;
17281739

17291740
Ok(())
17301741
}

0 commit comments

Comments
 (0)