mirror of
https://github.com/facebook/sapling.git
synced 2024-10-08 07:49:11 +03:00
1b28a95166
Summary: Eden doctor checks to that configured bind mounts are present for each Eden repository. It reports errors for missing directories and the device type is incorrect. The device type must differ from the device type of the repository's Eden path. Eden doctor can fix (by creating) missing bind point directories and then calling the eden thrift server to mount. Reviewed By: chadaustin Differential Revision: D8244287 fbshipit-source-id: c78e5ecce63002761a266c5925f2d6618e648e4a
89 lines
2.9 KiB
Python
89 lines
2.9 KiB
Python
#!/usr/bin/env python3
|
|
# Copyright (c) 2018-present, Facebook, Inc.
|
|
# All rights reserved.
|
|
#
|
|
# This source code is licensed under the BSD-style license found in the
|
|
# LICENSE file in the root directory of this source tree. An additional grant
|
|
# of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
import abc
|
|
import logging
|
|
import os
|
|
import subprocess
|
|
from typing import List, NamedTuple, Union
|
|
|
|
|
|
log = logging.getLogger("eden.cli.mtab")
|
|
|
|
|
|
MountInfo = NamedTuple(
|
|
"MountInfo", [("device", bytes), ("mount_point", bytes), ("vfstype", bytes)]
|
|
)
|
|
|
|
|
|
MTStat = NamedTuple("MTStat", [("st_uid", int), ("st_dev", int), ("st_mode", int)])
|
|
|
|
|
|
class MountTable(abc.ABC):
|
|
@abc.abstractmethod
|
|
def read(self) -> List[MountInfo]:
|
|
"Returns the list of system mounts."
|
|
|
|
@abc.abstractmethod
|
|
def unmount_lazy(self, mount_point: bytes) -> bool:
|
|
"Corresponds to `umount -l` on Linux."
|
|
|
|
@abc.abstractmethod
|
|
def unmount_force(self, mount_point: bytes) -> bool:
|
|
"Corresponds to `umount -f` on Linux."
|
|
|
|
@abc.abstractmethod
|
|
def lstat(self, path: Union[bytes, str]) -> MTStat:
|
|
"Returns a subset of the results of os.lstat."
|
|
|
|
@abc.abstractmethod
|
|
def create_bind_mount(self, source_path, dest_path) -> bool:
|
|
"Creates a bind mount from source_path to dest_path."
|
|
|
|
|
|
def parse_mtab(contents: bytes) -> List[MountInfo]:
|
|
mounts = []
|
|
for line in contents.splitlines():
|
|
# columns split by space or tab per man page
|
|
entries = line.split()
|
|
if len(entries) != 6:
|
|
log.warning(f"mount table line has {len(entries)} entries instead of 6")
|
|
continue
|
|
device, mount_point, vfstype, opts, freq, passno = entries
|
|
mounts.append(
|
|
MountInfo(device=device, mount_point=mount_point, vfstype=vfstype)
|
|
)
|
|
return mounts
|
|
|
|
|
|
class LinuxMountTable(MountTable):
|
|
def read(self) -> List[MountInfo]:
|
|
# What's the most portable mtab path? I've seen both /etc/mtab and
|
|
# /proc/self/mounts. CentOS 6 in particular does not symlink /etc/mtab
|
|
# to /proc/self/mounts so go directly to /proc/self/mounts.
|
|
# This code could eventually fall back to /proc/mounts and /etc/mtab.
|
|
with open("/proc/self/mounts", "rb") as f:
|
|
return parse_mtab(f.read())
|
|
|
|
def unmount_lazy(self, mount_point: bytes) -> bool:
|
|
# MNT_DETACH
|
|
return 0 == subprocess.call(["sudo", "umount", "-l", mount_point])
|
|
|
|
def unmount_force(self, mount_point: bytes) -> bool:
|
|
# MNT_FORCE
|
|
return 0 == subprocess.call(["sudo", "umount", "-f", mount_point])
|
|
|
|
def lstat(self, path: Union[bytes, str]) -> MTStat:
|
|
st = os.lstat(path)
|
|
return MTStat(st_uid=st.st_uid, st_dev=st.st_dev, st_mode=st.st_mode)
|
|
|
|
def create_bind_mount(self, source_path, dest_path) -> bool:
|
|
return 0 == subprocess.check_call(
|
|
["sudo", "mount", "-o", "bind", source_path, dest_path]
|
|
)
|