diff --git a/crates/cfsctl/src/main.rs b/crates/cfsctl/src/main.rs index c0e32369..d853dbf1 100644 --- a/crates/cfsctl/src/main.rs +++ b/crates/cfsctl/src/main.rs @@ -279,6 +279,7 @@ async fn main() -> Result<()> { entry, &id, bootdir, + None, entry_id.as_deref(), &cmdline_refs, )?; diff --git a/crates/composefs-boot/src/bootloader.rs b/crates/composefs-boot/src/bootloader.rs index 29d87a6b..92dea281 100644 --- a/crates/composefs-boot/src/bootloader.rs +++ b/crates/composefs-boot/src/bootloader.rs @@ -144,7 +144,7 @@ impl Type1Entry { // This is a bit of a strange operation: for each file mentioned in the bootloader entry, move // the file into the given 'entry_id' pathname and rename the entry file itself to // "{entry_id}.conf". - pub fn relocate(&mut self, entry_id: &str) { + pub fn relocate(&mut self, boot_subdir: Option<&str>, entry_id: &str) { self.filename = Box::from(format!("{entry_id}.conf").as_ref()); for line in &mut self.entry.lines { for key in ["linux", "initrd", "efi"] { @@ -159,7 +159,14 @@ impl Type1Entry { let new = format!("/{entry_id}/{basename}"); let range = substr_range(line, value).unwrap(); - line.replace_range(range, &new); + + let final_entry_path = if let Some(boot_subdir) = boot_subdir { + format!("/{boot_subdir}{new}") + } else { + new.clone() + }; + + line.replace_range(range, &final_entry_path); if let Some(file) = file { self.files.insert(new.into_boxed_str(), file); diff --git a/crates/composefs-boot/src/write_boot.rs b/crates/composefs-boot/src/write_boot.rs index 2d50fb68..c8b24265 100644 --- a/crates/composefs-boot/src/write_boot.rs +++ b/crates/composefs-boot/src/write_boot.rs @@ -16,10 +16,18 @@ use crate::{ pub fn write_t1_simple( mut t1: Type1Entry, bootdir: &Path, + boot_subdir: Option<&str>, root_id: &ObjectID, cmdline_extra: &[&str], repo: &Repository, ) -> Result<()> { + let bootdir = if let Some(subdir) = boot_subdir { + let subdir_path = Path::new(subdir); + bootdir.join(subdir_path.strip_prefix("/").unwrap_or(subdir_path)) + } else { + bootdir.to_path_buf() + }; + t1.entry .adjust_cmdline(Some(&root_id.to_hex()), cmdline_extra); @@ -63,32 +71,78 @@ pub fn write_t2_simple( Ok(()) } +/// Writes boot entry to the boot partition +/// +/// # Arguments +/// +/// * repo - The composefs repository +/// * entry - Boot entry variant to be written +/// * root_id - The content hash of the generated EROFS image id +/// * boot_partition - Path to the boot partition/directory +/// * boot_subdir - If `Some(path)`, the path is prepended to `initrd` and `linux` keys in the BLS entry +/// +/// For example, if `boot_partition = "/boot"` and `boot_subdir = Some("1")` , +/// the BLS entry will contain +/// +/// ```text +/// linux /boot/1//linux +/// initrd /boot/1//initrd +/// ``` +/// +/// If `boot_partition = "/boot"` and `boot_subdir = None` , the BLS entry will contain +/// +/// ```text +/// linux //linux +/// initrd //initrd +/// ``` +/// +/// * entry_id - In case of a BLS entry, the name of file to be generated in `loader/entries` +/// * cmdline_extra - Extra kernel command line arguments +/// pub fn write_boot_simple( repo: &Repository, entry: BootEntry, root_id: &ObjectID, - bootdir: &Path, + boot_partition: &Path, + boot_subdir: Option<&str>, entry_id: Option<&str>, cmdline_extra: &[&str], ) -> Result<()> { match entry { BootEntry::Type1(mut t1) => { if let Some(name) = entry_id { - t1.relocate(name); + t1.relocate(boot_subdir, name); } - write_t1_simple(t1, bootdir, root_id, cmdline_extra, repo)?; + write_t1_simple( + t1, + boot_partition, + boot_subdir, + root_id, + cmdline_extra, + repo, + )?; } BootEntry::Type2(mut t2) => { if let Some(name) = entry_id { t2.rename(name); } ensure!(cmdline_extra.is_empty(), "Can't add --cmdline args to UKIs"); - write_t2_simple(t2, bootdir, root_id, repo)?; + write_t2_simple(t2, boot_partition, root_id, repo)?; } BootEntry::UsrLibModulesUki(_entry) => todo!(), BootEntry::UsrLibModulesVmLinuz(entry) => { - let t1 = entry.into_type1(entry_id); - write_t1_simple(t1, bootdir, root_id, cmdline_extra, repo)?; + let mut t1 = entry.into_type1(entry_id); + if let Some(name) = entry_id { + t1.relocate(boot_subdir, name); + } + write_t1_simple( + t1, + boot_partition, + boot_subdir, + root_id, + cmdline_extra, + repo, + )?; } };