From e17fe2b295d1d1e97a1e553413759890c7b9ace4 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Thu, 17 Nov 2016 20:16:28 +0100 Subject: [PATCH] borg umount, fixes #1855 this refactors umount code we already used for the testsuite into the platform module's namespace. also, it exposes that functionality via the cli api, so users can use it via "borg umount ", which is more consistent than using borg to mount and fusermount -u (or umount) to un-mount. --- borg/archiver.py | 20 +++++++++++++++++++ borg/helpers.py | 2 +- borg/platform.py | 10 ++++++++-- borg/platform_darwin.pyx | 2 +- borg/platform_freebsd.pyx | 2 +- borg/platform_linux.pyx | 7 ++++++- borg/testsuite/__init__.py | 7 ++----- docs/usage.rst | 4 +++- docs/usage/umount.rst.inc | 40 ++++++++++++++++++++++++++++++++++++++ 9 files changed, 82 insertions(+), 12 deletions(-) create mode 100644 docs/usage/umount.rst.inc diff --git a/borg/archiver.py b/borg/archiver.py index 07086709b..ecc44be76 100644 --- a/borg/archiver.py +++ b/borg/archiver.py @@ -34,6 +34,7 @@ from .keymanager import KeyManager from .archive import backup_io, BackupOSError, Archive, ArchiveChecker, CHUNKER_PARAMS, is_special from .remote import RepositoryServer, RemoteRepository, cache_if_remote +from .platform import umount has_lchflags = hasattr(os, 'lchflags') @@ -539,6 +540,10 @@ def do_mount(self, args, repository, manifest, key): self.exit_code = EXIT_ERROR return self.exit_code + def do_umount(self, args): + """un-mount the FUSE filesystem""" + return umount(args.mountpoint) + @with_repository() def do_list(self, args, repository, manifest, key): """List archive or repository contents""" @@ -1476,6 +1481,21 @@ def build_parser(self, args=None, prog=None): subparser.add_argument('-o', dest='options', type=str, help='Extra mount options') + umount_epilog = textwrap.dedent(""" + This command un-mounts a FUSE filesystem that was mounted with ``borg mount``. + + This is a convenience wrapper that just calls the platform-specific shell + command - usually this is either umount or fusermount -u. + """) + subparser = subparsers.add_parser('umount', parents=[common_parser], + description=self.do_umount.__doc__, + epilog=umount_epilog, + formatter_class=argparse.RawDescriptionHelpFormatter, + help='umount repository') + subparser.set_defaults(func=self.do_umount) + subparser.add_argument('mountpoint', metavar='MOUNTPOINT', type=str, + help='mountpoint of the filesystem to umount') + info_epilog = textwrap.dedent(""" This command displays some detailed information about the specified archive. diff --git a/borg/helpers.py b/borg/helpers.py index a4469c990..72129f08e 100644 --- a/borg/helpers.py +++ b/borg/helpers.py @@ -88,7 +88,7 @@ def check_extension_modules(): raise ExtensionModuleError if crypto.API_VERSION != 2: raise ExtensionModuleError - if platform.API_VERSION != 2: + if platform.API_VERSION != 3: raise ExtensionModuleError diff --git a/borg/platform.py b/borg/platform.py index e1cffd87a..be7a2bcd1 100644 --- a/borg/platform.py +++ b/borg/platform.py @@ -1,5 +1,6 @@ import errno import os +import subprocess import sys @@ -17,14 +18,19 @@ def sync_dir(path): os.close(fd) +# most POSIX platforms (but not Linux), see also borg 1.1 platform.base +def umount(mountpoint): + return subprocess.call(['umount', mountpoint]) + + if sys.platform.startswith('linux'): # pragma: linux only - from .platform_linux import acl_get, acl_set, API_VERSION + from .platform_linux import acl_get, acl_set, umount, API_VERSION elif sys.platform.startswith('freebsd'): # pragma: freebsd only from .platform_freebsd import acl_get, acl_set, API_VERSION elif sys.platform == 'darwin': # pragma: darwin only from .platform_darwin import acl_get, acl_set, API_VERSION else: # pragma: unknown platform only - API_VERSION = 2 + API_VERSION = 3 def acl_get(path, item, st, numeric_owner=False): pass diff --git a/borg/platform_darwin.pyx b/borg/platform_darwin.pyx index edb41f715..4dc25b83a 100644 --- a/borg/platform_darwin.pyx +++ b/borg/platform_darwin.pyx @@ -1,7 +1,7 @@ import os from .helpers import user2uid, group2gid, safe_decode, safe_encode -API_VERSION = 2 +API_VERSION = 3 cdef extern from "sys/acl.h": ctypedef struct _acl_t: diff --git a/borg/platform_freebsd.pyx b/borg/platform_freebsd.pyx index 27d636263..ae69af68a 100644 --- a/borg/platform_freebsd.pyx +++ b/borg/platform_freebsd.pyx @@ -1,7 +1,7 @@ import os from .helpers import posix_acl_use_stored_uid_gid, safe_encode, safe_decode -API_VERSION = 2 +API_VERSION = 3 cdef extern from "errno.h": int errno diff --git a/borg/platform_linux.pyx b/borg/platform_linux.pyx index f9ed42415..0185268c1 100644 --- a/borg/platform_linux.pyx +++ b/borg/platform_linux.pyx @@ -1,9 +1,10 @@ import os import re +import subprocess from stat import S_ISLNK from .helpers import posix_acl_use_stored_uid_gid, user2uid, group2gid, safe_decode, safe_encode -API_VERSION = 2 +API_VERSION = 3 cdef extern from "sys/types.h": int ACL_TYPE_ACCESS @@ -141,3 +142,7 @@ def acl_set(path, item, numeric_owner=False): acl_set_file(p, ACL_TYPE_DEFAULT, default_acl) finally: acl_free(default_acl) + + +def umount(mountpoint): + return subprocess.call(['fusermount', '-u', mountpoint]) diff --git a/borg/testsuite/__init__.py b/borg/testsuite/__init__.py index 42b935d1e..8d757d2bd 100644 --- a/borg/testsuite/__init__.py +++ b/borg/testsuite/__init__.py @@ -9,6 +9,7 @@ import unittest from ..xattr import get_all from ..logger import setup_logging +from ..platform import umount try: import llfuse @@ -110,11 +111,7 @@ def fuse_mount(self, location, mountpoint, *options): self.cmd(*args, fork=True) self.wait_for_mount(mountpoint) yield - if sys.platform.startswith('linux'): - cmd = 'fusermount -u %s' % mountpoint - else: - cmd = 'umount %s' % mountpoint - os.system(cmd) + umount(mountpoint) os.rmdir(mountpoint) # Give the daemon some time to exit time.sleep(.2) diff --git a/docs/usage.rst b/docs/usage.rst index 8743f6ac0..2a3538b22 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -545,6 +545,8 @@ Examples .. include:: usage/mount.rst.inc +.. include:: usage/umount.rst.inc + Examples ~~~~~~~~ :: @@ -552,7 +554,7 @@ Examples $ borg mount /path/to/repo::root-2016-02-15 /tmp/mymountpoint $ ls /tmp/mymountpoint bin boot etc home lib lib64 lost+found media mnt opt root sbin srv tmp usr var - $ fusermount -u /tmp/mymountpoint + $ borg umount /tmp/mymountpoint .. include:: usage/key_export.rst.inc diff --git a/docs/usage/umount.rst.inc b/docs/usage/umount.rst.inc new file mode 100644 index 000000000..febacda06 --- /dev/null +++ b/docs/usage/umount.rst.inc @@ -0,0 +1,40 @@ +.. IMPORTANT: this file is auto-generated from borg's built-in help, do not edit! + +.. _borg_umount: + +borg umount +----------- +:: + + usage: borg umount [-h] [--critical] [--error] [--warning] [--info] [--debug] + [--lock-wait N] [--show-rc] [--no-files-cache] [--umask M] + [--remote-path PATH] + MOUNTPOINT + + un-mount the FUSE filesystem + + positional arguments: + MOUNTPOINT mountpoint of the filesystem to umount + + optional arguments: + -h, --help show this help message and exit + --critical work on log level CRITICAL + --error work on log level ERROR + --warning work on log level WARNING (default) + --info, -v, --verbose + work on log level INFO + --debug work on log level DEBUG + --lock-wait N wait for the lock, but max. N seconds (default: 1). + --show-rc show/log the return code (rc) + --no-files-cache do not load/update the file metadata cache used to + detect unchanged files + --umask M set umask to M (local and remote, default: 0077) + --remote-path PATH set remote path to executable (default: "borg") + +Description +~~~~~~~~~~~ + +This command un-mounts a FUSE filesystem that was mounted with ``borg mount``. + +This is a convenience wrapper that just calls the platform-specific shell +command - usually this is either umount or fusermount -u.