github.com/fawick/restic@v0.1.1-0.20171126184616-c02923fbfc79/cmd/restic/cmd_mount.go (about) 1 // +build !openbsd 2 // +build !windows 3 4 package main 5 6 import ( 7 "context" 8 "os" 9 10 "github.com/spf13/cobra" 11 12 "github.com/restic/restic/internal/debug" 13 "github.com/restic/restic/internal/errors" 14 "github.com/restic/restic/internal/restic" 15 16 resticfs "github.com/restic/restic/internal/fs" 17 "github.com/restic/restic/internal/fuse" 18 19 systemFuse "bazil.org/fuse" 20 "bazil.org/fuse/fs" 21 ) 22 23 var cmdMount = &cobra.Command{ 24 Use: "mount [flags] mountpoint", 25 Short: "Mount the repository", 26 Long: ` 27 The "mount" command mounts the repository via fuse to a directory. This is a 28 read-only mount. 29 `, 30 DisableAutoGenTag: true, 31 RunE: func(cmd *cobra.Command, args []string) error { 32 return runMount(mountOptions, globalOptions, args) 33 }, 34 } 35 36 // MountOptions collects all options for the mount command. 37 type MountOptions struct { 38 OwnerRoot bool 39 AllowRoot bool 40 AllowOther bool 41 Host string 42 Tags restic.TagLists 43 Paths []string 44 } 45 46 var mountOptions MountOptions 47 48 func init() { 49 cmdRoot.AddCommand(cmdMount) 50 51 mountFlags := cmdMount.Flags() 52 mountFlags.BoolVar(&mountOptions.OwnerRoot, "owner-root", false, "use 'root' as the owner of files and dirs") 53 mountFlags.BoolVar(&mountOptions.AllowRoot, "allow-root", false, "allow root user to access the data in the mounted directory") 54 mountFlags.BoolVar(&mountOptions.AllowOther, "allow-other", false, "allow other users to access the data in the mounted directory") 55 56 mountFlags.StringVarP(&mountOptions.Host, "host", "H", "", `only consider snapshots for this host`) 57 mountFlags.Var(&mountOptions.Tags, "tag", "only consider snapshots which include this `taglist`") 58 mountFlags.StringArrayVar(&mountOptions.Paths, "path", nil, "only consider snapshots which include this (absolute) `path`") 59 } 60 61 func mount(opts MountOptions, gopts GlobalOptions, mountpoint string) error { 62 debug.Log("start mount") 63 defer debug.Log("finish mount") 64 65 repo, err := OpenRepository(gopts) 66 if err != nil { 67 return err 68 } 69 70 lock, err := lockRepo(repo) 71 defer unlockRepo(lock) 72 if err != nil { 73 return err 74 } 75 76 err = repo.LoadIndex(context.TODO()) 77 if err != nil { 78 return err 79 } 80 81 if _, err := resticfs.Stat(mountpoint); os.IsNotExist(errors.Cause(err)) { 82 Verbosef("Mountpoint %s doesn't exist, creating it\n", mountpoint) 83 err = resticfs.Mkdir(mountpoint, os.ModeDir|0700) 84 if err != nil { 85 return err 86 } 87 } 88 89 mountOptions := []systemFuse.MountOption{ 90 systemFuse.ReadOnly(), 91 systemFuse.FSName("restic"), 92 } 93 94 if opts.AllowRoot { 95 mountOptions = append(mountOptions, systemFuse.AllowRoot()) 96 } 97 98 if opts.AllowOther { 99 mountOptions = append(mountOptions, systemFuse.AllowOther()) 100 } 101 102 c, err := systemFuse.Mount(mountpoint, mountOptions...) 103 if err != nil { 104 return err 105 } 106 107 systemFuse.Debug = func(msg interface{}) { 108 debug.Log("fuse: %v", msg) 109 } 110 111 cfg := fuse.Config{ 112 OwnerIsRoot: opts.OwnerRoot, 113 Host: opts.Host, 114 Tags: opts.Tags, 115 Paths: opts.Paths, 116 } 117 root, err := fuse.NewRoot(context.TODO(), repo, cfg) 118 if err != nil { 119 return err 120 } 121 122 Printf("Now serving the repository at %s\n", mountpoint) 123 Printf("Don't forget to umount after quitting!\n") 124 125 debug.Log("serving mount at %v", mountpoint) 126 err = fs.Serve(c, root) 127 if err != nil { 128 return err 129 } 130 131 <-c.Ready 132 return c.MountError 133 } 134 135 func umount(mountpoint string) error { 136 return systemFuse.Unmount(mountpoint) 137 } 138 139 func runMount(opts MountOptions, gopts GlobalOptions, args []string) error { 140 if len(args) == 0 { 141 return errors.Fatal("wrong number of parameters") 142 } 143 144 mountpoint := args[0] 145 146 AddCleanupHandler(func() error { 147 debug.Log("running umount cleanup handler for mount at %v", mountpoint) 148 err := umount(mountpoint) 149 if err != nil { 150 Warnf("unable to umount (maybe already umounted?): %v\n", err) 151 } 152 return nil 153 }) 154 155 return mount(opts, gopts, mountpoint) 156 }