bootc_internal_mount/
tempmount.rs1use std::os::fd::AsFd;
2use std::path::Path;
3
4use anyhow::{Context, Result};
5
6use camino::Utf8Path;
7use cap_std_ext::cap_std::{ambient_authority, fs::Dir};
8use fn_error_context::context;
9use rustix::mount::{MountFlags, MoveMountFlags, UnmountFlags, move_mount, unmount};
10
11#[derive(Debug)]
16pub struct MountGuard(std::path::PathBuf);
17
18impl MountGuard {
19 pub fn mount(
22 dev: &str,
23 path: std::path::PathBuf,
24 fstype: &str,
25 flags: MountFlags,
26 data: Option<&std::ffi::CStr>,
27 ) -> Result<Self> {
28 rustix::mount::mount(dev, &path, fstype, flags, data)
29 .with_context(|| format!("Mounting {} at {}", dev, path.display()))?;
30 Ok(Self(path))
31 }
32}
33
34impl std::ops::Deref for MountGuard {
35 type Target = Path;
36 fn deref(&self) -> &Path {
37 &self.0
38 }
39}
40
41impl Drop for MountGuard {
42 fn drop(&mut self) {
43 if let Err(e) = unmount(&self.0, UnmountFlags::empty()) {
44 tracing::error!("Failed to unmount {}: {e:?}", self.0.display());
48 }
49 }
50}
51
52#[derive(Debug)]
54pub struct TempMount {
55 pub dir: tempfile::TempDir,
57 pub fd: Dir,
59}
60
61impl TempMount {
62 #[context("Mounting {dev}")]
64 pub fn mount_dev(
65 dev: &str,
66 fstype: &str,
67 flags: MountFlags,
68 data: Option<&std::ffi::CStr>,
69 ) -> Result<Self> {
70 let tempdir = tempfile::TempDir::new()?;
71
72 let utf8path = Utf8Path::from_path(tempdir.path())
73 .ok_or(anyhow::anyhow!("Failed to convert path to UTF-8 Path"))?;
74
75 rustix::mount::mount(dev, utf8path.as_std_path(), fstype, flags, data)?;
76
77 let fd = Dir::open_ambient_dir(tempdir.path(), ambient_authority())
78 .with_context(|| format!("Opening {:?}", tempdir.path()));
79
80 let fd = match fd {
81 Ok(fd) => fd,
82 Err(e) => {
83 unmount(tempdir.path(), UnmountFlags::DETACH)?;
84 Err(e)?
85 }
86 };
87
88 Ok(Self { dir: tempdir, fd })
89 }
90
91 #[context("Mounting fd")]
93 pub fn mount_fd(mnt_fd: impl AsFd) -> Result<Self> {
94 let tempdir = tempfile::TempDir::new()?;
95
96 move_mount(
97 mnt_fd.as_fd(),
98 "",
99 rustix::fs::CWD,
100 tempdir.path(),
101 MoveMountFlags::MOVE_MOUNT_F_EMPTY_PATH,
102 )
103 .context("move_mount")?;
104
105 let fd = Dir::open_ambient_dir(tempdir.path(), ambient_authority())
106 .with_context(|| format!("Opening {:?}", tempdir.path()));
107
108 let fd = match fd {
109 Ok(fd) => fd,
110 Err(e) => {
111 unmount(tempdir.path(), UnmountFlags::DETACH)?;
112 Err(e)?
113 }
114 };
115
116 Ok(Self { dir: tempdir, fd })
117 }
118}
119
120impl Drop for TempMount {
121 fn drop(&mut self) {
122 match unmount(self.dir.path(), UnmountFlags::DETACH) {
123 Ok(_) => {}
124 Err(e) => tracing::warn!("Failed to unmount tempdir: {e:?}"),
125 }
126 }
127}