From b1ca7671ddade1a7079b3cb31af9cdc6c6f47f7c Mon Sep 17 00:00:00 2001 From: HuijingHei Date: Fri, 20 Sep 2024 10:58:31 +0800 Subject: [PATCH] Skip `UEFI` or `BIOS` on none hybrid partition layout - When booting with `BIOS` and no `ESP` device detected, skip `UEFI` checking - When booting with `UEFI` and no `bios_boot` partition found, skip `BIOS` checking Fixes https://github.com/coreos/bootupd/issues/717 --- src/bios.rs | 53 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/bootupd.rs | 6 +----- src/efi.rs | 35 ++++++++++++++++++++++----------- 3 files changed, 76 insertions(+), 18 deletions(-) diff --git a/src/bios.rs b/src/bios.rs index fbe12856..11609d28 100644 --- a/src/bios.rs +++ b/src/bios.rs @@ -8,10 +8,23 @@ use crate::packagesystem; use anyhow::{bail, Result}; use crate::util; +use serde::{Deserialize, Serialize}; // grub2-install file path pub(crate) const GRUB_BIN: &str = "usr/sbin/grub2-install"; +#[derive(Serialize, Deserialize, Debug)] +struct BlockDevice { + path: String, + pttype: String, + parttypename: Option, +} + +#[derive(Serialize, Deserialize, Debug)] +struct Devices { + blockdevices: Vec, +} + #[derive(Default)] pub(crate) struct Bios {} @@ -22,12 +35,11 @@ impl Bios { #[cfg(target_arch = "x86_64")] { // find /boot partition - let boot_dir = Path::new("/").join("boot"); cmd = Command::new("findmnt"); cmd.arg("--noheadings") .arg("--output") .arg("SOURCE") - .arg(boot_dir); + .arg("/boot"); let partition = util::cmd_output(&mut cmd)?; // lsblk to find parent device @@ -81,6 +93,38 @@ impl Bios { } Ok(()) } + + // check bios_boot partition on gpt type disk + fn get_bios_boot_partition(&self) -> Result> { + let target = self.get_device()?; + // lsblk to list children with bios_boot + let output = Command::new("lsblk") + .args([ + "--json", + "--output", + "PATH,PTTYPE,PARTTYPENAME", + target.trim(), + ]) + .output()?; + if !output.status.success() { + std::io::stderr().write_all(&output.stderr)?; + bail!("Failed to run lsblk"); + } + + let output = String::from_utf8(output.stdout)?; + // Parse the JSON string into the `Devices` struct + let devices: Devices = serde_json::from_str(&output).expect("JSON was not well-formatted"); + + // Find the device with the parttypename "BIOS boot" + for device in devices.blockdevices { + if let Some(parttypename) = &device.parttypename { + if parttypename == "BIOS boot" && device.pttype == "gpt" { + return Ok(Some(device.path)); + } + } + } + Ok(None) + } } impl Component for Bios { @@ -120,6 +164,11 @@ impl Component for Bios { } fn query_adopt(&self) -> Result> { + #[cfg(target_arch = "x86_64")] + if crate::efi::is_efi_booted()? && self.get_bios_boot_partition()?.is_none() { + log::debug!("Skip BIOS adopt"); + return Ok(None); + } crate::component::query_adopt_state() } diff --git a/src/bootupd.rs b/src/bootupd.rs index dd441096..2bf2c6b4 100644 --- a/src/bootupd.rs +++ b/src/bootupd.rs @@ -380,11 +380,7 @@ pub(crate) fn print_status(status: &Status) -> Result<()> { #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] { - let boot_method = if Path::new("/sys/firmware/efi").exists() { - "EFI" - } else { - "BIOS" - }; + let boot_method = if efi::is_efi_booted()? { "EFI" } else { "BIOS" }; println!("Boot method: {}", boot_method); } diff --git a/src/efi.rs b/src/efi.rs index 2ab46c24..389de581 100644 --- a/src/efi.rs +++ b/src/efi.rs @@ -63,6 +63,10 @@ impl Efi { } fn open_esp_optional(&self) -> Result> { + if !is_efi_booted()? && self.get_esp_device().is_none() { + log::debug!("Skip EFI"); + return Ok(None); + } let sysroot = openat::Dir::open("/")?; let esp = sysroot.sub_dir_optional(&self.esp_path()?)?; Ok(esp) @@ -75,6 +79,20 @@ impl Efi { Ok(esp) } + fn get_esp_device(&self) -> Option { + let esp_devices = [COREOS_ESP_PART_LABEL, ANACONDA_ESP_PART_LABEL] + .into_iter() + .map(|p| Path::new("/dev/disk/by-partlabel/").join(p)); + let mut esp_device = None; + for path in esp_devices { + if path.exists() { + esp_device = Some(path); + break; + } + } + return esp_device; + } + pub(crate) fn ensure_mounted_esp(&self, root: &Path) -> Result { let mut mountpoint = self.mountpoint.borrow_mut(); if let Some(mountpoint) = mountpoint.as_deref() { @@ -94,17 +112,9 @@ impl Efi { return Ok(mnt); } - let esp_devices = [COREOS_ESP_PART_LABEL, ANACONDA_ESP_PART_LABEL] - .into_iter() - .map(|p| Path::new("/dev/disk/by-partlabel/").join(p)); - let mut esp_device = None; - for path in esp_devices { - if path.exists() { - esp_device = Some(path); - break; - } - } - let esp_device = esp_device.ok_or_else(|| anyhow::anyhow!("Failed to find ESP device"))?; + let esp_device = self + .get_esp_device() + .ok_or_else(|| anyhow::anyhow!("Failed to find ESP device"))?; for &mnt in ESP_MOUNTS.iter() { let mnt = root.join(mnt); if !mnt.exists() { @@ -386,6 +396,9 @@ impl Component for Efi { } fn validate(&self, current: &InstalledContent) -> Result { + if !is_efi_booted()? && self.get_esp_device().is_none() { + return Ok(ValidationResult::Skip); + } let currentf = current .filetree .as_ref()