in xar/deprecated/mount_xar.py [0:0]
def should_unmount(devname, mountpath, fstype, timeout):
if fstype not in (
"fuse.squashfuse",
"fuse.squashfuse_ll",
"osxfusefs",
"osxfuse",
"macfuse",
):
return (False, None)
logging.debug("Considering %s (%s)..." % (mountpath, fstype))
# Only consider certain prefixes, and strip them off into
# mount_suffix
allowed_prefixes = ("/mnt/xarfuse/", "/dev/shm/")
mount_suffix = None
for prefix in allowed_prefixes:
if mountpath.startswith(prefix):
mount_suffix = mountpath[len(prefix) :]
logging.debug("Mount suffix: %s" % mount_suffix)
break
if mount_suffix is None:
logger.info("Skipping unmount of %s, incorrect prefix" % mountpath)
return (False, None)
# Mounts are of the form /prefix/uid-N/UUID-ns-NSID/... -- we need to
# extract the UUID portion.
uuid_regex = re.compile(r"uid-\d+/([^/]+)-ns-([^-/]+)$")
match = uuid_regex.match(mount_suffix)
if not match:
logger.info("Skipping unmount of %s, unexpected path strucure" % mountpath)
return (False, None)
# Sometimes mtab gets out of sync with reality; all XARs should
# contain files, so let's confirm they actually do, and if not,
# consider them worth unmounting.
try:
if len(os.listdir(mountpath)) == 0:
logger.info("Unmounting empty directory %s", mountpath)
return (True, None)
except OSError as oe:
logger.info("Unable to listdir %s, skipping emptiness check", mountpath)
# Look for the lockfile for this uuid.
stat_target = None
if match:
stat_target = os.path.join(
os.path.dirname(mountpath), "lockfile." + match.group(1)
)
# Legacy case from when lockfiles lacked the uuid portion.
if not os.path.exists(stat_target):
stat_target = os.path.join(os.path.dirname(mountpath), "lockfile")
logging.debug("Using stat target %s" % stat_target)
# We have a lockfile; use its mtime to determine if the mount
# point is old enough to try to reap.
lock_fd = None
try:
O_CLOEXEC = 524288 # not in os prior to 3.3
lock_fd = os.open(stat_target, os.O_RDWR | O_CLOEXEC)
# lock the file before checking timestamp to protect against a
# race with XarexecFuse.
if not flock_with_timeout(lock_fd, fcntl.LOCK_EX, 60):
logging.info("Unable to lock %s, skipping..." % stat_target)
os.close(lock_fd)
return (False, None)
st = os.fstat(lock_fd)
except OSError as oe:
# Chances are the open itself failed. In this case, we fail
# open and unmount.
if lock_fd is not None:
os.close(lock_fd)
if oe.errno == errno.ENOENT:
logger.info("Unable to open %s, assuming unmount...", stat_target)
return (True, None)
raise
if time.time() - st.st_mtime <= timeout * 60:
logger.info(
"Skipping unmount of %s, too recent (%.2fs)"
% (mountpath, time.time() - st.st_mtime)
)
os.close(lock_fd)
return (False, None)
# TODO(chip): one day we will need to support permanent mounts
# somehow (for fbcode runtime, etc). Hueristic TBD.
return (True, lock_fd)