From 9163e9aa39356a611de99c5cc2e52f684f03ba8a Mon Sep 17 00:00:00 2001 From: HuijingHei Date: Fri, 20 Sep 2024 10:58:31 +0800 Subject: [PATCH] Skip efi if no ESP device detected and skip bios if no bios_boot found Fixes https://github.com/coreos/bootupd/issues/717 --- src/bios.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- src/bootupd.rs | 2 +- src/efi.rs | 35 +++++++++++++++++++++++------------ 3 files changed, 71 insertions(+), 15 deletions(-) diff --git a/src/bios.rs b/src/bios.rs index 481fff16..c7cbb357 100644 --- a/src/bios.rs +++ b/src/bios.rs @@ -3,15 +3,29 @@ use std::path::Path; use std::process::Command; use crate::component::*; +use crate::efi; use crate::model::*; 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 +36,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 +94,34 @@ 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 { @@ -122,6 +163,10 @@ impl Component for Bios { } fn query_adopt(&self) -> Result> { + if efi::is_efi_booted()? && self.get_bios_boot_partition()?.is_none() { + println!("Skip BIOS adopt"); + return Ok(None); + } crate::component::query_adopt_state() } diff --git a/src/bootupd.rs b/src/bootupd.rs index 4f029e83..ca9ae42a 100644 --- a/src/bootupd.rs +++ b/src/bootupd.rs @@ -384,7 +384,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() { + let boot_method = if efi::is_efi_booted()? { "EFI" } else { "BIOS" diff --git a/src/efi.rs b/src/efi.rs index 75c34f4c..bc77d83c 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() { @@ -93,18 +111,8 @@ impl Efi { log::debug!("Reusing existing {mnt:?}"); 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() { @@ -388,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()