Skip to content

Commit e5c6cd9

Browse files
committed
efi: Handle already-mounted ESP in mount_esp_device
When running install-to-filesystem, the host may already have the ESP mounted (e.g. /dev/sda15 at /boot/efi). Previously mount_esp_device would unconditionally call mount, which fails with "already mounted". Check if the mount point already contains a vfat filesystem on a different device than its parent (i.e. is a real mount point) before attempting to mount, and reuse the existing mount if so. Assisted-by: Claude Code (Opus 4) Signed-off-by: ckyrouac <ckyrouac@redhat.com>
1 parent 0dbf086 commit e5c6cd9

File tree

1 file changed

+30
-4
lines changed

1 file changed

+30
-4
lines changed

src/efi.rs

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
*/
66

77
use std::cell::RefCell;
8-
use std::os::unix::fs::MetadataExt;
98
use std::os::unix::io::AsRawFd;
109
use std::path::{Path, PathBuf};
1110
use std::process::Command;
@@ -61,6 +60,23 @@ const STUB_INFO_VAR_STR: &str = "StubInfo-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f";
6160
/// The options of cp command for installation
6261
const OPTIONS: &[&str] = &["-rp", "--reflink=auto"];
6362

63+
/// Check if the given path is a mount point via statx(MOUNT_ROOT).
64+
fn is_mount_point(path: &Path) -> Result<bool> {
65+
let parent = path.parent().unwrap_or(path);
66+
let parent = if parent.as_os_str().is_empty() {
67+
Path::new(".")
68+
} else {
69+
parent
70+
};
71+
let parent_dir = Dir::open_ambient_dir(parent, cap_std::ambient_authority())?;
72+
let basename = path
73+
.file_name()
74+
.ok_or_else(|| anyhow::anyhow!("path has no file name: {path:?}"))?;
75+
parent_dir
76+
.is_mountpoint(basename)?
77+
.ok_or_else(|| anyhow::anyhow!("could not determine if {path:?} is a mount point"))
78+
}
79+
6480
/// Return `true` if the system is booted via EFI
6581
pub(crate) fn is_efi_booted() -> Result<bool> {
6682
Path::new("/sys/firmware/efi")
@@ -91,9 +107,7 @@ impl Efi {
91107
// different device than its parent. Without this check, a vfat
92108
// subdirectory (e.g. /boot/efi on a vfat /boot) could be
93109
// misidentified as a mounted ESP.
94-
let path_dev = std::fs::metadata(&path)?.dev();
95-
let parent_dev = std::fs::metadata(path.parent().unwrap_or(&path))?.dev();
96-
if path_dev == parent_dev {
110+
if !is_mount_point(&path)? {
97111
// Same device as parent - this is a subdirectory, not a mount point
98112
log::debug!("Skipping {path:?}: vfat but not a mount point");
99113
continue;
@@ -123,6 +137,18 @@ impl Efi {
123137
if !mnt.exists() {
124138
continue;
125139
}
140+
141+
// Check if the target is already a mounted ESP (e.g. the host
142+
// already has the ESP mounted when running install-to-filesystem).
143+
let st = rustix::fs::statfs(&mnt)?;
144+
if st.f_type == libc::MSDOS_SUPER_MAGIC {
145+
if is_mount_point(&mnt)? {
146+
log::debug!("ESP already mounted at {mnt:?}, reusing");
147+
mountpoint = Some(mnt);
148+
break;
149+
}
150+
}
151+
126152
std::process::Command::new("mount")
127153
.arg(&esp_device)
128154
.arg(&mnt)

0 commit comments

Comments
 (0)