Skip to content

Commit ab8cdc9

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 3c7a2e6 commit ab8cdc9

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
@@ -1540,15 +1540,18 @@ pub(crate) fn setup_composefs_bls_boot(
15401540
id: &Sha256HashValue,
15411541
entry: BootEntry<Sha256HashValue>,
15421542
) -> Result<()> {
1543-
let (root_path, cmdline_refs) = match setup_type {
1544-
BootSetupType::Setup(root_setup) => {
1543+
let (root_path, cmdline_refs, entry_id) = match setup_type {
1544+
BootSetupType::Setup(root_setup) => (
1545+
root_setup.physical_root_path.clone(),
15451546
// root_setup.kargs has [root=UUID=<UUID>, "rw"]
1546-
(root_setup.physical_root_path.clone(), &root_setup.kargs)
1547-
}
1547+
&root_setup.kargs,
1548+
format!("{}", id.to_hex()),
1549+
),
15481550

15491551
BootSetupType::Upgrade => (
15501552
Utf8PathBuf::from("/sysroot"),
15511553
&vec![format!("root=UUID={DPS_UUID}"), RW_KARG.to_string()],
1554+
format!("{}.staged", id.to_hex()),
15521555
),
15531556
};
15541557

@@ -1564,7 +1567,7 @@ pub(crate) fn setup_composefs_bls_boot(
15641567
false,
15651568
root_path.as_std_path(),
15661569
Some("boot"),
1567-
Some(&id.to_hex()),
1570+
Some(&entry_id),
15681571
&str_slice,
15691572
)
15701573
}
@@ -1580,6 +1583,24 @@ pub fn get_esp_partition(device: &str) -> Result<(String, Option<String>)> {
15801583
Ok((esp.node, esp.uuid))
15811584
}
15821585

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

16511672
let is_upgrade = matches!(setup_type, BootSetupType::Upgrade);
16521673

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

1666-
let user_cfg_name = "grub2/user.cfg";
1682+
let user_cfg_name = if is_upgrade {
1683+
"grub2/user.cfg.staged"
1684+
} else {
1685+
"grub2/user.cfg"
1686+
};
16671687
let user_cfg_path = boot_dir.join(user_cfg_name);
16681688

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

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

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

1691-
usr_cfg
1692-
.write_all(format!("{before} {grub_user_config}\nmenuentry {after}").as_bytes())
1693-
.with_context(|| format!("Writing to {user_cfg_name}"))?;
1708+
usr_cfg.write_all(get_user_config(&depl_file_name).as_bytes())?;
1709+
}
16941710

16951711
return Ok(());
16961712
}
16971713

1698-
// Open grub2/efiuuid.cfg and write the EFI partition UUID in there
1714+
let efi_uuid_file_path = format!("grub2/{EFI_UUID_FILE}");
1715+
1716+
// Open grub2/efiuuid.cfg and write the EFI partition fs-UUID in there
16991717
// This will be sourced by grub2/user.cfg to be used for `--fs-uuid`
17001718
let mut efi_uuid_file = std::fs::OpenOptions::new()
17011719
.write(true)
17021720
.create(true)
1703-
.open(boot_dir.join("grub2/efiuuid.cfg"))
1704-
.context("Opening grub2/efiuuid.cfg")?;
1721+
.open(boot_dir.join(&efi_uuid_file_path))
1722+
.with_context(|| format!("Opening {efi_uuid_file_path}"))?;
17051723

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

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

17141732
// Write to grub2/user.cfg
17151733
let mut usr_cfg = std::fs::OpenOptions::new()
@@ -1718,15 +1736,8 @@ menuentry "Fedora Bootc UKI: ({uki_id})" {{
17181736
.open(user_cfg_path)
17191737
.with_context(|| format!("Opening {user_cfg_name}"))?;
17201738

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

17311742
Ok(())
17321743
}

0 commit comments

Comments
 (0)