composefs_boot/
write_boot.rs1use std::{
9 fs::{create_dir_all, write},
10 path::Path,
11};
12
13use anyhow::{Context, Result, ensure};
14
15use composefs::{fsverity::FsVerityHashValue, repository::Repository};
16
17use crate::{
18 bootloader::{BootEntry, Type1Entry, Type2Entry},
19 cmdline::ComposefsCmdline,
20 uki,
21};
22
23pub fn write_t1_simple<ObjectID: FsVerityHashValue>(
34 mut t1: Type1Entry<ObjectID>,
35 bootdir: &Path,
36 boot_subdir: Option<&str>,
37 karg: &ComposefsCmdline<ObjectID>,
38 cmdline_extra: &[&str],
39 repo: &Repository<ObjectID>,
40) -> Result<()> {
41 let bootdir = if let Some(subdir) = boot_subdir {
42 let subdir_path = Path::new(subdir);
43 bootdir.join(subdir_path.strip_prefix("/").unwrap_or(subdir_path))
44 } else {
45 bootdir.to_path_buf()
46 };
47
48 let karg_str = karg.to_cmdline_arg();
49 t1.entry.adjust_cmdline(Some(&karg_str), cmdline_extra);
50
51 for (filename, file) in &t1.files {
53 let pathname = Path::new(filename.as_ref());
54 let file_path = bootdir.join(pathname.strip_prefix(Path::new("/"))?);
55 create_dir_all(file_path.parent().unwrap())?;
57 write(file_path, composefs::fs::read_file(file, repo)?)?;
58 }
59
60 let loader_entries = bootdir.join("loader/entries");
62 create_dir_all(&loader_entries)?;
63 let entry = loader_entries.join(t1.filename.as_ref());
64 let entry_content = t1.entry.lines.join("\n") + "\n";
65 write(entry, entry_content)?;
66 Ok(())
67}
68
69pub fn write_t2_simple<ObjectID: FsVerityHashValue>(
81 t2: Type2Entry<ObjectID>,
82 bootdir: &Path,
83 acceptable_digests: &[&ObjectID],
84 repo: &Repository<ObjectID>,
85) -> Result<()> {
86 let efi_linux = bootdir.join("EFI/Linux");
87 create_dir_all(&efi_linux)?;
88 let filename = efi_linux.join(t2.file_path);
89 let content = composefs::fs::read_file(&t2.file, repo)?;
90 let cmdline = uki::get_cmdline(&content)?;
91 let parsed = ComposefsCmdline::<ObjectID>::from_cmdline(cmdline)
92 .with_context(|| format!("parsing UKI .cmdline section: {cmdline:?}"))?
93 .ok_or_else(|| {
94 anyhow::anyhow!(
95 "UKI .cmdline has no composefs karg (composefs= or composefs.digest=): {cmdline:?}"
96 )
97 })?;
98
99 parsed.validate_digest(acceptable_digests.iter().copied())?;
100 write(filename, content)?;
101 Ok(())
102}
103
104pub fn write_boot_simple<ObjectID: FsVerityHashValue>(
134 repo: &Repository<ObjectID>,
135 entry: BootEntry<ObjectID>,
136 karg: &ComposefsCmdline<ObjectID>,
137 boot_partition: &Path,
138 boot_subdir: Option<&str>,
139 entry_id: Option<&str>,
140 cmdline_extra: &[&str],
141) -> Result<()> {
142 match entry {
143 BootEntry::Type1(mut t1) => {
144 if let Some(name) = entry_id {
145 t1.relocate(boot_subdir, name);
146 }
147 write_t1_simple(t1, boot_partition, boot_subdir, karg, cmdline_extra, repo)?;
148 }
149 BootEntry::Type2(mut t2) => {
150 if let Some(name) = entry_id {
151 t2.rename(name);
152 }
153 ensure!(cmdline_extra.is_empty(), "Can't add --cmdline args to UKIs");
154 write_t2_simple(t2, boot_partition, &[karg.digest()], repo)?;
155 }
156 BootEntry::UsrLibModulesVmLinuz(entry) => {
157 let mut t1 = entry.into_type1(entry_id)?;
158 if let Some(name) = entry_id {
159 t1.relocate(boot_subdir, name);
160 }
161 write_t1_simple(t1, boot_partition, boot_subdir, karg, cmdline_extra, repo)?;
162 }
163 };
164
165 Ok(())
166}