Пример #1
0
def main(argv=None):
    dirs = appdirs.AppDirs(appname="Stud.IP-Fuse", appauthor=False)  # disable author/company folder on windows
    os.makedirs(dirs.user_data_dir, exist_ok=True)  # must exist for log files
    os.makedirs(dirs.user_config_dir, exist_ok=True)  # must exist for oauth token storage
    configure_logging(dirs)
    args, fuse_args = parse_args(dirs, argv)
    os.makedirs(args.cache_dir, exist_ok=True)
    try:
        if not args.debug_logging:
            logging.root.setLevel(logging.INFO)
        if not args.debug_aio:
            logging.getLogger("asyncio").setLevel(logging.WARNING)

        log_status("STARTING", args=args, level=logging.DEBUG)
        log.info("Starting %s" % get_environment())

        if args.debug_fuse:
            from studip_fuse.studipfs.fuse_ops import log_ops
            log_ops.setLevel(logging.DEBUG)
        fuse_ops = FUSEView(log_args=args, loop_setup_fn=aioimpl_asyncio.setup_loop(args=args))

        if args.login_method == "oauth":
            login_oauth_args(args)
        else:
            if args.pwfile == "-":
                from getpass import getpass
                password = getpass()
            else:
                try:
                    with open(args.pwfile, "rt") as f:
                        password = f.read().rstrip('\n')
                except FileNotFoundError as e:
                    log.warning("%s. Either specify a file from which your Stud.IP password can be read "
                                "or use `--pwfile -` to enter it using a prompt in the shell." % e)
                    return
            args.get_password = lambda: password  # wrap in lambda to prevent printing

        log.info("Going to mount at %s (uid=%s, gid=%s, pid=%s, python pid=%s)", os.path.abspath(args.mount),
                 *fuse_get_context(), os.getpid())
        try:
            # this calls fork if args.foreground == False (and breaks running asyncio loops due to https://bugs.python.org/issue21998)
            # XXX on windows args.mount may not exist, on Linux it must exist
            FUSE(fuse_ops, args.mount, debug=fuse_args.pop("debug_fuse"), **fuse_args)
        except RuntimeError as e:
            if more_itertools.first(e.args, None) in FUSE_ERROR_CODES:
                msg = FUSE_ERROR_CODES[e.args[0]]
                if e.args[0] == 1:
                    msg += ". Please check whether the mountpoint you specified is an empty directory or another instance of studip-fuse is using it"
                msg += ". Please check stderr for details."
                raise RuntimeError(msg) from e
            else:
                raise
    except SystemExit:
        pass
    except:
        log.error("main() function quit exceptionally", exc_info=True)
    finally:
        log_status("TERMINATED", args=args, level=logging.DEBUG)
        log.debug("Program terminated")
Пример #2
0
def log_status(status, args=None, suffix=tuple(), level=logging.INFO):
    data = (status, *fuse_get_context(), os.getpid(),
            args.user if args else "?", args.mount if args else "?") + suffix
    if status_queue:
        status_queue.put(data)
    logging.getLogger("studip_fuse.status").log(level,
                                                " ".join(["%s"] * len(data)),
                                                *data)
Пример #3
0
	def symlink(self, target_path_, source_path):

		target_rel_path = self._rel_path(target_path_)

		os.symlink(source_path, target_rel_path, dir_fd = self._root_path_fd)

		uid, gid, pid = fuse_get_context()
		os.chown(target_rel_path, uid, gid, dir_fd = self._root_path_fd, follow_symlinks = False)
Пример #4
0
	def mkdir(self, path, mode):

		rel_path = self._rel_path(path)

		os.mkdir(rel_path, mode, dir_fd = self._root_path_fd)

		uid, gid, pid = fuse_get_context()

		os.chown(rel_path, uid, gid, dir_fd = self._root_path_fd, follow_symlinks = False)
		os.chmod(rel_path, mode, dir_fd = self._root_path_fd) # follow_symlinks = False
Пример #5
0
    def destroy(self, path):
        log_status("STOPPING", args=self.log_args)
        log.info("Unmounting from %s (uid=%s, gid=%s, pid=%s, python pid=%s)",
                 path, *fuse_get_context(), os.getpid())

        if self.loop_future:
            self.loop_future.cancel()
        if self.loop_stop_fn:
            self.loop_stop_fn()
        if self.loop_thread:
            join_thread(self.loop_thread)

        log.info("Unmounting complete")
