in xar/clean_xar_mounts/src/main.rs [559:658]
fn run() -> Result<()> {
let matches = App::new("Clean XAR Mounts")
.arg(
Arg::with_name("timeout")
.long("timeout")
.default_value("15")
.help("time, in minutes, after a xar was mounted to attempt to unmount it"),
)
.arg(
Arg::with_name("verbose")
.long("verbose")
.short("v")
.help("display detailed output"),
)
.arg(
Arg::with_name("dryrun")
.long("dry-run")
.help("display detailed output"),
)
.get_matches();
let timeout = value_t!(matches, "timeout", u32)?;
let dryrun = matches.is_present("dryrun");
let level = if matches.is_present("verbose") {
slog::Level::Debug
} else {
slog::Level::Info
};
let root_log = setup_logger(level);
let orig_ns_fd = nix::fcntl::open(
"/proc/self/ns/mnt",
nix::fcntl::OFlag::O_RDONLY,
nix::sys::stat::Mode::from_bits(0700).unwrap(),
)?;
let mount_namespaces = get_mount_namespaces()?;
info!(
root_log,
"Considering {} namespaces",
mount_namespaces.len()
);
for nsinfo in mount_namespaces {
info!(
root_log,
"Entering namespace {:?}...", nsinfo.namespace_path
);
// Enter the new namespace and then check /proc/mounts for the
// now-visible mounts.
let mounts = get_mounts(&nsinfo, &root_log);
if mounts.is_err() {
info!(
root_log,
"Unable to read mounts in {:?}", nsinfo.namespace_path
);
continue;
}
let _ns_saver = NamespaceSaver::new(orig_ns_fd, &nsinfo.namespace_path);
if _ns_saver.is_err() && nix::unistd::geteuid().is_root() {
info!(
root_log,
"Unable to enter namespace {:?}, skipping", nsinfo.namespace_path
);
continue;
}
for mount in mounts.unwrap() {
let result = should_unmount(&root_log, &mount, timeout)?;
if result.should_unmount {
// TODO: consider forking and chrooting into the
// process' chroot rather than constructing a path
// from outside. It may not always be true that we
// can append paths to find the actual mount point to
// unmount.
let mut target = mount.chroot.clone();
target.push(&mount.mountpoint[1..]); // strip leading slash
info!(
root_log,
"unmounting {:?}:{:?}", nsinfo.namespace_path, target
);
if !dryrun {
if nix::unistd::geteuid().is_root() {
if let Err(e) = nix::mount::umount(&target) {
info!(root_log, "Failed to unmount {:?}: {}", target, e);
}
} else {
let output = Command::new("fusermount").arg("-u").arg(&target).output()?;
if !output.status.success() {
info!(
root_log,
"fusermount -u failed to unmount {:?}: {}",
target,
String::from_utf8_lossy(&output.stderr).trim()
);
}
}
}
}
}
}
Ok(())
}