/
usr
/
lib
/
python2.7
/
site-packages
/
clcommon
/
Upload Filee
HOME
#!/usr/bin/python import os import subprocess CAGEFS_MP_FILENAME = '/etc/cagefs/cagefs.mp' CAGEFSCTL_TOOL = '/usr/sbin/cagefsctl' class CagefsMpConflict(Exception): def __init__(self, new_item, existing_item): self._msg = "Conflict in adding '%s' to %s because of pre-existing alternative specification: '%s'" \ % (new_item, CAGEFS_MP_FILENAME, existing_item) def __str__(self): return self._msg class CagefsMpItem(object): _PREFIX_LIST = '@!%'; _PREFIX_MOUNT_RW = ''; _PREFIX_MOUNT_RO = '!'; def __init__(self, arg): """Constructor :param arg: Is either path to add to cagefs.mp or a raw line is read from cagefs.mp :param prefix: The same as adding prefix '!' to arg before passing it to ctor""" if arg[:1] == '#': # is a comment? then init as dummy self._path_spec = None elif arg.strip() == '': # init as dummy for empty lines self._path_spec = None else: self._path_spec = arg def mode(self, mode): "Specify mode as in fluent constructor" if self.prefix() == '@' and not mode is None: self._path_spec = "%s,%03o" % (self._path_spec, mode) return self def __str__(self): return self._path_spec def _add_slash(path): if path == '': return '/' if (path[-1] != '/'): return path + '/' return path _add_slash = staticmethod(_add_slash) def pre_exist_in(self, another): adopted = CagefsMpItem._adopt(another) # overkill: just to keep strictly to comparing NULL objects principle if self.is_dummy() or adopted.is_dummy(): return False this_path = CagefsMpItem._add_slash(self.path()) test_preexist_in_path = CagefsMpItem._add_slash(adopted.path()) return this_path.startswith(test_preexist_in_path) def is_compatible_by_prefix_with(self, existing): adopted = CagefsMpItem._adopt(existing) # overkill: just to keep strictly to comparing NULL objects principle if self.is_dummy() or adopted.is_dummy(): return False if self.prefix() == adopted.prefix(): return True prefix_compatibility_map = { CagefsMpItem._PREFIX_MOUNT_RW : [CagefsMpItem._PREFIX_MOUNT_RO] } null_options = [] return self.prefix() in prefix_compatibility_map.get(adopted.prefix(), null_options) def is_dummy(self): return self._path_spec is None def _adopt(x): if isinstance(x, CagefsMpItem): return x else: return CagefsMpItem(x) _adopt = staticmethod(_adopt) def _cut_off_mode(path_spec): """Cut off mode from path spec like @/var/run/screen,777 Only one comma per path spec is allowed ;-)""" return path_spec.split(',')[0] _cut_off_mode = staticmethod(_cut_off_mode) def _cut_off_prefix(path_spec): return path_spec.lstrip(CagefsMpItem._PREFIX_LIST) _cut_off_prefix = staticmethod(_cut_off_prefix) def path(self): return CagefsMpItem._cut_off_prefix(CagefsMpItem._cut_off_mode(self._path_spec)) def prefix(self): if self._path_spec != self.path(): return self._path_spec[0] else: return '' def is_cagefs_present(): return os.path.exists(CAGEFS_MP_FILENAME) and \ os.path.exists(CAGEFSCTL_TOOL) def _mk_mount_dir_setup_perm(path, mode=0755, owner_id=None, group_id=None): if not os.path.isdir(path): os.mkdir(path) if not mode is None: os.chmod(path, mode) if (not owner_id is None) and (not group_id is None): os.chown(path, owner_id, group_id) def setup_mount_dir_cagefs(path, added_by, mode=0755, owner_id=None, group_id=None, prefix=''): '''Add mount point to /etc/cagefs/cagefs.mp :param path: Directory path to be added in cagefs.mp and mounted from within setup_mount_dir_cagefs(). If this directory does not exist, then it is created. :param added_by: package or component, mount dir relates to, or whatever will stay in cagefs.mp with "# added by..." comment :param mode: If is not None: Regardless of whether directory exists or not prior this call, it's permissions will be set to mode. :param owner_id: If group_id is also provided along: Regardless of whether directory exists or not prior this call, it's owner id will be set to. :param group_id: If owner_id is also provided along: Regardless of whether directory exists or not prior this call, it's group id will be set to. :param prefix: Mount point prefix. Default is mount as RW. Pass '!' to add read-only mount point. Refer CageFS section at http://docs.cloudlinux.com/ for more options. :returns: None Propagates native EnvironmentError if no CageFS installed or something else goes wrong. Raises CagefsMpConflict if path is already specified in cagefs.mp, but in a way which is opposite to mount_as_readonly param. ''' _mk_mount_dir_setup_perm(path, mode, owner_id, owner_id) subprocess.call([CAGEFSCTL_TOOL, "--check-mp"]) # ^^ # Hereafter we will not care if there was # 'no newline at the end of file' cagefs_mp = open(CAGEFS_MP_FILENAME, "r+") try: new_item = CagefsMpItem(prefix + path).mode(mode) trim_nl_iter = (file_line.rstrip() for file_line in cagefs_mp) pre_exist_option = filter(lambda x: new_item.pre_exist_in(x), trim_nl_iter) if not pre_exist_option: cagefs_mp.seek(0, 2) # 2: seek to the end of file # no newline is allowed added_by = added_by.replace("\n", " ") print >>cagefs_mp, "# next line is added by", added_by print >>cagefs_mp, new_item cagefs_mp.close() subprocess.call([CAGEFSCTL_TOOL, "--remount-all"]) elif not new_item.is_compatible_by_prefix_with(pre_exist_option[-1]): raise CagefsMpConflict(new_item, pre_exist_option[-1]) finally: cagefs_mp.close()