Example #1
0
func fusetestCommon(t *testing.T, fs *otaru.FileSystem, f func(mountpoint string)) {
	bfuse.Debug = func(msg interface{}) {
		log.Printf("fusedbg: %v", msg)
	}

	mountpoint := "/tmp/hoge"

	if err := os.Mkdir(mountpoint, 0777); err != nil && !os.IsExist(err) {
		log.Fatalf("Failed to create mountpoint: %v", err)
	}

	bfuse.Unmount(mountpoint)

	done := make(chan bool)
	ready := make(chan bool)
	go func() {
		if err := fuse.ServeFUSE("otaru-test", mountpoint, fs, ready); err != nil {
			t.Errorf("ServeFUSE err: %v", err)
			close(ready)
		}
		close(done)
	}()
	<-ready

	f(mountpoint)

	time.Sleep(100 * time.Millisecond)
	if err := bfuse.Unmount(mountpoint); err != nil {
		t.Errorf("umount failed: %v", err)
	}
	<-done
}
Example #2
0
func runMount(cmd *Command, args []string) bool {
	fmt.Printf("This is SeaweedFS version %s %s %s\n", util.VERSION, runtime.GOOS, runtime.GOARCH)
	if *mountOptions.dir == "" {
		fmt.Printf("Please specify the mount directory via \"-dir\"")
		return false
	}

	c, err := fuse.Mount(*mountOptions.dir)
	if err != nil {
		glog.Fatal(err)
		return false
	}

	OnInterrupt(func() {
		fuse.Unmount(*mountOptions.dir)
		c.Close()
	})

	err = fs.Serve(c, WFS{})
	if err != nil {
		fuse.Unmount(*mountOptions.dir)
	}

	// check if the mount process has an error to report
	<-c.Ready
	if err := c.MountError; err != nil {
		glog.Fatal(err)
	}

	return true
}
Example #3
0
func main() {
	flag.Usage = Usage
	flag.Parse()

	if flag.NArg() != 2 {
		Usage()
		os.Exit(2)
	}
	mountpoint := flag.Arg(0)

	c, err := fuse.Mount(
		mountpoint,
		fuse.FSName("MomFS"),
		fuse.Subtype("momfs"),
		fuse.LocalVolume(),
		fuse.VolumeName("Mom file system"),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()

	sigintCh := make(chan os.Signal, 1)
	signal.Notify(sigintCh, os.Interrupt)

	go func() {
		<-sigintCh
		log.Printf("Program interrupted. Trying to unmount file system.\n")
		err := fuse.Unmount(mountpoint)
		if err != nil {
			log.Println(err)
			log.Println("Failed to unmount file system. Trying again..")
			for {
				<-time.Tick(1 * time.Second)
				fuse.Unmount(mountpoint)
			}
		}
	}()

	err = fs.Serve(c, NewOrgFS())
	if err != nil {
		log.Fatal(err)
	}

	// check if the mount process has an error to report
	<-c.Ready
	if err := c.MountError; err != nil {
		log.Fatal(err)
	}
}
Example #4
0
func main() {
	config := NewConfig()
	fuse.Unmount(config.Base)
	os.MkdirAll(config.Base, 0777)

	conn, err := process(config)
	if err != nil {
		logex.Fatal(err)
	}
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGHUP)
	<-c
	fuse.Unmount(config.Base)
	conn.Close()
}
func (r *fsRoot) Close() error {
	r.Lock()
	if r.dst != nil {
		// Since newConn only sends on dst while holding a reader lock, holding the
		// writer lock is sufficient to ensure there are no pending sends on the
		// channel when it is closed.
		close(r.dst)
		// Setting it to nil prevents further sends.
		r.dst = nil
	}
	r.Unlock()

	log.Printf("unmount %q", r.linkDir)
	if err := fuse.Unmount(r.linkDir); err != nil {
		return err
	}

	var errs bytes.Buffer
	r.sockLock.Lock()
	for _, c := range r.closers {
		if err := c.Close(); err != nil {
			fmt.Fprintln(&errs, err)
		}
	}
	r.sockLock.Unlock()

	if errs.Len() == 0 {
		return nil
	}
	log.Printf("Close %q: %v", r.linkDir, errs.String())
	return errors.New(errs.String())
}
Example #6
0
// Close will wait until all I/O operations are done and unmount the fuse
// mount again.
func (m *Mount) Close() error {
	if m.closed {
		return nil
	}
	m.closed = true

	log.Info("Umount fuse layer...")

	for tries := 0; tries < 20; tries++ {
		if err := fuse.Unmount(m.Dir); err != nil {
			// log.Printf("unmount error: %v", err)
			time.Sleep(100 * time.Millisecond)
			continue
		}

		break
	}

	// Be sure to drain the error channel:
	select {
	case err := <-m.errors:
		// Serve() had some error after some time:
		if err != nil {
			log.Warningf("fuse returned an error: %v", err)
		}
	}

	// Be sure to pull the item from the channel:
	<-m.done

	if err := m.Conn.Close(); err != nil {
		return err
	}
	return nil
}
Example #7
0
func main() {
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)

	flag.Usage = Usage
	flag.Parse()

	cfg, err := facade.NewConfigFromTomlFile(*flagConfigFile)
	if err != nil {
		log.Printf("%v", err)
		Usage()
		os.Exit(2)
	}
	if flag.NArg() != 1 {
		Usage()
		os.Exit(2)
	}
	mountpoint := flag.Arg(0)

	o, err := facade.NewOtaru(cfg, &facade.OneshotConfig{Mkfs: *flagMkfs})
	if err != nil {
		log.Printf("NewOtaru failed: %v", err)
		os.Exit(1)
	}
	var muClose sync.Mutex
	closeOtaruAndExit := func() {
		muClose.Lock()
		defer muClose.Unlock()

		if err := bfuse.Unmount(mountpoint); err != nil {
			log.Printf("umount err: %v", err)
		}
		if o != nil {
			if err := o.Close(); err != nil {
				log.Printf("Otaru.Close() returned errs: %v", err)
			}
			o = nil
		}
		os.Exit(0)
	}
	defer closeOtaruAndExit()

	sigC := make(chan os.Signal, 1)
	signal.Notify(sigC, os.Interrupt)
	signal.Notify(sigC, syscall.SIGTERM)
	go func() {
		for s := range sigC {
			log.Printf("Received signal: %v", s)
			closeOtaruAndExit()
		}
	}()

	bfuse.Debug = func(msg interface{}) {
		log.Printf("fusedbg: %v", msg)
	}
	if err := fuse.ServeFUSE(mountpoint, o.FS, nil); err != nil {
		log.Fatalf("ServeFUSE failed: %v", err)
	}
	log.Printf("ServeFUSE end!")
}
Example #8
0
func ccfsUnmount(mountpoint string) {
	err := fuse.Unmount(mountpoint)
	if err != nil {
		log.Printf("Could not unmount: %s", err)
	}
	log.Printf("Exit-kill program")
	os.Exit(0)
}
Example #9
0
// Unmount tries to unmount normally and then force if unsuccessful
func (m ForceMounter) Unmount() (err error) {
	// Try unmount
	err = fuse.Unmount(m.dir)
	if err != nil {
		// Unmount failed, so let's try and force it.
		err = m.forceUnmount()
	}
	return
}
func TestMain(m *testing.M) {
	// Ensure this directory exists.
	os.MkdirAll(dir, 0777)

	// Unmount before the tests start, else they won't work correctly.
	if err := fuse.Unmount(dir); err != nil {
		log.Printf("couldn't unmount fuse directory %q: %v", dir, err)
	}

	ret := m.Run()
	// Make sure to unmount at the end, so that we don't leave the system in an
	// inconsistent state in case something weird happened.
	if err := fuse.Unmount(dir); err != nil {
		log.Printf("couldn't unmount fuse directory %q: %v", dir, err)
	}

	os.Exit(ret)
}
Example #11
0
func handleStopSignals(mountPoint string) {
	s := make(chan os.Signal, 10)
	signal.Notify(s, os.Interrupt, syscall.SIGTERM, syscall.SIGSTOP)

	for range s {
		if err := fuse.Unmount(mountPoint); err != nil {
			log.Fatalf("Error umounting %s: %s", mountPoint, err)
		}
		os.Exit(0)
	}
}
Example #12
0
func exitSignalHandlers(fs *torrentfs.TorrentFS) {
	c := make(chan os.Signal)
	signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
	for {
		<-c
		fs.Destroy()
		err := fuse.Unmount(*mountDir)
		if err != nil {
			log.Print(err)
		}
	}
}
// NewConnSrc returns a source of new connections based on Lookups in the
// provided mount directory. If there isn't a directory located at tmpdir one
// is created. The second return parameter can be used to shutdown and release
// any resources. As a result of this shutdown, or during any other fatal
// error, the returned chan will be closed.
//
// The connset parameter is optional.
func NewConnSrc(mountdir, tmpdir string, connset *proxy.ConnSet) (<-chan proxy.Conn, io.Closer, error) {
	if err := os.MkdirAll(tmpdir, 0777); err != nil {
		return nil, nil, err
	}

	if err := fuse.Unmount(mountdir); err != nil {
		// The error is too verbose to be useful to print out
	}
	log.Printf("Mounting %v...", mountdir)
	c, err := fuse.Mount(mountdir, fuse.AllowOther())
	if err != nil {
		return nil, nil, fmt.Errorf("cannot mount %q: %v", mountdir, err)
	}
	log.Printf("Mounted %v", mountdir)

	if connset == nil {
		// Make a dummy one.
		connset = proxy.NewConnSet()
	}
	conns := make(chan proxy.Conn, 1)
	root := &fsRoot{
		tmpDir:  tmpdir,
		linkDir: mountdir,
		dst:     conns,
		links:   make(map[string]symlink),
		closers: []io.Closer{c},
		connset: connset,
	}

	server := fs.New(c, &fs.Config{
		Debug: func(msg interface{}) {
			if false {
				log.Print(msg)
			}
		},
	})

	go func() {
		if err := server.Serve(root); err != nil {
			log.Printf("serve %q exited due to error: %v", mountdir, err)
		}
		// The server exited but we don't know whether this is because of a
		// graceful reason (via root.Close) or via an external force unmounting.
		// Closing the root will ensure the 'dst' chan is closed correctly to
		// signify that no new connections are possible.
		if err := root.Close(); err != nil {
			log.Printf("root.Close() error: %v", err)
		}
		log.Printf("FUSE exited")
	}()

	return conns, root, nil
}
Example #14
0
func (v *volumeDriver) Unmount(volumeID api.VolumeID, mountpath string) error {
	volume, err := v.GetVol(volumeID)
	if err != nil {
		return err
	}
	if volume.AttachPath == "" {
		return fmt.Errorf("openstorage: device not mounted: %v", volumeID)
	}
	if err := fuse.Unmount(volume.AttachPath); err != nil {
		return err
	}
	volume.AttachPath = ""
	return v.UpdateVol(volume)
}
Example #15
0
func (proxy *Proxy) Serve() error {
	err := fuse.Unmount(proxy.Mountpoint)
	if err != nil {
		log.Print(err)
	}

	connection, err := fuse.Mount(proxy.Mountpoint)
	if err != nil {
		log.Fatal(err)
	}

	log.Printf("%+v", connection)

	result := fs.Serve(connection, proxy)

	log.Printf("Result %+v", result)

	return result
}
Example #16
0
// Close unmounts the filesystem and waits for fs.Serve to return.
//
// TODO not true: Any returned error will be stored in Err.
//
//  It is safe to call Close multiple times.
func (mnt *Mount) Close() {
	if mnt.closed {
		return
	}
	mnt.closed = true
	for tries := 0; tries < 1000; tries++ {
		err := fuse.Unmount(mnt.Dir)
		if err != nil {
			// TODO do more than log?
			// TODO use lazy unmount where available?
			log.Printf("unmount error: %v", err)
			time.Sleep(10 * time.Millisecond)
			continue
		}
		break
	}
	mnt.app.WaitForUnmount(&mnt.Info.VolumeID)
	os.Remove(mnt.Dir)
}
Example #17
0
// Close unmounts the filesystem and waits for fs.Serve to return. Any
// returned error will be stored in Err. It is safe to call Close
// multiple times.
func (mnt *Mount) Close() {
	if mnt.closed {
		return
	}
	mnt.closed = true
	for tries := 0; tries < 1000; tries++ {
		err := fuse.Unmount(mnt.Dir)
		if err != nil {
			// TODO do more than log?
			log.Printf("unmount error: %v", err)
			time.Sleep(10 * time.Millisecond)
			continue
		}
		break
	}
	<-mnt.done
	mnt.Conn.Close()
	os.Remove(mnt.Dir)
}
Example #18
0
func process(c *Config) (conn *fuse.Conn, err error) {
	if err = fuse.Unmount(c.Base); err == nil {
		logex.Info("last not unmount")
		time.Sleep(1000 * time.Millisecond)
		err = nil
	} else {
		err = nil
	}

	ops := []fuse.MountOption{
		fuse.AllowOther(),
		fuse.FSName(FsName),
		fuse.LocalVolume(),
	}
	conn, err = fuse.Mount(c.Base, ops...)
	if err != nil {
		return nil, logex.Trace(err)
	}
	go fs.Serve(conn, NewTree("/", c.Target))
	logex.Info("connected.")
	return conn, nil
}
Example #19
0
// Unmount tries to unmount normally and then if force if unsuccessful.
func Unmount(dir string, force bool, log Log) error {
	if !force {
		mounted, err := IsMounted(dir, log)
		if err != nil {
			return err
		}
		if !mounted {
			return fmt.Errorf("Not mounted")
		}
	}

	log.Info("Trying to unmount: %s", dir)
	err := fuse.Unmount(dir)
	if err != nil {
		if !force {
			return err
		}
		// Unmount failed and we want to force it.
		log.Info("Unmount %s failed: %s; We will try to force it", dir, err)
		err = ForceUnmount(dir, log)
	}
	return err
}
Example #20
0
File: etcfs.go Project: a2sdl/etcfs
func main() {
	mountpoint := "/Users/gtarcea/fuse/nginx"
	fuse.Unmount(mountpoint)
	conn, err := fuse.Mount(
		mountpoint,
		fuse.FSName("etcfs"),
		fuse.Subtype("etcfs"),
		fuse.LocalVolume(),
		fuse.VolumeName("etcfs"),
	)
	if err != nil {
		log.Fatal(err)
	}

	defer conn.Close()

	err = fs.Serve(conn, etcfs.FS{})

	<-conn.Ready
	if conn.MountError != nil {
		log.Fatal(conn.MountError)
	}
}
Example #21
0
// Unmount tries to unmount normally and then if force if unsuccessful.
func Unmount(g *libkb.GlobalContext, dir string, force bool) error {
	if !force {
		mounted, err := IsMounted(g, dir)
		if err != nil {
			return err
		}
		if !mounted {
			return fmt.Errorf("Not mounted")
		}
	}

	g.Log.Info("Trying to unmount: %s", dir)
	err := fuse.Unmount(dir)
	if err != nil {
		if !force {
			return err
		}
		// Unmount failed and we want to force it.
		g.Log.Info("Unmount %s failed: %s; We will try to force it", dir, err)
		err = ForceUnmount(g, dir)
	}
	return err
}
Example #22
0
// Unmount the FS
func (v *VaultFS) Unmount() error {
	if v.conn == nil {
		return errors.New("not mounted")
	}

	err := fuse.Unmount(v.mountpoint)
	if err != nil {
		return err
	}

	err = v.conn.Close()
	if err != nil {
		return err
	}

	logrus.Debug("closed connection, waiting for ready")
	<-v.conn.Ready
	if v.conn.MountError != nil {
		return v.conn.MountError
	}

	return nil
}
Example #23
0
func action(c *cli.Context) {
	if len(c.Args()) < 1 {
		cli.ShowAppHelp(c)
		return
	}

	if c.Bool("unmount") {
		fuse.Unmount(c.Args().First())
		return
	}

	err := redisfs.Mount(c.Args().First(), &redisfs.MountOptions{
		Network:  "tcp",
		Address:  c.String("host") + ":" + c.String("port"),
		MaxIdel:  c.Int("max-idel"),
		Sep:      c.String("sep"),
		DB:       c.String("db"),
		Password: c.String("auth"),
	})

	if err != nil {
		log.Fatal(err)
	}
}
Example #24
0
func main() {
	flag.Usage = usage
	flag.Parse()

	if flag.NArg() != 2 {
		usage()
		os.Exit(2)
	}

	dbURL, mountPoint := flag.Arg(0), flag.Arg(1)

	// Open DB connection first.
	db, err := sql.Open("postgres", dbURL)
	if err != nil {
		log.Fatal(err)
	}
	defer func() { _ = db.Close() }()

	if err := initSchema(db); err != nil {
		log.Fatal(err)
	}

	cfs := CFS{db}
	// Mount filesystem.
	c, err := fuse.Mount(
		mountPoint,
		fuse.FSName("CockroachFS"),
		fuse.Subtype("CockroachFS"),
		fuse.LocalVolume(),
		fuse.VolumeName(""),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer func() {
		_ = c.Close()
	}()

	go func() {
		sig := make(chan os.Signal, 1)
		signal.Notify(sig, os.Interrupt)
		for range sig {
			if err := fuse.Unmount(mountPoint); err != nil {
				log.Printf("Signal received, but could not unmount: %s", err)
			} else {
				break
			}
		}
	}()

	// Serve root.
	err = fs.Serve(c, cfs)
	if err != nil {
		log.Fatal(err)
	}

	// check if the mount process has an error to report
	<-c.Ready
	if err := c.MountError; err != nil {
		log.Fatal(err)
	}
}
Example #25
0
func umount(mountpoint string) error {
	return systemFuse.Unmount(mountpoint)
}
Example #26
0
func (m *mounter) Unmount(mountPoint string) error {
	return fuse.Unmount(mountPoint)
}
Example #27
0
func main() {
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
	logger.Registry().AddOutput(logger.WriterLogger{os.Stderr})
	flag.Usage = Usage
	flag.Parse()

	cfg, err := facade.NewConfig(*flagConfigDir)
	if err != nil {
		logger.Criticalf(mylog, "%v", err)
		Usage()
		os.Exit(2)
	}
	if flag.NArg() != 1 {
		Usage()
		os.Exit(2)
	}
	mountpoint := flag.Arg(0)

	if err := facade.SetupFluentLogger(cfg); err != nil {
		logger.Criticalf(mylog, "Failed to setup fluentd logger: %v", err)
		os.Exit(1)
	}

	o, err := facade.NewOtaru(cfg, &facade.OneshotConfig{Mkfs: *flagMkfs})
	if err != nil {
		logger.Criticalf(mylog, "NewOtaru failed: %v", err)
		os.Exit(1)
	}
	var muClose sync.Mutex
	closeOtaruAndExit := func(exitCode int) {
		muClose.Lock()
		defer muClose.Unlock()

		if err := bfuse.Unmount(mountpoint); err != nil {
			logger.Warningf(mylog, "umount err: %v", err)
		}
		if o != nil {
			if err := o.Close(); err != nil {
				logger.Warningf(mylog, "Otaru.Close() returned errs: %v", err)
			}
			o = nil
		}
		os.Exit(exitCode)
	}
	defer closeOtaruAndExit(0)

	sigC := make(chan os.Signal, 1)
	signal.Notify(sigC, os.Interrupt)
	signal.Notify(sigC, syscall.SIGTERM)
	go func() {
		for s := range sigC {
			logger.Warningf(mylog, "Received signal: %v", s)
			closeOtaruAndExit(1)
		}
	}()
	logger.Registry().AddOutput(logger.HandleCritical(func() {
		logger.Warningf(mylog, "Starting shutdown due to critical event.")
		closeOtaruAndExit(1)
	}))

	bfuseLogger := logger.Registry().Category("bfuse")
	bfuse.Debug = func(msg interface{}) { logger.Debugf(bfuseLogger, "%v", msg) }
	if err := fuse.ServeFUSE(cfg.BucketName, mountpoint, o.FS, nil); err != nil {
		logger.Warningf(mylog, "ServeFUSE failed: %v", err)
		closeOtaruAndExit(1)
	}
	logger.Infof(mylog, "ServeFUSE end!")
}
Example #28
0
func main() {
	flag.Usage = Usage

	debugPtr := flag.Bool("debug", false, "print lots of stuff")
	newfsPtr := flag.Bool("newfs", false, "start with an empty file system")
	mtimePtr := flag.Bool("mtimeArchives", false, "use modify timestamp instead of version timestamp for archives")
	name := flag.String("name", "auto", "replica name")
	configFile := flag.String("config", "config.txt", "path to config file")
	flag.Parse()
	util.SetDebug(*debugPtr)
	myfs.UseMtime = *mtimePtr

	util.P_out("main\n")

	pid := myfs.GetOurPid(*configFile, *name)
	replicas := myfs.ReadReplicaInfo(*configFile)
	thisReplica := replicas[pid]

	if thisReplica == nil {
		util.P_err("No applicable replica")
		os.Exit(1)
	}

	if *newfsPtr {
		os.RemoveAll(thisReplica.DbPath)
	}

	if _, err := os.Stat(thisReplica.MntPoint); os.IsNotExist(err) {
		os.MkdirAll(thisReplica.MntPoint, os.ModeDir)
	}

	db, err := myfs.NewLeveldbFsDatabase(thisReplica.DbPath)
	//db := &myfs.DummyFsDb{}
	//err := error(nil)
	if err != nil {
		util.P_err("Problem loading the database: ", err)
		os.Exit(-1)
	}
	filesystem := myfs.NewFs(db, thisReplica, replicas)
	go filesystem.PeriodicFlush()

	//mountpoint := flag.Arg(0)
	mountpoint := thisReplica.MntPoint

	fuse.Unmount(mountpoint) //!!
	c, err := fuse.Mount(mountpoint)
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()

	err = fs.Serve(c, filesystem)
	if err != nil {
		log.Fatal(err)
	}

	// check if the mount process has an error to report
	<-c.Ready
	if err := c.MountError; err != nil {
		log.Fatal(err)
	}
}
Example #29
0
func main() {
	flag.Parse()
	if flag.NArg() != 0 {
		os.Stderr.WriteString("one does not simply pass positional args\n")
		os.Exit(2)
	}
	if *mountDir == "" {
		os.Stderr.WriteString("y u no specify mountpoint?\n")
		os.Exit(2)
	}
	log.SetFlags(log.LstdFlags | log.Lshortfile)
	conn, err := fuse.Mount(*mountDir)
	if err != nil {
		log.Fatal(err)
	}
	defer fuse.Unmount(*mountDir)
	// TODO: Think about the ramifications of exiting not due to a signal.
	defer conn.Close()
	client, err := torrent.NewClient(&torrent.Config{
		DataDir:         *downloadDir,
		DisableTrackers: *disableTrackers,
		ListenAddr:      *listenAddr,
		NoUpload:        true, // Ensure that downloads are responsive.
	})
	if err != nil {
		log.Fatal(err)
	}
	// This is naturally exported via GOPPROF=http.
	http.DefaultServeMux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		client.WriteStatus(w)
	})
	dw, err := dirwatch.New(*torrentPath)
	if err != nil {
		log.Fatal(err)
	}
	go func() {
		for ev := range dw.Events {
			switch ev.Change {
			case dirwatch.Added:
				if ev.TorrentFilePath != "" {
					_, err := client.AddTorrentFromFile(ev.TorrentFilePath)
					if err != nil {
						log.Printf("error adding torrent to client: %s", err)
					}
				} else if ev.MagnetURI != "" {
					_, err := client.AddMagnet(ev.MagnetURI)
					if err != nil {
						log.Printf("error adding magnet: %s", err)
					}
				}
			case dirwatch.Removed:
				T, ok := client.Torrent(ev.InfoHash)
				if !ok {
					break
				}
				T.Drop()
			}
		}
	}()
	resolveTestPeerAddr()
	fs := torrentfs.New(client)
	go exitSignalHandlers(fs)
	go func() {
		for {
			addTestPeer(client)
			time.Sleep(10 * time.Second)
		}
	}()

	if err := fusefs.Serve(conn, fs); err != nil {
		log.Fatal(err)
	}
	<-conn.Ready
	if err := conn.MountError; err != nil {
		log.Fatal(err)
	}
}
Example #30
0
func (cmd CmdMount) Execute(args []string) error {
	if len(args) == 0 {
		return fmt.Errorf("wrong number of parameters, Usage: %s", cmd.Usage())
	}

	repo, err := cmd.global.OpenRepository()
	if err != nil {
		return err
	}

	err = repo.LoadIndex()
	if err != nil {
		return err
	}

	mountpoint := args[0]
	if _, err := os.Stat(mountpoint); os.IsNotExist(err) {
		cmd.global.Verbosef("Mountpoint %s doesn't exist, creating it\n", mountpoint)
		err = os.Mkdir(mountpoint, os.ModeDir|0700)
		if err != nil {
			return err
		}
	}
	c, err := systemFuse.Mount(
		mountpoint,
		systemFuse.ReadOnly(),
		systemFuse.FSName("restic"),
	)
	if err != nil {
		return err
	}

	root := fs.Tree{}
	root.Add("snapshots", fuse.NewSnapshotsDir(repo, cmd.Root))

	cmd.global.Printf("Now serving %s at %s\n", repo.Backend().Location(), mountpoint)
	cmd.global.Printf("Don't forget to umount after quitting!\n")

	AddCleanupHandler(func() error {
		return systemFuse.Unmount(mountpoint)
	})

	cmd.ready <- struct{}{}

	errServe := make(chan error)
	go func() {
		err = fs.Serve(c, &root)
		if err != nil {
			errServe <- err
		}

		<-c.Ready
		errServe <- c.MountError
	}()

	select {
	case err := <-errServe:
		return err
	case <-cmd.done:
		err := c.Close()
		if err != nil {
			cmd.global.Printf("Error closing fuse connection: %s\n", err)
		}
		return systemFuse.Unmount(mountpoint)
	}
}