From 975b506cdd645edb75312a1e8ead9346e69b3ecf Mon Sep 17 00:00:00 2001 From: "A. Wilcox" Date: Sat, 21 Oct 2023 21:21:15 -0500 Subject: hscript: bootloader: Really, truly revamp EFI This should handle every single scenario we could be in regarding efivarfs. It also makes efivarfs errors non-fatal, as grub-install has --no-nvram for such situations. Closes: #370 Fixes: bad8487c53 ("hscript: bootloader: Hopefully fix EFI once and for all") --- hscript/meta.cc | 51 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/hscript/meta.cc b/hscript/meta.cc index abf0792..9ba1b40 100644 --- a/hscript/meta.cc +++ b/hscript/meta.cc @@ -18,6 +18,8 @@ #ifdef HAS_INSTALL_ENV # include # include +# include /* SYS_mount_setattr */ +# include /* MOUNT_ATTR_RDONLY, struct mount_attr */ # include "util/filesystem.hh" #endif /* HAS_INSTALL_ENV */ #include /* access - used by tz code even in RT env */ @@ -853,25 +855,54 @@ bool Bootloader::execute() const { return false; } - /* remount EFI vars r/w */ + std::vector grub_params = {script->targetDirectory(), + "grub-install"}; + /* handle EFI vars partition */ const auto efipath{script->targetDirectory() + "/sys/firmware/efi/efivars"}; - if(mount("efivarfs", efipath.c_str(), "efivarfs", MS_NOEXEC | - MS_NODEV | MS_NOSUID | MS_RELATIME, nullptr) != 0) { - output_error(pos, "bootloader: failed to mount writable efivarfs", - ::strerror(errno)); - return false; + bool efivarfs = false; + bool umount = false; + if(fs::exists(efipath)) { + if(mount("efivarfs", efipath.c_str(), "efivarfs", MS_NOEXEC | + MS_NODEV | MS_NOSUID | MS_RELATIME, nullptr) != 0) { + if(errno == EBUSY) { + struct mount_attr attr = {}; + attr.attr_clr = MS_RDONLY; + if(syscall(SYS_mount_setattr, -1, efipath.c_str(), 0, + &attr, sizeof(attr)) != 0) { + output_error(pos, "bootloader: failed to make NVRAM read/write", + ::strerror(errno)); + } else { + efivarfs = true; + } + } + output_error(pos, "bootloader: failed to mount efivarfs", + ::strerror(errno)); + } else { + efivarfs = true; + umount = true; /* We mounted it ourselves. */ + } } - if(run_command("chroot", - {script->targetDirectory(), "grub-install", _device}) - != 0) { + if(!efivarfs) { + output_warning(pos, "bootloader: efivarfs is not available", + "NVRAM variables cannot be updated!"); + grub_params.push_back("--no-nvram"); + } + + if(fs::exists(script->targetDirectory() + "/boot/efi")) { + grub_params.push_back("--efi-directory=/boot/efi"); + } + + grub_params.push_back(_device); + + if(run_command("chroot", grub_params) != 0) { output_error(pos, "bootloader: failed to install GRUB"); return false; } /* done, back to r/o */ - umount(efipath.c_str()); + if(umount) ::umount(efipath.c_str()); goto updateboot; #endif /* HAS_INSTALL_ENV */ } -- cgit v1.2.3-60-g2f50