Browse Source

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 <mountpoint>",
which is more consistent than using borg to mount and fusermount -u (or umount) to un-mount.
Thomas Waldmann 8 years ago
parent
commit
e17fe2b295

+ 20 - 0
borg/archiver.py

@@ -34,6 +34,7 @@ from .key import key_creator, RepoKey, PassphraseKey
 from .keymanager import KeyManager
 from .keymanager import KeyManager
 from .archive import backup_io, BackupOSError, Archive, ArchiveChecker, CHUNKER_PARAMS, is_special
 from .archive import backup_io, BackupOSError, Archive, ArchiveChecker, CHUNKER_PARAMS, is_special
 from .remote import RepositoryServer, RemoteRepository, cache_if_remote
 from .remote import RepositoryServer, RemoteRepository, cache_if_remote
+from .platform import umount
 
 
 has_lchflags = hasattr(os, 'lchflags')
 has_lchflags = hasattr(os, 'lchflags')
 
 
@@ -539,6 +540,10 @@ class Archiver:
                 self.exit_code = EXIT_ERROR
                 self.exit_code = EXIT_ERROR
         return self.exit_code
         return self.exit_code
 
 
+    def do_umount(self, args):
+        """un-mount the FUSE filesystem"""
+        return umount(args.mountpoint)
+
     @with_repository()
     @with_repository()
     def do_list(self, args, repository, manifest, key):
     def do_list(self, args, repository, manifest, key):
         """List archive or repository contents"""
         """List archive or repository contents"""
@@ -1476,6 +1481,21 @@ class Archiver:
         subparser.add_argument('-o', dest='options', type=str,
         subparser.add_argument('-o', dest='options', type=str,
                                help='Extra mount options')
                                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("""
         info_epilog = textwrap.dedent("""
         This command displays some detailed information about the specified archive.
         This command displays some detailed information about the specified archive.
 
 

+ 1 - 1
borg/helpers.py

@@ -88,7 +88,7 @@ def check_extension_modules():
         raise ExtensionModuleError
         raise ExtensionModuleError
     if crypto.API_VERSION != 2:
     if crypto.API_VERSION != 2:
         raise ExtensionModuleError
         raise ExtensionModuleError
-    if platform.API_VERSION != 2:
+    if platform.API_VERSION != 3:
         raise ExtensionModuleError
         raise ExtensionModuleError
 
 
 
 

+ 8 - 2
borg/platform.py

@@ -1,5 +1,6 @@
 import errno
 import errno
 import os
 import os
+import subprocess
 import sys
 import sys
 
 
 
 
@@ -17,14 +18,19 @@ def sync_dir(path):
         os.close(fd)
         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
 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
 elif sys.platform.startswith('freebsd'):  # pragma: freebsd only
     from .platform_freebsd import acl_get, acl_set, API_VERSION
     from .platform_freebsd import acl_get, acl_set, API_VERSION
 elif sys.platform == 'darwin':  # pragma: darwin only
 elif sys.platform == 'darwin':  # pragma: darwin only
     from .platform_darwin import acl_get, acl_set, API_VERSION
     from .platform_darwin import acl_get, acl_set, API_VERSION
 else:  # pragma: unknown platform only
 else:  # pragma: unknown platform only
-    API_VERSION = 2
+    API_VERSION = 3
 
 
     def acl_get(path, item, st, numeric_owner=False):
     def acl_get(path, item, st, numeric_owner=False):
         pass
         pass

+ 1 - 1
borg/platform_darwin.pyx

@@ -1,7 +1,7 @@
 import os
 import os
 from .helpers import user2uid, group2gid, safe_decode, safe_encode
 from .helpers import user2uid, group2gid, safe_decode, safe_encode
 
 
-API_VERSION = 2
+API_VERSION = 3
 
 
 cdef extern from "sys/acl.h":
 cdef extern from "sys/acl.h":
     ctypedef struct _acl_t:
     ctypedef struct _acl_t:

+ 1 - 1
borg/platform_freebsd.pyx

@@ -1,7 +1,7 @@
 import os
 import os
 from .helpers import posix_acl_use_stored_uid_gid, safe_encode, safe_decode
 from .helpers import posix_acl_use_stored_uid_gid, safe_encode, safe_decode
 
 
-API_VERSION = 2
+API_VERSION = 3
 
 
 cdef extern from "errno.h":
 cdef extern from "errno.h":
     int errno
     int errno

+ 6 - 1
borg/platform_linux.pyx

@@ -1,9 +1,10 @@
 import os
 import os
 import re
 import re
+import subprocess
 from stat import S_ISLNK
 from stat import S_ISLNK
 from .helpers import posix_acl_use_stored_uid_gid, user2uid, group2gid, safe_decode, safe_encode
 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":
 cdef extern from "sys/types.h":
     int ACL_TYPE_ACCESS
     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)
                 acl_set_file(p, ACL_TYPE_DEFAULT, default_acl)
         finally:
         finally:
             acl_free(default_acl)
             acl_free(default_acl)
+
+
+def umount(mountpoint):
+    return subprocess.call(['fusermount', '-u', mountpoint])

+ 2 - 5
borg/testsuite/__init__.py

@@ -9,6 +9,7 @@ import time
 import unittest
 import unittest
 from ..xattr import get_all
 from ..xattr import get_all
 from ..logger import setup_logging
 from ..logger import setup_logging
+from ..platform import umount
 
 
 try:
 try:
     import llfuse
     import llfuse
@@ -110,11 +111,7 @@ class BaseTestCase(unittest.TestCase):
         self.cmd(*args, fork=True)
         self.cmd(*args, fork=True)
         self.wait_for_mount(mountpoint)
         self.wait_for_mount(mountpoint)
         yield
         yield
-        if sys.platform.startswith('linux'):
-            cmd = 'fusermount -u %s' % mountpoint
-        else:
-            cmd = 'umount %s' % mountpoint
-        os.system(cmd)
+        umount(mountpoint)
         os.rmdir(mountpoint)
         os.rmdir(mountpoint)
         # Give the daemon some time to exit
         # Give the daemon some time to exit
         time.sleep(.2)
         time.sleep(.2)

+ 3 - 1
docs/usage.rst

@@ -545,6 +545,8 @@ Examples
 
 
 .. include:: usage/mount.rst.inc
 .. include:: usage/mount.rst.inc
 
 
+.. include:: usage/umount.rst.inc
+
 Examples
 Examples
 ~~~~~~~~
 ~~~~~~~~
 ::
 ::
@@ -552,7 +554,7 @@ Examples
     $ borg mount /path/to/repo::root-2016-02-15 /tmp/mymountpoint
     $ borg mount /path/to/repo::root-2016-02-15 /tmp/mymountpoint
     $ ls /tmp/mymountpoint
     $ ls /tmp/mymountpoint
     bin  boot  etc	home  lib  lib64  lost+found  media  mnt  opt  root  sbin  srv  tmp  usr  var
     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
 .. include:: usage/key_export.rst.inc

+ 40 - 0
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.