Skip to content

Commit 2dd3897

Browse files
authored
Windows: add option to startup juicefs as system service. fix juicedata#347, link juicedata#1546 (juicedata#5643)
1 parent 61fc5d9 commit 2dd3897

File tree

3 files changed

+78
-2
lines changed

3 files changed

+78
-2
lines changed

cmd/mount.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,9 @@ func mount(c *cli.Context) error {
676676
}
677677
os.Setenv("JFS_SUPERVISOR", strconv.Itoa(os.Getppid()))
678678
return launchMount(mp, vfsConf)
679+
} else if runtime.GOOS == "windows" && c.Bool("background") {
680+
daemonRun(c, addr, vfsConf)
681+
return nil
679682
}
680683
logger.Infof("JuiceFS version %s", version.Version())
681684

cmd/mount_windows.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,16 @@ func mountFlags() []cli.Flag {
4747
Name: "delay-close",
4848
Usage: "delay file closing in seconds.",
4949
},
50+
&cli.BoolFlag{
51+
Name: "d",
52+
Aliases: []string{"background"},
53+
Usage: "run in background(Windows: as a system service. support ONLY 1 volume mounting at the same time)",
54+
},
5055
}
5156
}
5257

5358
func makeDaemon(c *cli.Context, conf *vfs.Config) error {
54-
logger.Warnf("Cannot run in background in Windows.")
55-
return nil
59+
return winfsp.RunAsSystemSerivce(conf.Format.Name, c.Args().Get(1))
5660
}
5761

5862
func makeDaemonForSvc(c *cli.Context, m meta.Meta, metaUrl, listenAddr string) error {

pkg/winfsp/winfs.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ package winfsp
2222
import (
2323
"fmt"
2424
"os"
25+
"os/exec"
2526
"path"
2627
"runtime"
2728
"strings"
@@ -35,6 +36,8 @@ import (
3536
"github.com/juicedata/juicefs/pkg/meta"
3637
"github.com/juicedata/juicefs/pkg/utils"
3738
"github.com/juicedata/juicefs/pkg/vfs"
39+
40+
"golang.org/x/sys/windows/registry"
3841
)
3942

4043
var logger = utils.GetLogger("juicefs")
@@ -669,3 +672,69 @@ func Serve(v *vfs.VFS, fuseOpt string, fileCacheTo float64, asRoot bool, delayCl
669672
logger.Debugf("mount point: %s, options: %s", conf.Meta.MountPoint, options)
670673
_ = host.Mount(conf.Meta.MountPoint, []string{"-o", options})
671674
}
675+
676+
func RunAsSystemSerivce(name string, mountpoint string) error {
677+
// https://winfsp.dev/doc/WinFsp-Service-Architecture/
678+
logger.Info("Running as Windows system service.")
679+
680+
var cmds []string
681+
for _, v := range os.Args[1:] {
682+
if v == "-d" || v == "--background" {
683+
continue
684+
}
685+
cmds = append(cmds, v)
686+
}
687+
688+
cmdLine := strings.Join(cmds, " ")
689+
690+
regKeyPath := "SOFTWARE\\WOW6432Node\\WinFsp\\Services\\juicefs"
691+
k, err := registry.OpenKey(registry.LOCAL_MACHINE, regKeyPath, registry.ALL_ACCESS)
692+
if err != nil {
693+
if err == syscall.ERROR_FILE_NOT_FOUND || err == syscall.ERROR_PATH_NOT_FOUND {
694+
logger.Info("Registry key not found, create it")
695+
k, _, err = registry.CreateKey(registry.LOCAL_MACHINE, regKeyPath, registry.ALL_ACCESS)
696+
if err != nil {
697+
return fmt.Errorf("Failed to create registry key: %s", err)
698+
}
699+
} else {
700+
return fmt.Errorf("Failed to open registry key: %s", err)
701+
}
702+
}
703+
defer k.Close()
704+
705+
err = k.SetStringValue("CommandLine", cmdLine)
706+
if err != nil {
707+
return fmt.Errorf("Failed to set registry key: %s", err)
708+
}
709+
710+
securityDescriptor := "D:P(A;;RPWPLC;;;WD)"
711+
err = k.SetStringValue("Security", securityDescriptor)
712+
if err != nil {
713+
return fmt.Errorf("Failed to set registry key: %s", err)
714+
}
715+
716+
filePath, err := os.Executable()
717+
if err != nil {
718+
return fmt.Errorf("Failed to get current file path: %s", err)
719+
}
720+
721+
err = k.SetStringValue("Executable", filePath)
722+
if err != nil {
723+
return fmt.Errorf("Failed to set registry key: %s", err)
724+
}
725+
726+
err = k.SetDWordValue("JobControl", 1)
727+
if err != nil {
728+
return fmt.Errorf("Failed to set registry key: %s", err)
729+
}
730+
731+
logger.Debug("Starting juicefs service.")
732+
cmd := exec.Command("net", "use", mountpoint, "\\\\juicefs\\"+name)
733+
err = cmd.Run()
734+
if err != nil {
735+
return fmt.Errorf("Failed to mount juicefs: %s", err)
736+
}
737+
738+
logger.Info("Juicefs system service started successfully.")
739+
return nil
740+
}

0 commit comments

Comments
 (0)