Skip to content

Commit

Permalink
efi: update the ESP by creating a tmpdir and RENAME_EXCHANGE
Browse files Browse the repository at this point in the history
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
  • Loading branch information
HuijingHei committed Jun 21, 2024
1 parent 8a40a4e commit 5891859
Showing 1 changed file with 43 additions and 5 deletions.
48 changes: 43 additions & 5 deletions src/efi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ use crate::{component::*, packagesystem};
/// Well-known paths to the ESP that may have been mounted external to us.
pub(crate) const ESP_MOUNTS: &[&str] = &["boot/efi", "efi", "boot"];

/// Temp EFI dir
const TEMP_EFI_DIR: &str = ".EFI.tmp";

/// The binary to change EFI boot ordering
const EFIBOOTMGR: &str = "efibootmgr";
#[cfg(target_arch = "aarch64")]
Expand Down Expand Up @@ -349,12 +352,35 @@ impl Component for Efi {
.context("opening update dir")?;
let updatef = filetree::FileTree::new_from_dir(&updated).context("reading update dir")?;
let diff = currentf.diff(&updatef)?;
self.ensure_mounted_esp(Path::new("/"))?;
let destdir = self.open_esp().context("opening EFI dir")?;
validate_esp(&destdir)?;
let mountdir = self.ensure_mounted_esp(Path::new("/"))?;

let efipath = self.esp_path()?;
let tmp_efipath = mountdir.join(TEMP_EFI_DIR);
// remove a previous directory if it exists in order to handle being interrupted in the middle.
if tmp_efipath.exists() {
std::fs::remove_dir_all(&tmp_efipath)?;
}
copy_dir(&efipath, &tmp_efipath).with_context(|| "copying existing files to temp dir")?;

let tmpdir = sysroot.sub_dir(&tmp_efipath)?;
validate_esp(&tmpdir)?;
log::trace!("applying diff: {}", &diff);
filetree::apply_diff(&updated, &destdir, &diff, None)
.context("applying filesystem changes")?;
filetree::apply_diff(&updated, &tmpdir, &diff, None)
.context("applying filesystem changes to temp EFI")?;
{
let esp = sysroot.sub_dir(&mountdir)?;
log::trace!(
"doing local exchange for {} and {}",
tmp_efipath.display(),
efipath.display()
);

esp.local_exchange(&tmp_efipath, &efipath)
.with_context(|| format!("exchange for {:?} and {:?}", tmp_efipath, efipath))?;
// finally remove the temp dir
log::trace!("cleanup: {}", tmp_efipath.display());
std::fs::remove_dir_all(&tmp_efipath).context("clean up temp")?;
}
let adopted_from = None;
Ok(InstalledContent {
meta: updatemeta,
Expand Down Expand Up @@ -584,6 +610,18 @@ fn find_file_recursive<P: AsRef<Path>>(dir: P, target_file: &str) -> Result<Vec<
Ok(result)
}

fn copy_dir(src: &Path, dst: &Path) -> Result<()> {
let r = std::process::Command::new("cp")
.args(["-a"])
.arg(src)
.arg(dst)
.status()?;
if !r.success() {
anyhow::bail!("Failed to copy");
}
Ok(())
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down

0 comments on commit 5891859

Please sign in to comment.