main.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // +build linux
  2. package main
  3. //go:generate go run cmd/genversion/main.go -package main -out version.go
  4. import (
  5. "context"
  6. "flag"
  7. "fmt"
  8. "os"
  9. "strconv"
  10. "strings"
  11. "os/exec"
  12. "os/signal"
  13. "runtime"
  14. "syscall"
  15. "dev.hexasoftware.com/hxs/cloudmount/core"
  16. "github.com/jacobsa/fuse"
  17. "github.com/jacobsa/fuse/fuseutil"
  18. "dev.hexasoftware.com/hxs/prettylog"
  19. _ "dev.hexasoftware.com/hxs/cloudmount/fs/gdrivefs"
  20. //_ "github.com/icattlecoder/godaemon" // No reason
  21. )
  22. var (
  23. Name = "cloudmount"
  24. log = prettylog.New("main")
  25. )
  26. func main() {
  27. var daemonizeFlag bool
  28. var verboselogFlag bool
  29. var clouddriveFlag string
  30. var mountoptsFlag string
  31. prettylog.Global()
  32. // getClient
  33. fmt.Printf("%s-%s\n\n", Name, Version)
  34. flag.StringVar(&clouddriveFlag, "t", "gdrive", "which cloud service to use [gdrive]")
  35. flag.StringVar(&mountoptsFlag, "o", "", "-o [opts] uid,gid")
  36. flag.BoolVar(&daemonizeFlag, "d", false, "Run app in background")
  37. flag.BoolVar(&verboselogFlag, "v", false, "Verbose log")
  38. flag.Usage = func() {
  39. fmt.Fprintf(os.Stderr, "Usage: %s [options] MOUNTPOINT\n\n", os.Args[0])
  40. fmt.Fprintf(os.Stderr, "Options:\n")
  41. flag.PrintDefaults()
  42. fmt.Fprintf(os.Stderr, "\n")
  43. }
  44. flag.Parse()
  45. if len(flag.Args()) < 1 {
  46. flag.Usage()
  47. //fmt.Println("Usage:\n gdrivemount [-d] [-v] MOUNTPOINT")
  48. return
  49. }
  50. /////////////////////////////////////
  51. // Parse mount opts
  52. /////////////////
  53. pmountopts := strings.Split(mountoptsFlag, ",")
  54. mountopts := map[string]string{}
  55. for _, v := range pmountopts {
  56. keypart := strings.Split(v, "=")
  57. if len(keypart) != 2 {
  58. continue
  59. }
  60. mountopts[keypart[0]] = keypart[1]
  61. }
  62. /////////////////////////////////////
  63. // Use mount opts
  64. ///////////////
  65. uidStr, ok := mountopts["uid"]
  66. if ok {
  67. uid, err := strconv.Atoi(uidStr)
  68. if err != nil {
  69. panic(err)
  70. }
  71. core.Config.UID = uint32(uid)
  72. }
  73. ///////////////////////////////
  74. // cloud drive Type
  75. /////////////////
  76. f, ok := core.Drivers[clouddriveFlag] // there can be some interaction before daemon
  77. if !ok {
  78. log.Fatal("FileSystem not supported")
  79. }
  80. driveFS := f()
  81. ////////////////////////////////
  82. // Daemon
  83. /////////////////
  84. if daemonizeFlag {
  85. subArgs := []string{}
  86. for _, arg := range os.Args[1:] {
  87. if arg == "-d" { // ignore daemon flag
  88. continue
  89. }
  90. subArgs = append(subArgs, arg)
  91. }
  92. cmd := exec.Command(os.Args[0], subArgs...)
  93. cmd.Start()
  94. fmt.Println("[PID]", cmd.Process.Pid)
  95. os.Exit(0)
  96. return
  97. }
  98. //////////////
  99. // Server
  100. /////////
  101. ctx := context.Background()
  102. server := fuseutil.NewFileSystemServer(driveFS)
  103. mountPath := flag.Arg(0)
  104. var err error
  105. var mfs *fuse.MountedFileSystem
  106. if verboselogFlag {
  107. mfs, err = fuse.Mount(mountPath, server, &fuse.MountConfig{DebugLogger: prettylog.New("fuse"), ErrorLogger: prettylog.New("fuse-err")})
  108. } else {
  109. mfs, err = fuse.Mount(mountPath, server, &fuse.MountConfig{})
  110. }
  111. if err != nil {
  112. log.Fatal("Failed mounting path", flag.Arg(0))
  113. }
  114. // Signal handling to refresh Drives
  115. sigs := make(chan os.Signal, 2)
  116. signal.Notify(sigs, syscall.SIGUSR1, syscall.SIGHUP, syscall.SIGINT, os.Interrupt, syscall.SIGTERM)
  117. go func() {
  118. for sig := range sigs {
  119. log.Println("Signal:", sig)
  120. switch sig {
  121. case syscall.SIGUSR1:
  122. log.Println("Manually Refresh drive")
  123. go driveFS.Refresh()
  124. case syscall.SIGHUP:
  125. log.Println("GC")
  126. mem := runtime.MemStats{}
  127. runtime.ReadMemStats(&mem)
  128. log.Printf("Mem: %.2fMB", float64(mem.Alloc)/1024/1024)
  129. runtime.GC()
  130. runtime.ReadMemStats(&mem)
  131. log.Printf("After gc: Mem: %.2fMB", float64(mem.Alloc)/1024/1024)
  132. case os.Interrupt:
  133. log.Println("Graceful unmount")
  134. fuse.Unmount(mountPath)
  135. os.Exit(1)
  136. case syscall.SIGTERM:
  137. log.Println("Graceful unmount")
  138. fuse.Unmount(mountPath)
  139. os.Exit(1)
  140. }
  141. }
  142. }()
  143. if err := mfs.Join(ctx); err != nil {
  144. log.Fatalf("Joining: %v", err)
  145. }
  146. }