123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- package command
- import (
- "fmt"
- "os"
- "strconv"
- "strings"
- "time"
- )
- func init() {
- cmdFuse.Run = runFuse // break init cycle
- }
- type parameter struct {
- name string
- value string
- }
- func runFuse(cmd *Command, args []string) bool {
- rawArgs := strings.Join(args, " ")
- rawArgsLen := len(rawArgs)
- option := strings.Builder{}
- options := []parameter{}
- masterProcess := true
- fusermountPath := ""
- // first parameter
- i := 0
- for i = 0; i < rawArgsLen && rawArgs[i] != ' '; i++ {
- option.WriteByte(rawArgs[i])
- }
- options = append(options, parameter{"arg0", option.String()})
- option.Reset()
- for i++; i < rawArgsLen; i++ {
- // space separator check for filled option
- if rawArgs[i] == ' ' {
- if option.Len() > 0 {
- options = append(options, parameter{option.String(), "true"})
- option.Reset()
- }
- // dash separator read option until next space
- } else if rawArgs[i] == '-' {
- for i++; i < rawArgsLen && rawArgs[i] != ' '; i++ {
- option.WriteByte(rawArgs[i])
- }
- // ignore "-o"
- if option.String() != "o" {
- options = append(options, parameter{option.String(), "true"})
- }
- option.Reset()
- // equal separator start option with pending value
- } else if rawArgs[i] == '=' {
- name := option.String()
- option.Reset()
- for i++; i < rawArgsLen && rawArgs[i] != ',' && rawArgs[i] != ' '; i++ {
- // double quote separator read option until next double quote
- if rawArgs[i] == '"' {
- for i++; i < rawArgsLen && rawArgs[i] != '"'; i++ {
- option.WriteByte(rawArgs[i])
- }
- // single quote separator read option until next single quote
- } else if rawArgs[i] == '\'' {
- for i++; i < rawArgsLen && rawArgs[i] != '\''; i++ {
- option.WriteByte(rawArgs[i])
- }
- // add chars before comma
- } else if rawArgs[i] != ' ' {
- option.WriteByte(rawArgs[i])
- }
- }
- options = append(options, parameter{name, option.String()})
- option.Reset()
- // comma separator just read current option
- } else if rawArgs[i] == ',' {
- options = append(options, parameter{option.String(), "true"})
- option.Reset()
- // what is not a separator fill option buffer
- } else {
- option.WriteByte(rawArgs[i])
- }
- }
- // get residual option data
- if option.Len() > 0 {
- // add value to pending option
- options = append(options, parameter{option.String(), "true"})
- option.Reset()
- }
- // scan each parameter
- for i := 0; i < len(options); i++ {
- parameter := options[i]
- switch parameter.name {
- case "child":
- masterProcess = false
- case "arg0":
- mountOptions.dir = ¶meter.value
- case "filer":
- mountOptions.filer = ¶meter.value
- case "filer.path":
- mountOptions.filerMountRootPath = ¶meter.value
- case "dirAutoCreate":
- if parsed, err := strconv.ParseBool(parameter.value); err == nil {
- mountOptions.dirAutoCreate = &parsed
- } else {
- panic(fmt.Errorf("dirAutoCreate: %s", err))
- }
- case "collection":
- mountOptions.collection = ¶meter.value
- case "replication":
- mountOptions.replication = ¶meter.value
- case "disk":
- mountOptions.diskType = ¶meter.value
- case "ttl":
- if parsed, err := strconv.ParseInt(parameter.value, 0, 32); err == nil {
- intValue := int(parsed)
- mountOptions.ttlSec = &intValue
- } else {
- panic(fmt.Errorf("ttl: %s", err))
- }
- case "chunkSizeLimitMB":
- if parsed, err := strconv.ParseInt(parameter.value, 0, 32); err == nil {
- intValue := int(parsed)
- mountOptions.chunkSizeLimitMB = &intValue
- } else {
- panic(fmt.Errorf("chunkSizeLimitMB: %s", err))
- }
- case "concurrentWriters":
- i++
- if parsed, err := strconv.ParseInt(parameter.value, 0, 32); err == nil {
- intValue := int(parsed)
- mountOptions.concurrentWriters = &intValue
- } else {
- panic(fmt.Errorf("concurrentWriters: %s", err))
- }
- case "cacheDir":
- mountOptions.cacheDirForRead = ¶meter.value
- case "cacheCapacityMB":
- if parsed, err := strconv.ParseInt(parameter.value, 0, 64); err == nil {
- mountOptions.cacheSizeMBForRead = &parsed
- } else {
- panic(fmt.Errorf("cacheCapacityMB: %s", err))
- }
- case "cacheDirWrite":
- mountOptions.cacheDirForWrite = ¶meter.value
- case "dataCenter":
- mountOptions.dataCenter = ¶meter.value
- case "allowOthers":
- if parsed, err := strconv.ParseBool(parameter.value); err == nil {
- mountOptions.allowOthers = &parsed
- } else {
- panic(fmt.Errorf("allowOthers: %s", err))
- }
- case "umask":
- mountOptions.umaskString = ¶meter.value
- case "nonempty":
- if parsed, err := strconv.ParseBool(parameter.value); err == nil {
- mountOptions.nonempty = &parsed
- } else {
- panic(fmt.Errorf("nonempty: %s", err))
- }
- case "volumeServerAccess":
- mountOptions.volumeServerAccess = ¶meter.value
- case "map.uid":
- mountOptions.uidMap = ¶meter.value
- case "map.gid":
- mountOptions.gidMap = ¶meter.value
- case "readOnly":
- if parsed, err := strconv.ParseBool(parameter.value); err == nil {
- mountOptions.readOnly = &parsed
- } else {
- panic(fmt.Errorf("readOnly: %s", err))
- }
- case "cpuprofile":
- mountCpuProfile = ¶meter.value
- case "memprofile":
- mountMemProfile = ¶meter.value
- case "readRetryTime":
- if parsed, err := time.ParseDuration(parameter.value); err == nil {
- mountReadRetryTime = &parsed
- } else {
- panic(fmt.Errorf("readRetryTime: %s", err))
- }
- case "fusermount.path":
- fusermountPath = parameter.value
- default:
- t := parameter.name
- if parameter.value != "true" {
- t = fmt.Sprintf("%s=%s", parameter.name, parameter.value)
- }
- mountOptions.extraOptions = append(mountOptions.extraOptions, t)
- }
- }
- // the master start the child, release it then finish himself
- if masterProcess {
- arg0, err := os.Executable()
- if err != nil {
- panic(err)
- }
- argv := append(os.Args, "-o", "child")
- attr := os.ProcAttr{}
- attr.Env = os.Environ()
- child, err := os.StartProcess(arg0, argv, &attr)
- if err != nil {
- panic(fmt.Errorf("master process can not start child process: %s", err))
- }
- err = child.Release()
- if err != nil {
- panic(fmt.Errorf("master process can not release child process: %s", err))
- }
- return true
- }
- if fusermountPath != "" {
- if err := os.Setenv("PATH", fusermountPath); err != nil {
- panic(fmt.Errorf("setenv: %s", err))
- }
- } else if os.Getenv("PATH") == "" {
- if err := os.Setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin"); err != nil {
- panic(fmt.Errorf("setenv: %s", err))
- }
- }
- // just call "weed mount" command
- return runMount(cmdMount, []string{})
- }
- var cmdFuse = &Command{
- UsageLine: "fuse /mnt/mount/point -o \"filer=localhost:8888,filer.path=/\"",
- Short: "Allow use weed with linux's mount command",
- Long: `Allow use weed with linux's mount command
- You can use -t weed on mount command:
- mv weed /sbin/mount.weed
- mount -t weed fuse /mnt -o "filer=localhost:8888,filer.path=/"
- Or you can use -t fuse on mount command:
- mv weed /sbin/weed
- mount -t fuse.weed fuse /mnt -o "filer=localhost:8888,filer.path=/"
- mount -t fuse "weed#fuse" /mnt -o "filer=localhost:8888,filer.path=/"
- To use without mess with your /sbin:
- mount -t fuse./home/user/bin/weed fuse /mnt -o "filer=localhost:8888,filer.path=/"
- mount -t fuse "/home/user/bin/weed#fuse" /mnt -o "filer=localhost:8888,filer.path=/"
- To pass more than one parameter use quotes, example:
- mount -t weed fuse /mnt -o "filer='192.168.0.1:8888,192.168.0.2:8888',filer.path=/"
- To check valid options look "weed mount --help"
- `,
- }
|