bootc_internal_mount/
tempmount.rs1use std::os::fd::AsFd;
2
3use anyhow::{Context, Result};
4
5use camino::Utf8Path;
6use cap_std_ext::cap_std::{ambient_authority, fs::Dir};
7use fn_error_context::context;
8use rustix::mount::{MountFlags, MoveMountFlags, UnmountFlags, move_mount, unmount};
9
10#[derive(Debug)]
12pub struct TempMount {
13 pub dir: tempfile::TempDir,
15 pub fd: Dir,
17}
18
19impl TempMount {
20 #[context("Mounting {dev}")]
22 pub fn mount_dev(
23 dev: &str,
24 fstype: &str,
25 flags: MountFlags,
26 data: Option<&std::ffi::CStr>,
27 ) -> Result<Self> {
28 let tempdir = tempfile::TempDir::new()?;
29
30 let utf8path = Utf8Path::from_path(tempdir.path())
31 .ok_or(anyhow::anyhow!("Failed to convert path to UTF-8 Path"))?;
32
33 rustix::mount::mount(dev, utf8path.as_std_path(), fstype, flags, data)?;
34
35 let fd = Dir::open_ambient_dir(tempdir.path(), ambient_authority())
36 .with_context(|| format!("Opening {:?}", tempdir.path()));
37
38 let fd = match fd {
39 Ok(fd) => fd,
40 Err(e) => {
41 unmount(tempdir.path(), UnmountFlags::DETACH)?;
42 Err(e)?
43 }
44 };
45
46 Ok(Self { dir: tempdir, fd })
47 }
48
49 #[context("Mounting fd")]
51 pub fn mount_fd(mnt_fd: impl AsFd) -> Result<Self> {
52 let tempdir = tempfile::TempDir::new()?;
53
54 move_mount(
55 mnt_fd.as_fd(),
56 "",
57 rustix::fs::CWD,
58 tempdir.path(),
59 MoveMountFlags::MOVE_MOUNT_F_EMPTY_PATH,
60 )
61 .context("move_mount")?;
62
63 let fd = Dir::open_ambient_dir(tempdir.path(), ambient_authority())
64 .with_context(|| format!("Opening {:?}", tempdir.path()));
65
66 let fd = match fd {
67 Ok(fd) => fd,
68 Err(e) => {
69 unmount(tempdir.path(), UnmountFlags::DETACH)?;
70 Err(e)?
71 }
72 };
73
74 Ok(Self { dir: tempdir, fd })
75 }
76}
77
78impl Drop for TempMount {
79 fn drop(&mut self) {
80 match unmount(self.dir.path(), UnmountFlags::DETACH) {
81 Ok(_) => {}
82 Err(e) => tracing::warn!("Failed to unmount tempdir: {e:?}"),
83 }
84 }
85}