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.

222 lines
6.2 KiB

  1. package command
  2. import (
  3. "fmt"
  4. "strings"
  5. "strconv"
  6. "time"
  7. "os"
  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. // first parameter
  22. i := 0
  23. for i = 0; i < rawArgsLen && rawArgs[i] != ' '; i++ {
  24. option.WriteByte(rawArgs[i])
  25. }
  26. options = append(options, parameter{"arg0", option.String()})
  27. option.Reset()
  28. for i++; i < rawArgsLen; i++ {
  29. // space separator check for filled option
  30. if rawArgs[i] == ' ' {
  31. if option.Len() > 0 {
  32. options = append(options, parameter{option.String(), "true"})
  33. option.Reset()
  34. }
  35. // dash separator read option until next space
  36. } else if rawArgs[i] == '-' {
  37. for i++; i < rawArgsLen && rawArgs[i] != ' '; i++ {
  38. option.WriteByte(rawArgs[i])
  39. }
  40. options = append(options, parameter{option.String(), "true"})
  41. option.Reset()
  42. // equal separator start option with pending value
  43. } else if rawArgs[i] == '=' {
  44. name := option.String()
  45. option.Reset()
  46. for i++; i < rawArgsLen && rawArgs[i] != ','; i++ {
  47. // double quote separator read option until next double quote
  48. if rawArgs[i] == '"' {
  49. for i++; i < rawArgsLen && rawArgs[i] != '"'; i++ {
  50. option.WriteByte(rawArgs[i])
  51. }
  52. // single quote separator read option until next single quote
  53. } else if rawArgs[i] == '\'' {
  54. for i++; i < rawArgsLen && rawArgs[i] != '\''; i++ {
  55. option.WriteByte(rawArgs[i])
  56. }
  57. // add chars before comma
  58. } else if rawArgs[i] != ' ' {
  59. option.WriteByte(rawArgs[i])
  60. }
  61. }
  62. options = append(options, parameter{name, option.String()})
  63. option.Reset()
  64. // comma separator just read current option
  65. } else if rawArgs[i] == ',' {
  66. options = append(options, parameter{option.String(), "true"})
  67. option.Reset()
  68. // what is not a separator fill option buffer
  69. } else {
  70. option.WriteByte(rawArgs[i])
  71. }
  72. }
  73. // get residual option data
  74. if option.Len() > 0 {
  75. // add value to pending option
  76. options = append(options, parameter{option.String(), "true"})
  77. option.Reset()
  78. }
  79. // scan each parameter
  80. for i := 0; i < len(options); i++ {
  81. parameter := options[i]
  82. switch parameter.name {
  83. case "arg0":
  84. mountOptions.dir = &parameter.value
  85. case "filer":
  86. mountOptions.filer = &parameter.value
  87. case "filer.path":
  88. mountOptions.filerMountRootPath = &parameter.value
  89. case "dirAutoCreate":
  90. if parsed, err := strconv.ParseBool(parameter.value); err != nil {
  91. mountOptions.dirAutoCreate = &parsed
  92. } else {
  93. panic(fmt.Errorf("dirAutoCreate: %s", err))
  94. }
  95. case "collection":
  96. mountOptions.collection = &parameter.value
  97. case "replication":
  98. mountOptions.replication = &parameter.value
  99. case "disk":
  100. mountOptions.diskType = &parameter.value
  101. case "ttl":
  102. if parsed, err := strconv.ParseInt(parameter.value, 0, 32); err != nil {
  103. intValue := int(parsed)
  104. mountOptions.ttlSec = &intValue
  105. } else {
  106. panic(fmt.Errorf("ttl: %s", err))
  107. }
  108. case "chunkSizeLimitMB":
  109. if parsed, err := strconv.ParseInt(parameter.value, 0, 32); err != nil {
  110. intValue := int(parsed)
  111. mountOptions.chunkSizeLimitMB = &intValue
  112. } else {
  113. panic(fmt.Errorf("chunkSizeLimitMB: %s", err))
  114. }
  115. case "concurrentWriters":
  116. i++
  117. if parsed, err := strconv.ParseInt(parameter.value, 0, 32); err != nil {
  118. intValue := int(parsed)
  119. mountOptions.concurrentWriters = &intValue
  120. } else {
  121. panic(fmt.Errorf("concurrentWriters: %s", err))
  122. }
  123. case "cacheDir":
  124. mountOptions.cacheDir = &parameter.value
  125. case "cacheCapacityMB":
  126. if parsed, err := strconv.ParseInt(parameter.value, 0, 64); err != nil {
  127. mountOptions.cacheSizeMB = &parsed
  128. } else {
  129. panic(fmt.Errorf("cacheCapacityMB: %s", err))
  130. }
  131. case "dataCenter":
  132. mountOptions.dataCenter = &parameter.value
  133. case "allowOthers":
  134. if parsed, err := strconv.ParseBool(parameter.value); err != nil {
  135. mountOptions.allowOthers = &parsed
  136. } else {
  137. panic(fmt.Errorf("allowOthers: %s", err))
  138. }
  139. case "umask":
  140. mountOptions.umaskString = &parameter.value
  141. case "nonempty":
  142. if parsed, err := strconv.ParseBool(parameter.value); err != nil {
  143. mountOptions.nonempty = &parsed
  144. } else {
  145. panic(fmt.Errorf("nonempty: %s", err))
  146. }
  147. case "volumeServerAccess":
  148. mountOptions.volumeServerAccess = &parameter.value
  149. case "map.uid":
  150. mountOptions.uidMap = &parameter.value
  151. case "map.gid":
  152. mountOptions.gidMap = &parameter.value
  153. case "readOnly":
  154. if parsed, err := strconv.ParseBool(parameter.value); err != nil {
  155. mountOptions.readOnly = &parsed
  156. } else {
  157. panic(fmt.Errorf("readOnly: %s", err))
  158. }
  159. case "cpuprofile":
  160. mountCpuProfile = &parameter.value
  161. case "memprofile":
  162. mountMemProfile = &parameter.value
  163. case "readRetryTime":
  164. if parsed, err := time.ParseDuration(parameter.value); err != nil {
  165. mountReadRetryTime = &parsed
  166. } else {
  167. panic(fmt.Errorf("readRetryTime: %s", err))
  168. }
  169. }
  170. }
  171. // I don't know why PATH environment variable is lost
  172. if err := os.Setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"); err != nil {
  173. panic(fmt.Errorf("setenv: %s", err))
  174. }
  175. // just call "weed mount" command
  176. return runMount(cmdMount, []string{})
  177. }
  178. var cmdFuse = &Command{
  179. UsageLine: "fuse /mnt/mount/point -o \"filer=localhost:8888,filer.path=/\"",
  180. Short: "Allow use weed with linux's mount command",
  181. Long: `Allow use weed with linux's mount command
  182. You can use -t weed on mount command:
  183. mv weed /sbin/mount.weed
  184. mount -t weed fuse /mnt -o "filer=localhost:8888,filer.path=/"
  185. Or you can use -t fuse on mount command:
  186. mv weed /sbin/weed
  187. mount -t fuse.weed fuse /mnt -o "filer=localhost:8888,filer.path=/"
  188. mount -t fuse "weed#fuse" /mnt -o "filer=localhost:8888,filer.path=/"
  189. To use without mess with your /sbin:
  190. mount -t fuse./home/user/bin/weed fuse /mnt -o "filer=localhost:8888,filer.path=/"
  191. mount -t fuse "/home/user/bin/weed#fuse" /mnt -o "filer=localhost:8888,filer.path=/"
  192. To pass more than one parameter use quotes, example:
  193. mount -t weed fuse /mnt -o "filer='192.168.0.1:8888,192.168.0.2:8888',filer.path=/"
  194. To check valid options look "weed mount --help"
  195. `,
  196. }