bwrap: Create a RoFilesMount struct
This cleans up the drop handling/ownership.
This commit is contained in:
parent
fa81456cbf
commit
8ba6348267
@ -27,37 +27,7 @@ pub(crate) struct Bubblewrap {
|
|||||||
child_argv0: Option<NonZeroUsize>,
|
child_argv0: Option<NonZeroUsize>,
|
||||||
launcher: gio::SubprocessLauncher, // 🚀
|
launcher: gio::SubprocessLauncher, // 🚀
|
||||||
|
|
||||||
tempdirs: Vec<tempfile::TempDir>,
|
rofiles_mounts: Vec<RoFilesMount>,
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for Bubblewrap {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
for d in self.tempdirs.drain(..) {
|
|
||||||
// We need to unmount the tempdirs, before letting
|
|
||||||
// the drop handler recursively remove them.
|
|
||||||
let success = Command::new("fusermount")
|
|
||||||
.arg("-u")
|
|
||||||
.arg(d.path())
|
|
||||||
.status()
|
|
||||||
.map_err(anyhow::Error::new)
|
|
||||||
.and_then(|status| -> Result<()> {
|
|
||||||
if !status.success() {
|
|
||||||
Err(anyhow::anyhow!("{}", status))
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.err()
|
|
||||||
.map(|e| {
|
|
||||||
systemd::journal::print(4, &format!("{}", e));
|
|
||||||
})
|
|
||||||
.is_none();
|
|
||||||
if !success {
|
|
||||||
// If fusermount fails, then we cannot remove it; just leak it.
|
|
||||||
let _ = d.into_path();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// nspawn by default doesn't give us CAP_NET_ADMIN; see
|
// nspawn by default doesn't give us CAP_NET_ADMIN; see
|
||||||
@ -72,21 +42,69 @@ fn running_in_nspawn() -> bool {
|
|||||||
std::env::var_os("container").as_deref() == Some(std::ffi::OsStr::new("systemd-nspawn"))
|
std::env::var_os("container").as_deref() == Some(std::ffi::OsStr::new("systemd-nspawn"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_rofiles_in(rootfs: &openat::Dir, path: &str) -> Result<tempfile::TempDir> {
|
/// A wrapper for rofiles-fuse from ostree. This protects the underlying
|
||||||
let path = path.trim_start_matches('/');
|
/// hardlinked files from mutation. The mount point is a temporary
|
||||||
let tempdir = tempfile::Builder::new()
|
/// directory.
|
||||||
.prefix("rpmostree-rofiles-fuse")
|
struct RoFilesMount {
|
||||||
.tempdir()?;
|
tempdir: Option<tempfile::TempDir>,
|
||||||
let status = std::process::Command::new("rofiles-fuse")
|
}
|
||||||
.arg("--copyup")
|
|
||||||
.arg(path)
|
impl RoFilesMount {
|
||||||
.arg(tempdir.path())
|
/// Create a new rofiles-fuse mount point
|
||||||
.current_dir(format!("/proc/self/fd/{}", rootfs.as_raw_fd()))
|
fn new(rootfs: &openat::Dir, path: &str) -> Result<Self> {
|
||||||
.status()?;
|
let path = path.trim_start_matches('/');
|
||||||
if !status.success() {
|
let tempdir = tempfile::Builder::new()
|
||||||
return Err(anyhow::anyhow!("{}", status));
|
.prefix("rpmostree-rofiles-fuse")
|
||||||
|
.tempdir()?;
|
||||||
|
let status = std::process::Command::new("rofiles-fuse")
|
||||||
|
.arg("--copyup")
|
||||||
|
.arg(path)
|
||||||
|
.arg(tempdir.path())
|
||||||
|
.current_dir(format!("/proc/self/fd/{}", rootfs.as_raw_fd()))
|
||||||
|
.status()?;
|
||||||
|
if !status.success() {
|
||||||
|
return Err(anyhow::anyhow!("{}", status));
|
||||||
|
}
|
||||||
|
Ok(Self {
|
||||||
|
tempdir: Some(tempdir),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn path(&self) -> &Path {
|
||||||
|
self.tempdir.as_ref().unwrap().path()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for RoFilesMount {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let tempdir = if let Some(d) = self.tempdir.take() {
|
||||||
|
d
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
// We need to unmount before letting the tempdir cleanup run.
|
||||||
|
let success = Command::new("fusermount")
|
||||||
|
.arg("-u")
|
||||||
|
.arg(tempdir.path())
|
||||||
|
.status()
|
||||||
|
.map_err(anyhow::Error::new)
|
||||||
|
.and_then(|status| -> Result<()> {
|
||||||
|
if !status.success() {
|
||||||
|
Err(anyhow::anyhow!("{}", status))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.err()
|
||||||
|
.map(|e| {
|
||||||
|
systemd::journal::print(4, &format!("{}", e));
|
||||||
|
})
|
||||||
|
.is_none();
|
||||||
|
if !success {
|
||||||
|
// If fusermount fails, then we cannot remove it; just leak it.
|
||||||
|
let _ = tempdir.into_path();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(tempdir)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn child_wait_check(
|
fn child_wait_check(
|
||||||
@ -230,15 +248,15 @@ impl Bubblewrap {
|
|||||||
argv,
|
argv,
|
||||||
launcher,
|
launcher,
|
||||||
child_argv0: None,
|
child_argv0: None,
|
||||||
tempdirs: Vec::new(),
|
rofiles_mounts: Vec::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_rofiles(&mut self, path: &str) -> Result<()> {
|
fn setup_rofiles(&mut self, path: &str) -> Result<()> {
|
||||||
let tmpdir = setup_rofiles_in(&self.rootfs_fd, path)?;
|
let mnt = RoFilesMount::new(&self.rootfs_fd, path)?;
|
||||||
let tmpdir_path = tmpdir.path().to_str().expect("tempdir str");
|
let tmpdir_path = mnt.path().to_str().expect("tempdir str");
|
||||||
self.bind_readwrite(tmpdir_path, path);
|
self.bind_readwrite(tmpdir_path, path);
|
||||||
self.tempdirs.push(tmpdir);
|
self.rofiles_mounts.push(mnt);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user