rclone/cmd/nfsmount/nfsmount.go

70 lines
1.9 KiB
Go
Raw Normal View History

//go:build darwin && !cmount
// +build darwin,!cmount
// Package nfsmount implements mounting functionality using serve nfs command
//
// NFS mount is only needed for macOS since it has no
// support for FUSE-based file systems
package nfsmount
import (
"context"
"fmt"
"net"
"os/exec"
"runtime"
"strings"
"github.com/rclone/rclone/cmd/mountlib"
"github.com/rclone/rclone/cmd/serve/nfs"
"github.com/rclone/rclone/vfs"
)
func init() {
cmd := mountlib.NewMountCommand("mount", false, mount)
cmd.Aliases = append(cmd.Aliases, "nfsmount")
mountlib.AddRc("nfsmount", mount)
}
func mount(VFS *vfs.VFS, mountpoint string, opt *mountlib.Options) (asyncerrors <-chan error, unmount func() error, err error) {
s, err := nfs.NewServer(context.Background(), VFS, &nfs.Options{})
if err != nil {
return
}
errChan := make(chan error, 1)
go func() {
errChan <- s.Serve()
}()
// The port is always picked at random after the NFS server has started
// we need to query the server for the port number so we can mount it
_, port, err := net.SplitHostPort(s.Addr().String())
if err != nil {
err = fmt.Errorf("cannot find port number in %s", s.Addr().String())
return
}
optionsString := strings.Join(opt.ExtraOptions, ",")
err = exec.Command("mount", fmt.Sprintf("-oport=%s,mountport=%s,%s", port, port, optionsString), "localhost:", mountpoint).Run()
if err != nil {
err = fmt.Errorf("failed to mount NFS volume %e", err)
return
}
asyncerrors = errChan
unmount = func() error {
var umountErr error
if runtime.GOOS == "darwin" {
umountErr = exec.Command("diskutil", "umount", "force", mountpoint).Run()
} else {
umountErr = exec.Command("umount", "-f", mountpoint).Run()
}
shutdownErr := s.Shutdown()
VFS.Shutdown()
if umountErr != nil {
return fmt.Errorf("failed to umount the NFS volume %e", umountErr)
} else if shutdownErr != nil {
return fmt.Errorf("failed to shutdown NFS server: %e", shutdownErr)
}
return nil
}
return
}