diff options
Diffstat (limited to 'hscript')
-rw-r--r-- | hscript/meta.cc | 51 |
1 files 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 <cstring> # include <sys/mount.h> +# include <sys/syscall.h> /* SYS_mount_setattr */ +# include <linux/mount.h> /* MOUNT_ATTR_RDONLY, struct mount_attr */ # include "util/filesystem.hh" #endif /* HAS_INSTALL_ENV */ #include <unistd.h> /* 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<std::string> 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 */ } |