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)

Fixes #454
  • Loading branch information
HuijingHei committed Jun 21, 2024
1 parent 8a40a4e commit e7f4e69
Showing 1 changed file with 55 additions and 16 deletions.
71 changes: 55 additions & 16 deletions src/efi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ use anyhow::{bail, Context, Result};
use fn_error_context::context;
use openat_ext::OpenatDirExt;
use os_release::OsRelease;
use rustix::fd::BorrowedFd;
use walkdir::WalkDir;
use widestring::U16CString;

Expand All @@ -26,6 +25,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"];

/// Backup 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 @@ -83,9 +85,9 @@ impl Efi {
if !mnt.exists() {
continue;
}
let st =
rustix::fs::statfs(&mnt).with_context(|| format!("statfs failed for {mnt:?}"))?;
if st.f_type != libc::MSDOS_SUPER_MAGIC {
let st = nix::sys::statfs::statfs(&mnt)
.with_context(|| format!("statfs failed for {mnt:?}"))?;
if st.filesystem_type() != nix::sys::statfs::MSDOS_SUPER_MAGIC {
continue;
}
log::debug!("Reusing existing {mnt:?}");
Expand Down Expand Up @@ -349,12 +351,40 @@ 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("/"))?;

/* copy "lowest" directory that we need to make the change
* e.g. we only affect EFI/fedora for example and not all of EFI
*/

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 @@ -455,13 +485,10 @@ impl Drop for Efi {
}

fn validate_esp(dir: &openat::Dir) -> Result<()> {
let dir = unsafe { BorrowedFd::borrow_raw(dir.as_raw_fd()) };
let stat = rustix::fs::fstatfs(&dir)?;
if stat.f_type != libc::MSDOS_SUPER_MAGIC {
bail!(
"EFI mount is not a msdos filesystem, but is {:?}",
stat.f_type
);
let stat = nix::sys::statfs::fstatfs(dir)?;
let fstype = stat.filesystem_type();
if fstype != nix::sys::statfs::MSDOS_SUPER_MAGIC {
bail!("EFI mount is not a msdos filesystem, but is {:?}", fstype);
};
Ok(())
}
Expand Down Expand Up @@ -584,6 +611,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 e7f4e69

Please sign in to comment.