Skip to content

Commit e649743

Browse files
committed
test
1 parent 5136fa7 commit e649743

File tree

3 files changed

+127
-62
lines changed

3 files changed

+127
-62
lines changed

src/bios.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,16 +97,16 @@ impl Bios {
9797
}
9898

9999
// check bios_boot partition on gpt type disk
100+
#[cfg(target_arch = "x86_64")]
100101
fn get_bios_boot_partition(&self) -> Option<String> {
101102
match blockdev::get_single_device("/") {
102103
Ok(device) => {
103104
let bios_boot_part =
104105
blockdev::get_bios_boot_partition(&device).expect("get bios_boot part");
105106
return bios_boot_part;
106107
}
107-
Err(e) => log::warn!("Get error: {}", e),
108+
Err(e) => log::warn!("Get single device: {}", e),
108109
}
109-
log::debug!("Not found any bios_boot partition");
110110
None
111111
}
112112
}
@@ -148,6 +148,7 @@ impl Component for Bios {
148148
}
149149

150150
fn query_adopt(&self) -> Result<Option<Adoptable>> {
151+
// Skip BIOS adopt if booting with efi and without bios_boot part
151152
#[cfg(target_arch = "x86_64")]
152153
if crate::efi::is_efi_booted()? && self.get_bios_boot_partition().is_none() {
153154
log::debug!("Skip BIOS adopt");

src/blockdev.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use anyhow::{bail, Context, Result};
55
use bootc_blockdev::PartitionTable;
66
use fn_error_context::context;
77

8-
#[context("get parent devices from mount point boot")]
8+
#[context("get parent devices from mount point boot or sysroot")]
99
pub fn get_devices<P: AsRef<Path>>(target_root: P) -> Result<Vec<String>> {
1010
let target_root = target_root.as_ref();
1111
let bootdir = target_root.join("boot");
@@ -14,10 +14,18 @@ pub fn get_devices<P: AsRef<Path>>(target_root: P) -> Result<Vec<String>> {
1414
}
1515
let bootdir = openat::Dir::open(&bootdir)?;
1616
// Run findmnt to get the source path of mount point boot
17-
let fsinfo = crate::filesystem::inspect_filesystem(&bootdir, ".")?;
17+
// If failed, change to sysroot
18+
let source= if let Ok(fsinfo) = crate::filesystem::inspect_filesystem(&bootdir, ".") {
19+
fsinfo.source
20+
} else {
21+
let sysroot = target_root.join("sysroot");
22+
let sysrootdir = openat::Dir::open(&sysroot)?;
23+
let fsinfo = crate::filesystem::inspect_filesystem(&sysrootdir, ".")?;
24+
fsinfo.source
25+
};
1826
// Find the parent devices of the source path
19-
let parent_devices = bootc_blockdev::find_parent_devices(&fsinfo.source)
20-
.with_context(|| format!("while looking for backing devices of {}", fsinfo.source))?;
27+
let parent_devices = bootc_blockdev::find_parent_devices(&source)
28+
.with_context(|| format!("while looking for backing devices of {}", source))?;
2129
log::debug!("Find parent devices: {parent_devices:?}");
2230
Ok(parent_devices)
2331
}

src/efi.rs

Lines changed: 112 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use rustix::fd::BorrowedFd;
1919
use walkdir::WalkDir;
2020
use widestring::U16CString;
2121

22+
use crate::blockdev;
2223
use crate::filetree;
2324
use crate::model::*;
2425
use crate::ostreeutil;
@@ -57,28 +58,7 @@ pub(crate) struct Efi {
5758
}
5859

5960
impl Efi {
60-
fn esp_path(&self) -> Result<PathBuf> {
61-
self.ensure_mounted_esp(Path::new("/"))
62-
.map(|v| v.join("EFI"))
63-
}
64-
65-
fn open_esp_optional(&self) -> Result<Option<openat::Dir>> {
66-
if !is_efi_booted()? && self.get_esp_device().is_none() {
67-
log::debug!("Skip EFI");
68-
return Ok(None);
69-
}
70-
let sysroot = openat::Dir::open("/")?;
71-
let esp = sysroot.sub_dir_optional(&self.esp_path()?)?;
72-
Ok(esp)
73-
}
74-
75-
fn open_esp(&self) -> Result<openat::Dir> {
76-
self.ensure_mounted_esp(Path::new("/"))?;
77-
let sysroot = openat::Dir::open("/")?;
78-
let esp = sysroot.sub_dir(&self.esp_path()?)?;
79-
Ok(esp)
80-
}
81-
61+
// Get esp device via legacy
8262
fn get_esp_device(&self) -> Option<PathBuf> {
8363
let esp_devices = [COREOS_ESP_PART_LABEL, ANACONDA_ESP_PART_LABEL]
8464
.into_iter()
@@ -93,11 +73,27 @@ impl Efi {
9373
return esp_device;
9474
}
9575

96-
pub(crate) fn ensure_mounted_esp(&self, root: &Path) -> Result<PathBuf> {
97-
let mut mountpoint = self.mountpoint.borrow_mut();
76+
// Get esp device list on all devices
77+
fn get_esp_devices(&self) -> Option<Vec<String>> {
78+
let mut esp_devices = vec![];
79+
if let Ok(esp_devices) = blockdev::find_colocated_esps("/") {
80+
return Some(esp_devices);
81+
} else {
82+
let device = self.get_esp_device().expect("get esp device");
83+
esp_devices.push(device.to_string_lossy().into_owned());
84+
};
85+
if !esp_devices.is_empty() {
86+
return Some(esp_devices);
87+
}
88+
return None;
89+
}
90+
91+
fn check_mounted_esp<P: AsRef<Path>>(&self, root: P) -> Result<Option<PathBuf>> {
92+
let mountpoint = self.mountpoint.borrow_mut();
9893
if let Some(mountpoint) = mountpoint.as_deref() {
99-
return Ok(mountpoint.to_owned());
94+
return Ok(Some(mountpoint.to_owned()));
10095
}
96+
let root = root.as_ref();
10197
for &mnt in ESP_MOUNTS {
10298
let mnt = root.join(mnt);
10399
if !mnt.exists() {
@@ -109,13 +105,23 @@ impl Efi {
109105
continue;
110106
}
111107
util::ensure_writable_mount(&mnt)?;
112-
log::debug!("Reusing existing {mnt:?}");
113-
return Ok(mnt);
108+
log::debug!("Reusing existing mount point {mnt:?}");
109+
return Ok(Some(mnt));
114110
}
111+
Ok(None)
112+
}
115113

116-
let esp_device = self
117-
.get_esp_device()
118-
.ok_or_else(|| anyhow::anyhow!("Failed to find ESP device"))?;
114+
pub(crate) fn ensure_mounted_esp<P: AsRef<Path>>(
115+
&self,
116+
root: P,
117+
esp_device: &str,
118+
) -> Result<PathBuf> {
119+
let mut mountpoint = self.mountpoint.borrow_mut();
120+
if let Some(mountpoint) = mountpoint.as_deref() {
121+
return Ok(mountpoint.to_owned());
122+
}
123+
124+
let root = root.as_ref();
119125
for &mnt in ESP_MOUNTS.iter() {
120126
let mnt = root.join(mnt);
121127
if !mnt.exists() {
@@ -137,6 +143,7 @@ impl Efi {
137143
if let Some(mount) = self.mountpoint.borrow_mut().take() {
138144
Command::new("umount")
139145
.arg(&mount)
146+
.arg("-l")
140147
.run()
141148
.with_context(|| format!("Failed to unmount {mount:?}"))?;
142149
log::trace!("Unmounted");
@@ -243,8 +250,7 @@ impl Component for Efi {
243250
}
244251

245252
fn query_adopt(&self) -> Result<Option<Adoptable>> {
246-
let esp = self.open_esp_optional()?;
247-
if esp.is_none() {
253+
if self.get_esp_devices().is_none() {
248254
log::trace!("No ESP detected");
249255
return Ok(None);
250256
};
@@ -267,16 +273,32 @@ impl Component for Efi {
267273
anyhow::bail!("Failed to find adoptable system")
268274
};
269275

270-
let esp = self.open_esp()?;
271-
validate_esp(&esp)?;
272276
let updated = sysroot
273277
.sub_dir(&component_updatedirname(self))
274278
.context("opening update dir")?;
275279
let updatef = filetree::FileTree::new_from_dir(&updated).context("reading update dir")?;
276-
// For adoption, we should only touch files that we know about.
277-
let diff = updatef.relative_diff_to(&esp)?;
278-
log::trace!("applying adoption diff: {}", &diff);
279-
filetree::apply_diff(&updated, &esp, &diff, None).context("applying filesystem changes")?;
280+
let esp_devices = self
281+
.get_esp_devices()
282+
.expect("get esp devices before adopt");
283+
let sysroot = sysroot.recover_path()?;
284+
285+
for esp_dev in esp_devices {
286+
let dest_path = if let Some(dest_path) = self.check_mounted_esp(&sysroot)? {
287+
dest_path.join("EFI")
288+
} else {
289+
self.ensure_mounted_esp(&sysroot, &esp_dev)?.join("EFI")
290+
};
291+
292+
let esp = openat::Dir::open(&dest_path).context("opening EFI dir")?;
293+
validate_esp(&esp)?;
294+
295+
// For adoption, we should only touch files that we know about.
296+
let diff = updatef.relative_diff_to(&esp)?;
297+
log::trace!("applying adoption diff: {}", &diff);
298+
filetree::apply_diff(&updated, &esp, &diff, None)
299+
.context("applying filesystem changes")?;
300+
self.unmount().context("unmount after adopt")?;
301+
}
280302
Ok(InstalledContent {
281303
meta: updatemeta.clone(),
282304
filetree: Some(updatef),
@@ -298,9 +320,17 @@ impl Component for Efi {
298320
log::debug!("Found metadata {}", meta.version);
299321
let srcdir_name = component_updatedirname(self);
300322
let ft = crate::filetree::FileTree::new_from_dir(&src_root.sub_dir(&srcdir_name)?)?;
301-
let destdir = &self.ensure_mounted_esp(Path::new(dest_root))?;
323+
let destdir = if let Some(destdir) = self.check_mounted_esp(dest_root)? {
324+
destdir
325+
} else {
326+
let esp_device = self
327+
.get_esp_device()
328+
.ok_or_else(|| anyhow::anyhow!("Failed to find ESP device"))?;
329+
let esp_device = esp_device.to_str().unwrap();
330+
self.ensure_mounted_esp(dest_root, esp_device)?
331+
};
302332

303-
let destd = &openat::Dir::open(destdir)
333+
let destd = &openat::Dir::open(&destdir)
304334
.with_context(|| format!("opening dest dir {}", destdir.display()))?;
305335
validate_esp(destd)?;
306336

@@ -339,12 +369,25 @@ impl Component for Efi {
339369
.context("opening update dir")?;
340370
let updatef = filetree::FileTree::new_from_dir(&updated).context("reading update dir")?;
341371
let diff = currentf.diff(&updatef)?;
342-
self.ensure_mounted_esp(Path::new("/"))?;
343-
let destdir = self.open_esp().context("opening EFI dir")?;
344-
validate_esp(&destdir)?;
345-
log::trace!("applying diff: {}", &diff);
346-
filetree::apply_diff(&updated, &destdir, &diff, None)
347-
.context("applying filesystem changes")?;
372+
let esp_devices = self
373+
.get_esp_devices()
374+
.context("get esp devices when running update")?;
375+
let sysroot = sysroot.recover_path()?;
376+
377+
for esp in esp_devices {
378+
let dest_path = if let Some(dest_path) = self.check_mounted_esp(&sysroot)? {
379+
dest_path.join("EFI")
380+
} else {
381+
self.ensure_mounted_esp(&sysroot, &esp)?.join("EFI")
382+
};
383+
384+
let destdir = openat::Dir::open(&dest_path).context("opening EFI dir")?;
385+
validate_esp(&destdir)?;
386+
log::trace!("applying diff: {}", &diff);
387+
filetree::apply_diff(&updated, &destdir, &diff, None)
388+
.context("applying filesystem changes")?;
389+
self.unmount().context("unmount after update")?;
390+
}
348391
let adopted_from = None;
349392
Ok(InstalledContent {
350393
meta: updatemeta,
@@ -392,24 +435,37 @@ impl Component for Efi {
392435
}
393436

394437
fn validate(&self, current: &InstalledContent) -> Result<ValidationResult> {
395-
if !is_efi_booted()? && self.get_esp_device().is_none() {
438+
let esp_devices = self.get_esp_devices();
439+
if !is_efi_booted()? && esp_devices.is_none() {
396440
return Ok(ValidationResult::Skip);
397441
}
398442
let currentf = current
399443
.filetree
400444
.as_ref()
401445
.ok_or_else(|| anyhow::anyhow!("No filetree for installed EFI found!"))?;
402-
self.ensure_mounted_esp(Path::new("/"))?;
403-
let efidir = self.open_esp()?;
404-
let diff = currentf.relative_diff_to(&efidir)?;
446+
405447
let mut errs = Vec::new();
406-
for f in diff.changes.iter() {
407-
errs.push(format!("Changed: {}", f));
408-
}
409-
for f in diff.removals.iter() {
410-
errs.push(format!("Removed: {}", f));
448+
let esps = esp_devices.ok_or_else(|| anyhow::anyhow!("No esp device found!"))?;
449+
let dest_root = Path::new("/");
450+
for esp_dev in esps.iter() {
451+
let dest_path = if let Some(dest_path) = self.check_mounted_esp(dest_root)? {
452+
dest_path.join("EFI")
453+
} else {
454+
self.ensure_mounted_esp(dest_root, &esp_dev)?.join("EFI")
455+
};
456+
457+
let efidir = openat::Dir::open(dest_path.as_path())?;
458+
let diff = currentf.relative_diff_to(&efidir)?;
459+
460+
for f in diff.changes.iter() {
461+
errs.push(format!("Changed: {}", f));
462+
}
463+
for f in diff.removals.iter() {
464+
errs.push(format!("Removed: {}", f));
465+
}
466+
assert_eq!(diff.additions.len(), 0);
467+
self.unmount().context("unmount after validate")?;
411468
}
412-
assert_eq!(diff.additions.len(), 0);
413469
if !errs.is_empty() {
414470
Ok(ValidationResult::Errors(errs))
415471
} else {

0 commit comments

Comments
 (0)