You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

269 lines
7.3 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. package command
  2. import (
  3. "fmt"
  4. "os"
  5. "strconv"
  6. "strings"
  7. "time"
  8. )
  9. func init() {
  10. cmdFuse.Run = runFuse // break init cycle
  11. }
  12. type parameter struct {
  13. name string
  14. value string
  15. }
  16. func runFuse(cmd *Command, args []string) bool {
  17. rawArgs := strings.Join(args, " ")
  18. rawArgsLen := len(rawArgs)
  19. option := strings.Builder{}
  20. options := []parameter{}
  21. masterProcess := true
  22. fusermountPath := ""
  23. // first parameter
  24. i := 0
  25. for i = 0; i < rawArgsLen && rawArgs[i] != ' '; i++ {
  26. option.WriteByte(rawArgs[i])
  27. }
  28. options = append(options, parameter{"arg0", option.String()})
  29. option.Reset()
  30. for i++; i < rawArgsLen; i++ {
  31. // space separator check for filled option
  32. if rawArgs[i] == ' ' {
  33. if option.Len() > 0 {
  34. options = append(options, parameter{option.String(), "true"})
  35. option.Reset()
  36. }
  37. // dash separator read option until next space
  38. } else if rawArgs[i] == '-' {
  39. for i++; i < rawArgsLen && rawArgs[i] != ' '; i++ {
  40. option.WriteByte(rawArgs[i])
  41. }
  42. // ignore "-o"
  43. if option.String() != "o" {
  44. options = append(options, parameter{option.String(), "true"})
  45. }
  46. option.Reset()
  47. // equal separator start option with pending value
  48. } else if rawArgs[i] == '=' {
  49. name := option.String()
  50. option.Reset()
  51. for i++; i < rawArgsLen && rawArgs[i] != ',' && rawArgs[i] != ' '; i++ {
  52. // double quote separator read option until next double quote
  53. if rawArgs[i] == '"' {
  54. for i++; i < rawArgsLen && rawArgs[i] != '"'; i++ {
  55. option.WriteByte(rawArgs[i])
  56. }
  57. // single quote separator read option until next single quote
  58. } else if rawArgs[i] == '\'' {
  59. for i++; i < rawArgsLen && rawArgs[i] != '\''; i++ {
  60. option.WriteByte(rawArgs[i])
  61. }
  62. // add chars before comma
  63. } else if rawArgs[i] != ' ' {
  64. option.WriteByte(rawArgs[i])
  65. }
  66. }
  67. options = append(options, parameter{name, option.String()})
  68. option.Reset()
  69. // comma separator just read current option
  70. } else if rawArgs[i] == ',' {
  71. options = append(options, parameter{option.String(), "true"})
  72. option.Reset()
  73. // what is not a separator fill option buffer
  74. } else {
  75. option.WriteByte(rawArgs[i])
  76. }
  77. }
  78. // get residual option data
  79. if option.Len() > 0 {
  80. // add value to pending option
  81. options = append(options, parameter{option.String(), "true"})
  82. option.Reset()
  83. }
  84. // scan each parameter
  85. for i := 0; i < len(options); i++ {
  86. parameter := options[i]
  87. switch parameter.name {
  88. case "child":
  89. masterProcess = false
  90. case "arg0":
  91. mountOptions.dir = &parameter.value
  92. case "filer":
  93. mountOptions.filer = &parameter.value
  94. case "filer.path":
  95. mountOptions.filerMountRootPath = &parameter.value
  96. case "dirAutoCreate":
  97. if parsed, err := strconv.ParseBool(parameter.value); err == nil {
  98. mountOptions.dirAutoCreate = &parsed
  99. } else {
  100. panic(fmt.Errorf("dirAutoCreate: %s", err))
  101. }
  102. case "collection":
  103. mountOptions.collection = &parameter.value
  104. case "replication":
  105. mountOptions.replication = &parameter.value
  106. case "disk":
  107. mountOptions.diskType = &parameter.value
  108. case "ttl":
  109. if parsed, err := strconv.ParseInt(parameter.value, 0, 32); err == nil {
  110. intValue := int(parsed)
  111. mountOptions.ttlSec = &intValue
  112. } else {
  113. panic(fmt.Errorf("ttl: %s", err))
  114. }
  115. case "chunkSizeLimitMB":
  116. if parsed, err := strconv.ParseInt(parameter.value, 0, 32); err == nil {
  117. intValue := int(parsed)
  118. mountOptions.chunkSizeLimitMB = &intValue
  119. } else {
  120. panic(fmt.Errorf("chunkSizeLimitMB: %s", err))
  121. }
  122. case "concurrentWriters":
  123. i++
  124. if parsed, err := strconv.ParseInt(parameter.value, 0, 32); err == nil {
  125. intValue := int(parsed)
  126. mountOptions.concurrentWriters = &intValue
  127. } else {
  128. panic(fmt.Errorf("concurrentWriters: %s", err))
  129. }
  130. case "cacheDir":
  131. mountOptions.cacheDir = &parameter.value
  132. case "cacheCapacityMB":
  133. if parsed, err := strconv.ParseInt(parameter.value, 0, 64); err == nil {
  134. mountOptions.cacheSizeMB = &parsed
  135. } else {
  136. panic(fmt.Errorf("cacheCapacityMB: %s", err))
  137. }
  138. case "dataCenter":
  139. mountOptions.dataCenter = &parameter.value
  140. case "allowOthers":
  141. if parsed, err := strconv.ParseBool(parameter.value); err == nil {
  142. mountOptions.allowOthers = &parsed
  143. } else {
  144. panic(fmt.Errorf("allowOthers: %s", err))
  145. }
  146. case "umask":
  147. mountOptions.umaskString = &parameter.value
  148. case "nonempty":
  149. if parsed, err := strconv.ParseBool(parameter.value); err == nil {
  150. mountOptions.nonempty = &parsed
  151. } else {
  152. panic(fmt.Errorf("nonempty: %s", err))
  153. }
  154. case "volumeServerAccess":
  155. mountOptions.volumeServerAccess = &parameter.value
  156. case "map.uid":
  157. mountOptions.uidMap = &parameter.value
  158. case "map.gid":
  159. mountOptions.gidMap = &parameter.value
  160. case "readOnly":
  161. if parsed, err := strconv.ParseBool(parameter.value); err == nil {
  162. mountOptions.readOnly = &parsed
  163. } else {
  164. panic(fmt.Errorf("readOnly: %s", err))
  165. }
  166. case "cpuprofile":
  167. mountCpuProfile = &parameter.value
  168. case "memprofile":
  169. mountMemProfile = &parameter.value
  170. case "readRetryTime":
  171. if parsed, err := time.ParseDuration(parameter.value); err == nil {
  172. mountReadRetryTime = &parsed
  173. } else {
  174. panic(fmt.Errorf("readRetryTime: %s", err))
  175. }
  176. case "fusermount.path":
  177. fusermountPath = parameter.value
  178. default:
  179. t := parameter.name
  180. if parameter.value != "true" {
  181. t = fmt.Sprintf("%s=%s", parameter.name, parameter.value)
  182. }
  183. mountOptions.extraOptions = append(mountOptions.extraOptions, t)
  184. }
  185. }
  186. // the master start the child, release it then finish himself
  187. if masterProcess {
  188. arg0, err := os.Executable()
  189. if err != nil {
  190. panic(err)
  191. }
  192. argv := append(os.Args, "-o", "child")
  193. attr := os.ProcAttr{}
  194. attr.Env = os.Environ()
  195. child, err := os.StartProcess(arg0, argv, &attr)
  196. if err != nil {
  197. panic(fmt.Errorf("master process can not start child process: %s", err))
  198. }
  199. err = child.Release()
  200. if err != nil {
  201. panic(fmt.Errorf("master process can not release child process: %s", err))
  202. }
  203. return true
  204. }
  205. if fusermountPath != "" {
  206. if err := os.Setenv("PATH", fusermountPath); err != nil {
  207. panic(fmt.Errorf("setenv: %s", err))
  208. }
  209. } else if os.Getenv("PATH") == "" {
  210. if err := os.Setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin"); err != nil {
  211. panic(fmt.Errorf("setenv: %s", err))
  212. }
  213. }
  214. // just call "weed mount" command
  215. return runMount(cmdMount, []string{})
  216. }
  217. var cmdFuse = &Command{
  218. UsageLine: "fuse /mnt/mount/point -o \"filer=localhost:8888,filer.path=/\"",
  219. Short: "Allow use weed with linux's mount command",
  220. Long: `Allow use weed with linux's mount command
  221. You can use -t weed on mount command:
  222. mv weed /sbin/mount.weed
  223. mount -t weed fuse /mnt -o "filer=localhost:8888,filer.path=/"
  224. Or you can use -t fuse on mount command:
  225. mv weed /sbin/weed
  226. mount -t fuse.weed fuse /mnt -o "filer=localhost:8888,filer.path=/"
  227. mount -t fuse "weed#fuse" /mnt -o "filer=localhost:8888,filer.path=/"
  228. To use without mess with your /sbin:
  229. mount -t fuse./home/user/bin/weed fuse /mnt -o "filer=localhost:8888,filer.path=/"
  230. mount -t fuse "/home/user/bin/weed#fuse" /mnt -o "filer=localhost:8888,filer.path=/"
  231. To pass more than one parameter use quotes, example:
  232. mount -t weed fuse /mnt -o "filer='192.168.0.1:8888,192.168.0.2:8888',filer.path=/"
  233. To check valid options look "weed mount --help"
  234. `,
  235. }