From bb5a9ac3e9d363b52d39081106261ff45340b570 Mon Sep 17 00:00:00 2001 From: "Brad P. Crochet" Date: Mon, 25 Mar 2024 21:22:38 -0400 Subject: [PATCH] Ensure /dev is mounted before losetup is called Not a race condition, but more of a timing issue. Just needed to make sure the /dev mount was happening before any of the losetup calls. Fixes #352 Signed-off-by: Brad P. Crochet rh-pre-commit.version: 2.2.0 rh-pre-commit.check-secrets: ENABLED --- lib/src/blockdev.rs | 16 ++++++++++++++++ lib/src/install.rs | 5 +++++ lib/src/mount.rs | 24 ++++++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/lib/src/blockdev.rs b/lib/src/blockdev.rs index f6683e3e..c9a1e89b 100644 --- a/lib/src/blockdev.rs +++ b/lib/src/blockdev.rs @@ -13,6 +13,10 @@ use std::os::unix::io::AsRawFd; use std::path::Path; use std::process::Command; +/// The mount path and type for devtmpfs +#[cfg(feature = "install")] +const DEV_MOUNT_POINT: &str = "/dev"; + #[derive(Debug, Deserialize)] struct DevicesOutput { blockdevices: Vec, @@ -80,9 +84,21 @@ pub(crate) struct LoopbackDevice { pub(crate) dev: Option, } +// Ensure that `/dev` directory exists and is mounted. +fn ensure_dev_mounted() -> Result<()> { + crate::mount::ensure_mount( + "none", + DEV_MOUNT_POINT.into(), + crate::mount::FilesystemType::DevTmpFs, + )?; + Ok(()) +} + impl LoopbackDevice { // Create a new loopback block device targeting the provided file path. pub(crate) fn new(path: &Path) -> Result { + // Ensure /dev exists and is mounted + ensure_dev_mounted()?; let dev = Task::new("losetup", "losetup") .args(["--show", "--direct-io=on", "-P", "--find"]) .arg(path) diff --git a/lib/src/install.rs b/lib/src/install.rs index 96002fb6..0841b708 100644 --- a/lib/src/install.rs +++ b/lib/src/install.rs @@ -1069,6 +1069,11 @@ async fn prepare_install( ensure_var()?; setup_tmp_mounts()?; + crate::mount::ensure_mount( + "none", + Utf8Path::new("/dev"), + crate::mount::FilesystemType::DevTmpFs, + )?; // Even though we require running in a container, the mounts we create should be specific // to this process, so let's enter a private mountns to avoid leaking them. diff --git a/lib/src/mount.rs b/lib/src/mount.rs index 431d4f13..b060cac3 100644 --- a/lib/src/mount.rs +++ b/lib/src/mount.rs @@ -4,6 +4,7 @@ use anyhow::{anyhow, Context, Result}; use camino::Utf8Path; use fn_error_context::context; use serde::Deserialize; +use std::fmt; use crate::task::Task; @@ -17,6 +18,19 @@ pub(crate) struct Filesystem { pub(crate) uuid: Option, } +#[derive(Deserialize, Debug)] +pub(crate) enum FilesystemType { + DevTmpFs, +} + +impl fmt::Display for FilesystemType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + FilesystemType::DevTmpFs => write!(f, "devtmpfs"), + } + } +} + #[derive(Deserialize, Debug)] pub(crate) struct Findmnt { pub(crate) filesystems: Vec, @@ -57,3 +71,13 @@ pub(crate) fn mount(dev: &str, target: &Utf8Path) -> Result<()> { [dev, target.as_str()], ) } + +/// Create the target directory if it does not exist, then mount the specified filesystem +pub(crate) fn ensure_mount(dev: &str, target: &Utf8Path, fstype: FilesystemType) -> Result<()> { + std::fs::create_dir_all(target)?; + Task::new(format!("Mounting {fstype} {target}"), "mount") + .args(["-t", format!("{fstype}").as_str(), dev, target.as_str()]) + .quiet() + .run()?; + Ok(()) +}