Example #1
0
File: fs.go Project: ncw/rclone
// mountOptions configures the options from the command line flags
func mountOptions(device string) (options []fuse.MountOption) {
	options = []fuse.MountOption{
		fuse.MaxReadahead(uint32(maxReadAhead)),
		fuse.Subtype("rclone"),
		fuse.FSName(device), fuse.VolumeName(device),
		fuse.NoAppleDouble(),
		fuse.NoAppleXattr(),

		// Options from benchmarking in the fuse module
		//fuse.MaxReadahead(64 * 1024 * 1024),
		//fuse.AsyncRead(), - FIXME this causes
		// ReadFileHandle.Read error: read /home/files/ISOs/xubuntu-15.10-desktop-amd64.iso: bad file descriptor
		// which is probably related to errors people are having
		//fuse.WritebackCache(),
	}
	if allowNonEmpty {
		options = append(options, fuse.AllowNonEmptyMount())
	}
	if allowOther {
		options = append(options, fuse.AllowOther())
	}
	if allowRoot {
		options = append(options, fuse.AllowRoot())
	}
	if defaultPermissions {
		options = append(options, fuse.DefaultPermissions())
	}
	if readOnly {
		options = append(options, fuse.ReadOnly())
	}
	if writebackCache {
		options = append(options, fuse.WritebackCache())
	}
	return options
}
Example #2
0
func main() {
	allowOther := flag.Bool("allow-other", false, "allow all users access to the filesystem")
	allowRoot := flag.Bool("allow-root", false, "allow root to access the filesystem")
	debug := flag.Bool("debug", false, "enable debug output")
	gid := flag.Int("gid", os.Getgid(), "set the GID that should own all files")
	perm := flag.Int("perm", 0, "set the file permission flags for all files")
	ro := flag.Bool("ro", false, "mount the filesystem read-only")
	root := flag.String("root", "", "path in Consul to the root of the filesystem")
	timeout := flag.String("timeout", defaultTimeout, "timeout for Consul requests")
	uid := flag.Int("uid", os.Getuid(), "set the UID that should own all files")
	flag.Parse()

	logger := logrus.New()
	if *debug {
		logger.Level = logrus.DebugLevel
	}

	consulConfig := &consul.Config{}
	var mountPoint string
	switch flag.NArg() {
	case 1:
		mountPoint = flag.Arg(0)
	case 2:
		consulConfig.Address = flag.Arg(0)
		mountPoint = flag.Arg(1)
	default:
		flag.Usage()
	}

	// Initialize a Consul client. TODO: connection parameters
	client, err := consul.NewClient(consulConfig)
	if err != nil {
		logrus.NewEntry(logger).WithError(err).Error("could not initialize consul")
		os.Exit(1)
	}

	// Configure some mount options
	timeoutDuration, err := time.ParseDuration(*timeout)
	if err != nil {
		logrus.NewEntry(logger).WithError(err).Fatal("invalid -timeout value")
	}
	mountOptions := []fuse.MountOption{
		fuse.DefaultPermissions(),
		fuse.DaemonTimeout(fmt.Sprint(int64(timeoutDuration.Seconds() + 1))),
		fuse.NoAppleDouble(),
		fuse.NoAppleXattr(),
	}
	if *allowOther {
		mountOptions = append(mountOptions, fuse.AllowOther())
	}
	if *allowRoot {
		mountOptions = append(mountOptions, fuse.AllowRoot())
	}
	if *ro {
		mountOptions = append(mountOptions, fuse.ReadOnly())
	}

	// Mount the file system to start receiving FS events at the mount point.
	logger.WithField("location", mountPoint).Info("mounting kvfs")
	conn, err := fuse.Mount(mountPoint, mountOptions...)
	if err != nil {
		logrus.NewEntry(logger).WithError(err).Fatal("error mounting kvfs")
	}
	defer conn.Close()

	// Try to cleanly unmount the FS if SIGINT or SIGTERM is received
	sigs := make(chan os.Signal, 10)
	signal.Notify(sigs, os.Interrupt, syscall.SIGTERM)
	go func() {
		for sig := range sigs {
			logger.WithField("signal", sig).Info("attempting to unmount")
			err := fuse.Unmount(mountPoint)
			if err != nil {
				logrus.NewEntry(logger).WithError(err).Error("cannot unmount")
			}
		}
	}()

	// Create a file system object and start handing its requests
	server := fs.New(conn, &fs.Config{
		Debug: func(m interface{}) { logger.Debug(m) },
		WithContext: func(ctx context.Context, req fuse.Request) context.Context {
			// The returned cancel function doesn't matter: the request handler will
			// cancel the parent context at the end of the request.
			newCtx, _ := context.WithTimeout(ctx, timeoutDuration)
			return newCtx
		},
	})
	f := &consulfs.ConsulFS{
		Consul: &consulfs.CancelConsulKV{
			Client: client,
			Logger: logger,
		},
		Logger:   logger,
		UID:      uint32(*uid),
		GID:      uint32(*gid),
		Perms:    os.FileMode(*perm),
		RootPath: *root,
	}
	err = server.Serve(f)
	if err != nil {
		// Not sure what would cause Serve() to exit with an error
		logrus.NewEntry(logger).WithError(err).Error("error serving filesystem")
	}

	// Wait for the FUSE connection to end
	<-conn.Ready
	if conn.MountError != nil {
		logrus.NewEntry(logger).WithError(conn.MountError).Error("unmount error")
		os.Exit(1)
	} else {
		logger.Info("file system exiting normally")
	}
}