Repository: borgbackup/borg

Issue:
add a mount.borg wrapper
it just needs to do:

```
#!/bin/bash
borg mount "$@"
```

it can be used in fstab like:

```
mount.borg#repo_or_archive mountpoint fuse defaults noauto 0 0
```



Discussion:
Create `borgmount`-wrapper:
Add symlink to fuse:
`ln -s /sbin/mount.fuse /sbin/mount.fuse.borgmount`

Now fstab line works without '#'-program
`repo_or_archive mountpoint fuse.borgmount defaults noauto 0 0`

If we add mount.borg here https://github.com/borgbackup/borg/blob/master/setup.py#L262 we can have it automatically installed in a directory in the PATH within the usual installation process. Also we save having that extra directory/file.

Should this:

```
# archiver.py
def main_mount():  # pragma: no cover
    sys.argv.insert(1, "mount")
    main()

# somewhere down in setup.py
'console_scripts': [
    ...
    'mount.borg = borg.archiver:main_mount',
]
```

not already suffice for a fstab to work? `borg mount` expects `<device> <dir>`, just like mount.*

@enkore looks good, try. :)

Well, after being dropped once into "emergency maintenance mode" (systemd's wording :-) because I didn't have llfuse installed system-wide, it works quite well. See https://github.com/enkore/borg/tree/feature-mount.borg

```
$ borg list testrepo::arch1 
drwxr-xr-x mabe   mabe          0 Sun, 2016-03-13 15:53:45 testdir
-rw-r--r-- mabe   mabe          5 Sun, 2016-03-13 15:53:45 testdir/file1
-rw-r--r-- mabe   mabe          5 Sun, 2016-03-13 15:53:45 testdir/file2
-rw-r--r-- mabe   mabe          5 Sun, 2016-03-13 15:53:45 testdir/file3
-rw-r--r-- mabe   mabe   10485760 Sun, 2016-03-13 15:53:45 testdir/kern
$ cat /etc/fstab | tail -n 1
/home/mabe/Projekte/_oss/borg/testrepo::arch1 /mnt/test borg rw 0 2
$ sudo ls -lR /mnt/test  
/mnt/test:
total 0
drwxr-xr-x 1 mabe mabe 0 Mar 13 15:53 testdir

/mnt/test/testdir:
total 10240
-rw-r--r-- 1 mabe mabe        5 Mar 13 15:53 file1
-rw-r--r-- 1 mabe mabe        5 Mar 13 15:53 file2
-rw-r--r-- 1 mabe mabe        5 Mar 13 15:53 file3
-rw-r--r-- 1 mabe mabe 10485760 Mar 13 15:53 kern
```

(I only need sudo here because I forgot to chown /mnt/test after creating it. chown'ing it now fails, because that would apply to both / in the mounted archive, which isn't supported).

I specified `rw` (habit), `borg` didn't complain, I guess `borg mount`'s `-o` option is not too strict about what is passed.

`mount -t borg <repo> <mountpoint>` works just as well.

How will this affect standalone builds? Do we then have two "binaries" to download or will it be only borg and leave the rest to documentation? I'm all for this patch and having `mount.borg` to work with mount type `borg` looks great. 

Because they would need to be independent it would double the download size. I think there are two options for making this work with standalone binaries:
1. Tell the user to create bin/mount.borg with something like `borg mount $@`.
2. Tell the user to ln -s bin/mount.borg to borg (which would need a bit of code in borg.archiver:main to look at sys.argv[0](endswith%28/mount.borg%29 and do `sys.argv.insert%281,)`

@manwegit about the binary: there will be just 1 binary, leaving the rest to the docs.

That's what I thought, so examples to FAQ I assume?

Maybe rather extend borg mount usage docs.


Resolving patch:
diff --git a/borg/archiver.py b/borg/archiver.py
--- a/borg/archiver.py
+++ b/borg/archiver.py
@@ -1347,6 +1347,13 @@ def build_parser(self, args=None, prog=None):
         browsing an archive or restoring individual files. Unless the ``--foreground``
         option is given the command will run in the background until the filesystem
         is ``umounted``.
+
+        The command ``borgfs`` provides a wrapper for ``borg mount``. This can also be
+        used in fstab entries:
+        ``/path/to/repo /mnt/point fuse.borgfs defaults,noauto 0 0``
+
+        To allow a regular user to use fstab entries, add the ``user`` option:
+        ``/path/to/repo /mnt/point fuse.borgfs defaults,noauto,user 0 0``
         """)
         subparser = subparsers.add_parser('mount', parents=[common_parser],
                                           description=self.do_mount.__doc__,
@@ -1650,6 +1657,10 @@ def setup_signal_handlers():  # pragma: no cover
 
 
 def main():  # pragma: no cover
+    # provide 'borg mount' behaviour when the main script/executable is named borgfs
+    if os.path.basename(sys.argv[0]) == "borgfs":
+        sys.argv.insert(1, "mount")
+
     # Make sure stdout and stderr have errors='replace') to avoid unicode
     # issues when print()-ing unicode file names
     sys.stdout = io.TextIOWrapper(sys.stdout.buffer, sys.stdout.encoding, 'replace', line_buffering=True)
diff --git a/borg/helpers.py b/borg/helpers.py
--- a/borg/helpers.py
+++ b/borg/helpers.py
@@ -213,7 +213,17 @@ def show_progress(self, item=None, final=False, stream=None, dt=None):
 
 def get_keys_dir():
     """Determine where to repository keys and cache"""
-    xdg_config = os.environ.get('XDG_CONFIG_HOME', os.path.join(os.path.expanduser('~'), '.config'))
+
+    # os.path.expanduser() behaves differently for '~' and '~someuser' as
+    # parameters: when called with an explicit username, the possibly set
+    # environment variable HOME is no longer respected. So we have to check if
+    # it is set and only expand the user's home directory if HOME is unset.
+    if os.environ.get('HOME', ''):
+        home_dir = os.environ.get('HOME')
+    else:
+        home_dir = os.path.expanduser('~%s' % os.environ.get('USER'))
+
+    xdg_config = os.environ.get('XDG_CONFIG_HOME', os.path.join(home_dir, '.config'))
     keys_dir = os.environ.get('BORG_KEYS_DIR', os.path.join(xdg_config, 'borg', 'keys'))
     if not os.path.exists(keys_dir):
         os.makedirs(keys_dir)
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -262,6 +262,7 @@ def run(self):
     entry_points={
         'console_scripts': [
             'borg = borg.archiver:main',
+            'borgfs = borg.archiver:main',
         ]
     },
     cmdclass=cmdclass,


Test patch: