in xar/clean_xar_mounts/src/main.rs [463:549]
fn should_unmount(
logger: &slog::Logger,
mount: &MountedFilesystem,
timeout: u32,
) -> Result<ShouldUnmountResult> {
// Only consider certain mount types.
match mount.fstype.as_str() {
"fuse.squashfuse" | "fuse.squashfuse_ll" | "osxfusefs" | "osxfuse" | "macfuse" => {}
_ => return Ok(ShouldUnmountResult::new(false, None)),
}
info!(
logger,
"Considering {} ({})", mount.mountpoint, mount.fstype
);
let lockfiles = get_lockfile_path(&logger, &mount);
// Sometimes mtab gets out of sync with reality; all XARs should
// contain files, so let's confirm they actually do, and if not,
// still consider them for unmounting.
let mut chrooted_mountpoint = mount.chroot.clone();
chrooted_mountpoint.push(&mount.mountpoint[1..]);
if let Ok(it) = fs::read_dir(&chrooted_mountpoint) {
if it.take_while(|r| r.is_ok()).next().is_none() {
debug!(
logger,
"Unmounting empty directory: {:?}", chrooted_mountpoint
);
return Ok(ShouldUnmountResult::new(true, None));
}
} else {
info!(
logger,
"Unable to read dir {:?}, skipping emptiness check", chrooted_mountpoint
);
}
debug!(logger, "lockfile candidates: {:?}", lockfiles);
// Find the lockfile; use its mtime to determine if the mount
// point is old enough to try to reap.
let lock_opt = lockfiles
.iter()
.map(|ref filename| {
nix::fcntl::open(
filename.as_path().as_os_str(),
nix::fcntl::OFlag::O_RDWR | nix::fcntl::OFlag::O_CLOEXEC,
nix::sys::stat::Mode::from_bits(0700).unwrap(),
)
})
.filter_map(|open_result| open_result.ok())
.next();
let lock_fd = match lock_opt {
Some(fd) => fd,
None => {
debug!(
logger,
"Unable to find lock file for {}, skipping...", mount.mountpoint
);
return Ok(ShouldUnmountResult::new(false, None));
}
};
// lock the file before checking timestamp to protect against a
// race with XarexecFuse.
if !flock_with_timeout(lock_fd, 60) {
info!(
logger,
"Unable to flock {:?}, skipping...", chrooted_mountpoint
);
return Ok(ShouldUnmountResult::new(false, lock_opt));
}
let stat = nix::sys::stat::fstat(lock_fd)?;
let epoch_now = SystemTime::now().duration_since(UNIX_EPOCH)?;
let age = epoch_now.as_secs_f64()
- Duration::new(stat.st_mtime as u64, stat.st_mtime_nsec as u32).as_secs_f64();
let timeout = timeout as f64 * 60.0;
if age <= timeout {
info!(
logger,
"Skipping unmount of {}, too recent ({:.2}s)", mount.mountpoint, age
);
return Ok(ShouldUnmountResult::new(false, lock_opt));
}
Ok(ShouldUnmountResult::new(true, lock_opt))
}