2020-05-12 11:30:41 +02:00
// +build darwin freebsd linux
2015-07-18 23:19:50 +02:00
2015-04-07 21:10:53 +02:00
package main
import (
"os"
2018-01-14 14:22:08 +01:00
"strings"
"time"
2017-07-23 14:21:03 +02:00
2016-09-17 12:36:05 +02:00
"github.com/spf13/cobra"
2017-07-23 14:21:03 +02:00
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/errors"
2017-07-24 17:42:25 +02:00
"github.com/restic/restic/internal/restic"
2016-08-29 19:18:57 +02:00
2017-07-23 14:21:03 +02:00
resticfs "github.com/restic/restic/internal/fs"
"github.com/restic/restic/internal/fuse"
2015-04-07 21:10:53 +02:00
2015-07-19 14:28:11 +02:00
systemFuse "bazil.org/fuse"
2015-04-07 21:10:53 +02:00
"bazil.org/fuse/fs"
)
2016-09-17 12:36:05 +02:00
var cmdMount = & cobra . Command {
Use : "mount [flags] mountpoint" ,
2017-09-11 18:32:44 +02:00
Short : "Mount the repository" ,
2016-09-17 12:36:05 +02:00
Long : `
The "mount" command mounts the repository via fuse to a directory . This is a
read - only mount .
2018-01-14 14:22:08 +01:00
Snapshot Directories
== == == == == == == == == ==
If you need a different template for all directories that contain snapshots ,
you can pass a template via -- snapshot - template . Example without colons :
-- snapshot - template "2006-01-02_15-04-05"
You need to specify a sample format for exactly the following timestamp :
Mon Jan 2 15 : 04 : 05 - 0700 MST 2006
For details please see the documentation for time . Format ( ) at :
https : //godoc.org/time#Time.Format
2019-11-05 07:03:38 +01:00
EXIT STATUS
== == == == == =
Exit status is 0 if the command was successful , and non - zero if there was any error .
2016-09-17 12:36:05 +02:00
` ,
2017-08-06 21:02:16 +02:00
DisableAutoGenTag : true ,
2016-09-17 12:36:05 +02:00
RunE : func ( cmd * cobra . Command , args [ ] string ) error {
return runMount ( mountOptions , globalOptions , args )
} ,
}
2015-07-26 20:41:29 +02:00
2016-09-17 12:36:05 +02:00
// MountOptions collects all options for the mount command.
type MountOptions struct {
2018-11-27 06:06:47 +01:00
OwnerRoot bool
AllowOther bool
NoDefaultPermissions bool
2020-02-26 22:17:59 +01:00
Hosts [ ] string
2018-11-27 06:06:47 +01:00
Tags restic . TagLists
Paths [ ] string
SnapshotTemplate string
2015-04-07 21:10:53 +02:00
}
2016-09-17 12:36:05 +02:00
var mountOptions MountOptions
2015-04-07 21:10:53 +02:00
func init ( ) {
2016-09-17 12:36:05 +02:00
cmdRoot . AddCommand ( cmdMount )
2015-04-07 21:10:53 +02:00
2017-03-08 19:59:19 +01:00
mountFlags := cmdMount . Flags ( )
mountFlags . BoolVar ( & mountOptions . OwnerRoot , "owner-root" , false , "use 'root' as the owner of files and dirs" )
mountFlags . BoolVar ( & mountOptions . AllowOther , "allow-other" , false , "allow other users to access the data in the mounted directory" )
2018-11-27 06:06:47 +01:00
mountFlags . BoolVar ( & mountOptions . NoDefaultPermissions , "no-default-permissions" , false , "for 'allow-other', ignore Unix permissions and allow users to read all snapshot files" )
2017-03-08 19:59:19 +01:00
2020-02-26 22:17:59 +01:00
mountFlags . StringArrayVarP ( & mountOptions . Hosts , "host" , "H" , nil , ` only consider snapshots for this host (can be specified multiple times) ` )
2017-07-09 12:45:49 +02:00
mountFlags . Var ( & mountOptions . Tags , "tag" , "only consider snapshots which include this `taglist`" )
2017-07-07 03:19:06 +02:00
mountFlags . StringArrayVar ( & mountOptions . Paths , "path" , nil , "only consider snapshots which include this (absolute) `path`" )
2018-01-14 14:22:08 +01:00
mountFlags . StringVar ( & mountOptions . SnapshotTemplate , "snapshot-template" , time . RFC3339 , "set `template` to use for snapshot dirs" )
2015-04-07 21:10:53 +02:00
}
2020-10-21 11:04:02 +02:00
func runMount ( opts MountOptions , gopts GlobalOptions , args [ ] string ) error {
if opts . SnapshotTemplate == "" {
return errors . Fatal ( "snapshot template string cannot be empty" )
}
if strings . ContainsAny ( opts . SnapshotTemplate , ` \/ ` ) {
return errors . Fatal ( "snapshot template string contains a slash (/) or backslash (\\) character" )
}
if len ( args ) == 0 {
return errors . Fatal ( "wrong number of parameters" )
}
2016-09-27 22:35:08 +02:00
debug . Log ( "start mount" )
defer debug . Log ( "finish mount" )
2015-04-07 21:10:53 +02:00
2016-09-17 12:36:05 +02:00
repo , err := OpenRepository ( gopts )
2015-04-07 21:10:53 +02:00
if err != nil {
return err
}
2020-07-06 02:26:21 +02:00
if ! gopts . NoLock {
2020-08-09 13:24:47 +02:00
lock , err := lockRepo ( gopts . ctx , repo )
2020-07-06 02:26:21 +02:00
defer unlockRepo ( lock )
if err != nil {
return err
}
2017-10-05 14:55:55 +02:00
}
use global context for check, debug, dump, find, forget, init, key,
list, mount, tag, unlock commands
gh-1434
2017-12-06 13:02:55 +01:00
err = repo . LoadIndex ( gopts . ctx )
2015-04-07 21:10:53 +02:00
if err != nil {
return err
}
2020-10-21 11:04:02 +02:00
mountpoint := args [ 0 ]
2016-08-29 19:18:57 +02:00
if _ , err := resticfs . Stat ( mountpoint ) ; os . IsNotExist ( errors . Cause ( err ) ) {
2020-10-11 11:39:35 +02:00
Verbosef ( "Mountpoint %s doesn't exist\n" , mountpoint )
return err
2015-04-07 21:10:53 +02:00
}
2017-02-10 21:56:25 +01:00
mountOptions := [ ] systemFuse . MountOption {
2015-07-19 14:28:11 +02:00
systemFuse . ReadOnly ( ) ,
systemFuse . FSName ( "restic" ) ,
2017-02-10 21:56:25 +01:00
}
if opts . AllowOther {
mountOptions = append ( mountOptions , systemFuse . AllowOther ( ) )
2019-01-06 20:55:49 +01:00
// let the kernel check permissions unless it is explicitly disabled
if ! opts . NoDefaultPermissions {
mountOptions = append ( mountOptions , systemFuse . DefaultPermissions ( ) )
}
2018-11-27 06:06:47 +01:00
}
2018-10-03 06:34:28 +02:00
2020-10-21 11:04:02 +02:00
AddCleanupHandler ( func ( ) error {
debug . Log ( "running umount cleanup handler for mount at %v" , mountpoint )
err := umount ( mountpoint )
if err != nil {
Warnf ( "unable to umount (maybe already umounted or still in use?): %v\n" , err )
}
return nil
} )
2017-02-10 21:56:25 +01:00
c , err := systemFuse . Mount ( mountpoint , mountOptions ... )
2015-04-07 21:10:53 +02:00
if err != nil {
return err
}
2017-06-18 14:59:44 +02:00
systemFuse . Debug = func ( msg interface { } ) {
debug . Log ( "fuse: %v" , msg )
}
cfg := fuse . Config {
2018-01-14 14:22:08 +01:00
OwnerIsRoot : opts . OwnerRoot ,
2020-02-26 22:17:59 +01:00
Hosts : opts . Hosts ,
2018-01-14 14:22:08 +01:00
Tags : opts . Tags ,
Paths : opts . Paths ,
SnapshotTemplate : opts . SnapshotTemplate ,
2017-06-18 14:59:44 +02:00
}
2020-06-14 12:49:39 +02:00
root := fuse . NewRoot ( repo , cfg )
2017-06-18 14:59:44 +02:00
2016-09-17 12:36:05 +02:00
Printf ( "Now serving the repository at %s\n" , mountpoint )
2019-01-28 22:53:35 +01:00
Printf ( "When finished, quit with Ctrl-c or umount the mountpoint.\n" )
2016-09-17 12:36:05 +02:00
2016-09-27 22:35:08 +02:00
debug . Log ( "serving mount at %v" , mountpoint )
2017-06-18 14:59:44 +02:00
err = fs . Serve ( c , root )
2016-09-15 21:17:20 +02:00
if err != nil {
return err
}
<- c . Ready
return c . MountError
}
2016-09-17 12:36:05 +02:00
func umount ( mountpoint string ) error {
2016-09-15 21:17:20 +02:00
return systemFuse . Unmount ( mountpoint )
}