Skip to content

Commit 30e304a

Browse files
committed
Skip updating BIOS on multiple devices with mirrored setups(RAID1)
1 parent 4a620a2 commit 30e304a

File tree

1 file changed

+27
-100
lines changed

1 file changed

+27
-100
lines changed

src/bios.rs

Lines changed: 27 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -2,67 +2,19 @@ use std::io::prelude::*;
22
use std::path::Path;
33
use std::process::Command;
44

5+
use crate::blockdev;
56
use crate::component::*;
67
use crate::model::*;
78
use crate::packagesystem;
89
use anyhow::{bail, Result};
910

10-
use crate::util;
11-
use serde::{Deserialize, Serialize};
12-
1311
// grub2-install file path
1412
pub(crate) const GRUB_BIN: &str = "usr/sbin/grub2-install";
1513

16-
#[derive(Serialize, Deserialize, Debug)]
17-
struct BlockDevice {
18-
path: String,
19-
pttype: Option<String>,
20-
parttypename: Option<String>,
21-
}
22-
23-
#[derive(Serialize, Deserialize, Debug)]
24-
struct Devices {
25-
blockdevices: Vec<BlockDevice>,
26-
}
27-
2814
#[derive(Default)]
2915
pub(crate) struct Bios {}
3016

3117
impl Bios {
32-
// get target device for running update
33-
fn get_device(&self) -> Result<String> {
34-
let mut cmd: Command;
35-
#[cfg(target_arch = "x86_64")]
36-
{
37-
// find /boot partition
38-
cmd = Command::new("findmnt");
39-
cmd.arg("--noheadings")
40-
.arg("--nofsroot")
41-
.arg("--output")
42-
.arg("SOURCE")
43-
.arg("/boot");
44-
let partition = util::cmd_output(&mut cmd)?;
45-
46-
// lsblk to find parent device
47-
cmd = Command::new("lsblk");
48-
cmd.arg("--paths")
49-
.arg("--noheadings")
50-
.arg("--output")
51-
.arg("PKNAME")
52-
.arg(partition.trim());
53-
}
54-
55-
#[cfg(target_arch = "powerpc64")]
56-
{
57-
// get PowerPC-PReP-boot partition
58-
cmd = Command::new("realpath");
59-
cmd.arg("/dev/disk/by-partlabel/PowerPC-PReP-boot");
60-
}
61-
62-
let device = util::cmd_output(&mut cmd)?;
63-
Ok(device)
64-
}
65-
6618
// Return `true` if grub2-modules installed
6719
fn check_grub_modules(&self) -> Result<bool> {
6820
let usr_path = Path::new("/usr/lib/grub");
@@ -115,37 +67,18 @@ impl Bios {
11567
}
11668

11769
// check bios_boot partition on gpt type disk
118-
fn get_bios_boot_partition(&self) -> Result<Option<String>> {
119-
let target = self.get_device()?;
120-
// lsblk to list children with bios_boot
121-
let output = Command::new("lsblk")
122-
.args([
123-
"--json",
124-
"--output",
125-
"PATH,PTTYPE,PARTTYPENAME",
126-
target.trim(),
127-
])
128-
.output()?;
129-
if !output.status.success() {
130-
std::io::stderr().write_all(&output.stderr)?;
131-
bail!("Failed to run lsblk");
70+
fn get_bios_boot_partition(&self) -> Option<Vec<String>> {
71+
let bios_boot_devices =
72+
blockdev::find_colocated_bios_boot("/").expect("get bios_boot devices");
73+
// skip bios update if has multiple devices
74+
if bios_boot_devices.len() > 1 {
75+
log::warn!("Find multiple devices which are currently not supported");
76+
return None;
13277
}
133-
134-
let output = String::from_utf8(output.stdout)?;
135-
// Parse the JSON string into the `Devices` struct
136-
let Ok(devices) = serde_json::from_str::<Devices>(&output) else {
137-
bail!("Could not deserialize JSON output from lsblk");
138-
};
139-
140-
// Find the device with the parttypename "BIOS boot"
141-
for device in devices.blockdevices {
142-
if let Some(parttypename) = &device.parttypename {
143-
if parttypename == "BIOS boot" && device.pttype.as_deref() == Some("gpt") {
144-
return Ok(Some(device.path));
145-
}
146-
}
78+
if !bios_boot_devices.is_empty() {
79+
return Some(bios_boot_devices);
14780
}
148-
Ok(None)
81+
None
14982
}
15083
}
15184

@@ -187,7 +120,7 @@ impl Component for Bios {
187120

188121
fn query_adopt(&self) -> Result<Option<Adoptable>> {
189122
#[cfg(target_arch = "x86_64")]
190-
if crate::efi::is_efi_booted()? && self.get_bios_boot_partition()?.is_none() {
123+
if crate::efi::is_efi_booted()? && self.get_bios_boot_partition().is_none() {
191124
log::debug!("Skip BIOS adopt");
192125
return Ok(None);
193126
}
@@ -199,9 +132,13 @@ impl Component for Bios {
199132
anyhow::bail!("Failed to find adoptable system")
200133
};
201134

202-
let device = self.get_device()?;
203-
let device = device.trim();
204-
self.run_grub_install("/", device)?;
135+
let target_root = "/";
136+
let devices = blockdev::get_backing_devices(&target_root)?
137+
.into_iter()
138+
.next();
139+
let dev = devices.unwrap();
140+
self.run_grub_install(target_root, &dev)?;
141+
log::debug!("Install grub2 on {dev}");
205142
Ok(InstalledContent {
206143
meta: update.clone(),
207144
filetree: None,
@@ -215,9 +152,14 @@ impl Component for Bios {
215152

216153
fn run_update(&self, sysroot: &openat::Dir, _: &InstalledContent) -> Result<InstalledContent> {
217154
let updatemeta = self.query_update(sysroot)?.expect("update available");
218-
let device = self.get_device()?;
219-
let device = device.trim();
220-
self.run_grub_install("/", device)?;
155+
let sysroot = sysroot.recover_path()?;
156+
let dest_root = sysroot.to_str().unwrap_or("/");
157+
let devices = blockdev::get_backing_devices(&dest_root)?
158+
.into_iter()
159+
.next();
160+
let dev = devices.unwrap();
161+
self.run_grub_install(dest_root, &dev)?;
162+
log::debug!("Install grub2 on {dev}");
221163

222164
let adopted_from = None;
223165
Ok(InstalledContent {
@@ -235,18 +177,3 @@ impl Component for Bios {
235177
Ok(None)
236178
}
237179
}
238-
239-
#[cfg(test)]
240-
mod tests {
241-
use super::*;
242-
243-
#[test]
244-
fn test_deserialize_lsblk_output() {
245-
let data = include_str!("../tests/fixtures/example-lsblk-output.json");
246-
let devices: Devices = serde_json::from_str(&data).expect("JSON was not well-formatted");
247-
assert_eq!(devices.blockdevices.len(), 7);
248-
assert_eq!(devices.blockdevices[0].path, "/dev/sr0");
249-
assert!(devices.blockdevices[0].pttype.is_none());
250-
assert!(devices.blockdevices[0].parttypename.is_none());
251-
}
252-
}

0 commit comments

Comments
 (0)