Skip to content

Commit 5891859

Browse files
committed
efi: update the ESP by creating a tmpdir and RENAME_EXCHANGE
See Timothée's comment #454 (comment) Also make some tunes for the logic: - `cp -a EFI .EFI.tmp` - We start with a copy to make sure to keep all other files that we do not explicitly track in bootupd - Update the content of `.EFI.tmp` with the new binaries - Exchange `.EFI.tmp -> EFI` - Remove now "old" .EFI.tmp Fixes #454
1 parent 8a40a4e commit 5891859

File tree

1 file changed

+43
-5
lines changed

1 file changed

+43
-5
lines changed

src/efi.rs

+43-5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ use crate::{component::*, packagesystem};
2626
/// Well-known paths to the ESP that may have been mounted external to us.
2727
pub(crate) const ESP_MOUNTS: &[&str] = &["boot/efi", "efi", "boot"];
2828

29+
/// Temp EFI dir
30+
const TEMP_EFI_DIR: &str = ".EFI.tmp";
31+
2932
/// The binary to change EFI boot ordering
3033
const EFIBOOTMGR: &str = "efibootmgr";
3134
#[cfg(target_arch = "aarch64")]
@@ -349,12 +352,35 @@ impl Component for Efi {
349352
.context("opening update dir")?;
350353
let updatef = filetree::FileTree::new_from_dir(&updated).context("reading update dir")?;
351354
let diff = currentf.diff(&updatef)?;
352-
self.ensure_mounted_esp(Path::new("/"))?;
353-
let destdir = self.open_esp().context("opening EFI dir")?;
354-
validate_esp(&destdir)?;
355+
let mountdir = self.ensure_mounted_esp(Path::new("/"))?;
356+
357+
let efipath = self.esp_path()?;
358+
let tmp_efipath = mountdir.join(TEMP_EFI_DIR);
359+
// remove a previous directory if it exists in order to handle being interrupted in the middle.
360+
if tmp_efipath.exists() {
361+
std::fs::remove_dir_all(&tmp_efipath)?;
362+
}
363+
copy_dir(&efipath, &tmp_efipath).with_context(|| "copying existing files to temp dir")?;
364+
365+
let tmpdir = sysroot.sub_dir(&tmp_efipath)?;
366+
validate_esp(&tmpdir)?;
355367
log::trace!("applying diff: {}", &diff);
356-
filetree::apply_diff(&updated, &destdir, &diff, None)
357-
.context("applying filesystem changes")?;
368+
filetree::apply_diff(&updated, &tmpdir, &diff, None)
369+
.context("applying filesystem changes to temp EFI")?;
370+
{
371+
let esp = sysroot.sub_dir(&mountdir)?;
372+
log::trace!(
373+
"doing local exchange for {} and {}",
374+
tmp_efipath.display(),
375+
efipath.display()
376+
);
377+
378+
esp.local_exchange(&tmp_efipath, &efipath)
379+
.with_context(|| format!("exchange for {:?} and {:?}", tmp_efipath, efipath))?;
380+
// finally remove the temp dir
381+
log::trace!("cleanup: {}", tmp_efipath.display());
382+
std::fs::remove_dir_all(&tmp_efipath).context("clean up temp")?;
383+
}
358384
let adopted_from = None;
359385
Ok(InstalledContent {
360386
meta: updatemeta,
@@ -584,6 +610,18 @@ fn find_file_recursive<P: AsRef<Path>>(dir: P, target_file: &str) -> Result<Vec<
584610
Ok(result)
585611
}
586612

613+
fn copy_dir(src: &Path, dst: &Path) -> Result<()> {
614+
let r = std::process::Command::new("cp")
615+
.args(["-a"])
616+
.arg(src)
617+
.arg(dst)
618+
.status()?;
619+
if !r.success() {
620+
anyhow::bail!("Failed to copy");
621+
}
622+
Ok(())
623+
}
624+
587625
#[cfg(test)]
588626
mod tests {
589627
use super::*;

0 commit comments

Comments
 (0)