Пример #6
0
	def mknod(self, path, mode, dev):

		rel_path = self._rel_path(path)

		if stat.S_ISREG(mode):
			res = os.open(
				rel_path, os.O_CREAT | os.O_EXCL | os.O_WRONLY, mode,
				dir_fd = self._root_path_fd
				) # TODO broken, applies umask to mode no matter what ...
			if res >= 0:
				os.close(res)
		elif stat.S_ISFIFO(mode):
			os.mkfifo(rel_path, mode, dir_fd = self._root_path_fd)
		else:
			os.mknod(rel_path, mode, dev, dir_fd = self._root_path_fd)

		uid, gid, pid = fuse_get_context()
		os.chown(rel_path, uid, gid, dir_fd = self._root_path_fd, follow_symlinks = False)
		os.chmod(rel_path, mode, dir_fd = self._root_path_fd) # follow_symlinks = False
Пример #7
0
    def init(self, path):
        log_status("INITIALIZING", args=self.log_args)
        log.debug("Mounting at %s (uid=%s, gid=%s, pid=%s, python pid=%s)",
                  path, *fuse_get_context(), os.getpid())

        self.loop_future = concurrent.futures.Future()
        self.loop_thread = Thread(target=self.loop_setup_fn,
                                  args=(self.loop_future, ),
                                  name="aio event loop",
                                  daemon=True)
        self.loop_thread.start()

        log.debug(
            "Event loop thread started, waiting for initialization to complete"
        )
        self.loop_stop_fn, self.loop_run_fn, self.root_rp = self.loop_future.result(
        )

        log_status("READY", args=self.log_args)
        log.info("Mounting complete")
Пример #8
0
def _log_event_(self, func, func_arg_names, func_arg_abspath,
                func_arg_defaults, func_args, func_kwargs, format_pattern,
                ret_status, ret_value):

    if self._log_only_modify_operations:
        if func.__name__ not in ('chmod', 'chown', 'link', 'mkdir', 'mknod',
                                 'rename', 'rmdir', 'symlink', 'truncate',
                                 'unlink', 'utimens', 'write'):
            return

    uid, gid, pid = fuse_get_context()

    p_cmdname = ''
    if self._log_printprocessname or self._log_json:
        p_cmdname = _get_process_cmdline_(pid).strip()

    log_dict = {
        'proc_cmd': p_cmdname,
        'proc_uid': uid,
        'proc_uid_name': _get_user_name_from_uid_(uid),
        'proc_gid': gid,
        'proc_gid_name': _get_group_name_from_gid_(gid),
        'proc_pid': pid,
        'action': func.__name__,
        'status': ret_status,
    }

    arg_dict = {
        arg_name: arg
        for arg_name, arg in zip(func_arg_names, func_args)
    }
    arg_dict.update({
        arg_name: func_kwargs.get(arg_name, func_arg_defaults[arg_name])
        for arg_name in func_arg_names[len(func_args):]
    })

    try:
        arg_dict['uid_name'] = _get_user_name_from_uid_(arg_dict['uid'])
    except KeyError:
        pass
    try:
        arg_dict['gid_name'] = _get_group_name_from_gid_(arg_dict['gid'])
    except KeyError:
        pass
    try:
        arg_dict['fip'] = _get_fh_from_fip_(arg_dict['fip'])
    except KeyError:
        pass
    for k in arg_dict.keys():
        if k.endswith('path'):
            arg_dict[k] = self._full_path(arg_dict[k])
    try:
        arg_dict['buf_len'] = len(arg_dict['buf'])
        arg_dict['buf'] = _encode_buffer_(
            arg_dict['buf']) if self._log_buffers else ''
    except KeyError:
        pass

    log_dict.update({'param_%s' % k: v for k, v in arg_dict.items()})

    if log_dict['status']:  # SUCCESS
        if any((ret_value is None, isinstance(ret_value,
                                              int), isinstance(ret_value, str),
                isinstance(ret_value, dict), isinstance(ret_value, list))):
            log_dict['return'] = ret_value
        elif isinstance(ret_value, bytes):
            log_dict['return_len'] = len(ret_value)
            log_dict['return'] = _encode_buffer_(
                ret_value) if self._log_buffers else ''

    else:  # FAILURE
        log_dict.update({
            'return': None,
            'return_exception': ret_value[0],
            'return_errno': ret_value[1],
            'return_errorcode': errno.errorcode[ret_value[1]]
        })

    if not self._lib_mode:
        if not self._log_filter.match(log_dict):
            return

    if self._log_json and not self._lib_mode:
        self._logger.info(json.dumps(log_dict, sort_keys=True)[1:-1])
        return
    elif self._lib_mode:
        log_dict['time'] = time.time_ns()
        send(log_dict)
        return

    log_out = ' '.join([
        '%s %s' % (func.__name__, format_pattern.format(**log_dict)),
        '{%s}' % STATUS_DICT[ret_status],
        '[ pid = %d %suid = %d ]' %
        (pid, ('%s ' % p_cmdname) if len(p_cmdname) > 0 else '', uid),
        '( r = %s )' %
        str(log_dict['return']) if log_dict['status'] else '( %s = %d )' %
        ret_value
    ])

    self._logger.info(log_out)