2022-03-28 20:23:47 +00:00
//go:build darwin || freebsd || linux
2020-05-12 09:30:41 +00:00
// +build darwin freebsd linux
2015-07-18 21:19:50 +00:00
2015-04-07 19:10:53 +00:00
package main
import (
"os"
2020-09-03 18:31:57 +00:00
"strings"
2018-01-14 13:22:08 +00:00
"time"
2017-07-23 12:21:03 +00:00
2016-09-17 10:36:05 +00:00
"github.com/spf13/cobra"
2017-07-23 12:21:03 +00:00
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/errors"
2016-08-29 17:18:57 +00:00
2017-07-23 12:21:03 +00:00
resticfs "github.com/restic/restic/internal/fs"
"github.com/restic/restic/internal/fuse"
2015-04-07 19:10:53 +00:00
2015-07-19 12:28:11 +00:00
systemFuse "bazil.org/fuse"
2015-04-07 19:10:53 +00:00
"bazil.org/fuse/fs"
)
2016-09-17 10:36:05 +00:00
var cmdMount = & cobra . Command {
Use : "mount [flags] mountpoint" ,
2017-09-11 16:32:44 +00:00
Short : "Mount the repository" ,
2016-09-17 10:36:05 +00:00
Long : `
The "mount" command mounts the repository via fuse to a directory . This is a
read - only mount .
2018-01-14 13:22:08 +00:00
Snapshot Directories
== == == == == == == == == ==
2020-09-03 18:31:57 +00:00
If you need a different template for directories that contain snapshots ,
you can pass a time template via -- time - template and path templates via
-- path - template .
2018-01-14 13:22:08 +00:00
2020-09-03 18:31:57 +00:00
Example time template without colons :
-- time - template "2006-01-02_15-04-05"
2018-01-14 13:22:08 +00:00
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 06:03:38 +00:00
2020-09-03 18:31:57 +00:00
For path templates , you can use the following patterns which will be replaced :
% i by short snapshot ID
% I by long snapshot ID
% u by username
% h by hostname
% t by tags
% T by timestamp as specified by -- time - template
The default path templates are :
"ids/%i"
"snapshots/%T"
"hosts/%h/%T"
"tags/%t/%T"
2019-11-05 06:03:38 +00:00
EXIT STATUS
== == == == == =
Exit status is 0 if the command was successful , and non - zero if there was any error .
2016-09-17 10:36:05 +00:00
` ,
2017-08-06 19:02:16 +00:00
DisableAutoGenTag : true ,
2016-09-17 10:36:05 +00:00
RunE : func ( cmd * cobra . Command , args [ ] string ) error {
return runMount ( mountOptions , globalOptions , args )
} ,
}
2015-07-26 18:41:29 +00:00
2016-09-17 10:36:05 +00:00
// MountOptions collects all options for the mount command.
type MountOptions struct {
2018-11-27 05:06:47 +00:00
OwnerRoot bool
AllowOther bool
NoDefaultPermissions bool
2022-09-02 22:19:19 +00:00
snapshotFilterOptions
TimeTemplate string
PathTemplates [ ] string
2015-04-07 19:10:53 +00:00
}
2016-09-17 10:36:05 +00:00
var mountOptions MountOptions
2015-04-07 19:10:53 +00:00
func init ( ) {
2016-09-17 10:36:05 +00:00
cmdRoot . AddCommand ( cmdMount )
2015-04-07 19:10:53 +00:00
2017-03-08 18:59:19 +00: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 05:06:47 +00: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 18:59:19 +00:00
2022-09-02 22:19:19 +00:00
initMultiSnapshotFilterOptions ( mountFlags , & mountOptions . snapshotFilterOptions , true )
2018-01-14 13:22:08 +00:00
2020-09-03 18:31:57 +00:00
mountFlags . StringArrayVar ( & mountOptions . PathTemplates , "path-template" , nil , "set `template` for path names (can be specified multiple times)" )
mountFlags . StringVar ( & mountOptions . TimeTemplate , "snapshot-template" , time . RFC3339 , "set `template` to use for snapshot dirs" )
mountFlags . StringVar ( & mountOptions . TimeTemplate , "time-template" , time . RFC3339 , "set `template` to use for times" )
_ = mountFlags . MarkDeprecated ( "snapshot-template" , "use --time-template" )
2015-04-07 19:10:53 +00:00
}
2020-10-21 09:04:02 +00:00
func runMount ( opts MountOptions , gopts GlobalOptions , args [ ] string ) error {
2020-09-03 18:31:57 +00:00
if opts . TimeTemplate == "" {
return errors . Fatal ( "time template string cannot be empty" )
2020-10-21 09:04:02 +00:00
}
2020-09-03 18:31:57 +00:00
if strings . HasPrefix ( opts . TimeTemplate , "/" ) || strings . HasSuffix ( opts . TimeTemplate , "/" ) {
return errors . Fatal ( "time template string cannot start or end with '/'" )
}
2020-10-21 09:04:02 +00:00
if len ( args ) == 0 {
return errors . Fatal ( "wrong number of parameters" )
}
2016-09-27 20:35:08 +00:00
debug . Log ( "start mount" )
defer debug . Log ( "finish mount" )
2015-04-07 19:10:53 +00:00
2016-09-17 10:36:05 +00:00
repo , err := OpenRepository ( gopts )
2015-04-07 19:10:53 +00:00
if err != nil {
return err
}
2020-07-06 00:26:21 +00:00
if ! gopts . NoLock {
2020-08-09 11:24:47 +00:00
lock , err := lockRepo ( gopts . ctx , repo )
2020-07-06 00:26:21 +00:00
defer unlockRepo ( lock )
if err != nil {
return err
}
2017-10-05 12:55:55 +00:00
}
use global context for check, debug, dump, find, forget, init, key,
list, mount, tag, unlock commands
gh-1434
2017-12-06 12:02:55 +00:00
err = repo . LoadIndex ( gopts . ctx )
2015-04-07 19:10:53 +00:00
if err != nil {
return err
}
2020-10-21 09:04:02 +00:00
mountpoint := args [ 0 ]
2022-06-13 18:35:37 +00:00
if _ , err := resticfs . Stat ( mountpoint ) ; errors . Is ( err , os . ErrNotExist ) {
2020-10-11 09:39:35 +00:00
Verbosef ( "Mountpoint %s doesn't exist\n" , mountpoint )
return err
2015-04-07 19:10:53 +00:00
}
2017-02-10 20:56:25 +00:00
mountOptions := [ ] systemFuse . MountOption {
2015-07-19 12:28:11 +00:00
systemFuse . ReadOnly ( ) ,
systemFuse . FSName ( "restic" ) ,
2021-06-12 15:01:51 +00:00
systemFuse . MaxReadahead ( 128 * 1024 ) ,
2017-02-10 20:56:25 +00:00
}
if opts . AllowOther {
mountOptions = append ( mountOptions , systemFuse . AllowOther ( ) )
2019-01-06 19:55:49 +00:00
// let the kernel check permissions unless it is explicitly disabled
if ! opts . NoDefaultPermissions {
mountOptions = append ( mountOptions , systemFuse . DefaultPermissions ( ) )
}
2018-11-27 05:06:47 +00:00
}
2018-10-03 04:34:28 +00:00
2022-08-26 21:04:59 +00:00
AddCleanupHandler ( func ( code int ) ( int , error ) {
2020-10-21 09:04:02 +00:00
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 )
}
2022-08-26 21:07:07 +00:00
// replace error code of sigint
if code == 130 {
code = 0
}
2022-08-26 21:04:59 +00:00
return code , nil
2020-10-21 09:04:02 +00:00
} )
2017-02-10 20:56:25 +00:00
c , err := systemFuse . Mount ( mountpoint , mountOptions ... )
2015-04-07 19:10:53 +00:00
if err != nil {
return err
}
2017-06-18 12:59:44 +00:00
systemFuse . Debug = func ( msg interface { } ) {
debug . Log ( "fuse: %v" , msg )
}
cfg := fuse . Config {
2020-09-03 18:31:57 +00:00
OwnerIsRoot : opts . OwnerRoot ,
Hosts : opts . Hosts ,
Tags : opts . Tags ,
Paths : opts . Paths ,
TimeTemplate : opts . TimeTemplate ,
PathTemplates : opts . PathTemplates ,
2017-06-18 12:59:44 +00:00
}
2020-06-14 10:49:39 +00:00
root := fuse . NewRoot ( repo , cfg )
2017-06-18 12:59:44 +00:00
2016-09-17 10:36:05 +00:00
Printf ( "Now serving the repository at %s\n" , mountpoint )
2021-11-01 19:59:20 +00:00
Printf ( "Use another terminal or tool to browse the contents of this folder.\n" )
Printf ( "When finished, quit with Ctrl-c here or umount the mountpoint.\n" )
2016-09-17 10:36:05 +00:00
2016-09-27 20:35:08 +00:00
debug . Log ( "serving mount at %v" , mountpoint )
2017-06-18 12:59:44 +00:00
err = fs . Serve ( c , root )
2016-09-15 19:17:20 +00:00
if err != nil {
return err
}
<- c . Ready
return c . MountError
}
2016-09-17 10:36:05 +00:00
func umount ( mountpoint string ) error {
2016-09-15 19:17:20 +00:00
return systemFuse . Unmount ( mountpoint )
}