|
@ -12,124 +12,178 @@ func init() { |
|
|
cmdFuse.Run = runFuse // break init cycle
|
|
|
cmdFuse.Run = runFuse // break init cycle
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func runFuse(cmd *Command, args []string) bool { |
|
|
|
|
|
argsLen := len(args) |
|
|
|
|
|
options := []string{} |
|
|
|
|
|
|
|
|
type parameter struct { |
|
|
|
|
|
name string |
|
|
|
|
|
value string |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// at least target mount path should be passed
|
|
|
|
|
|
if argsLen < 1 { |
|
|
|
|
|
return false |
|
|
|
|
|
|
|
|
func runFuse(cmd *Command, args []string) bool { |
|
|
|
|
|
rawArgs := strings.Join(args, " ") |
|
|
|
|
|
rawArgsLen := len(rawArgs) |
|
|
|
|
|
option := strings.Builder{} |
|
|
|
|
|
options := []parameter{} |
|
|
|
|
|
|
|
|
|
|
|
// 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]) |
|
|
|
|
|
} |
|
|
|
|
|
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] != ','; 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]) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// first option is always target mount path
|
|
|
|
|
|
mountOptions.dir = &args[0] |
|
|
|
|
|
|
|
|
options = append(options, parameter{name, option.String()}) |
|
|
|
|
|
option.Reset() |
|
|
|
|
|
|
|
|
// scan parameters looking for one or more -o options
|
|
|
|
|
|
// -o options receive parameters on format key=value[,key=value]...
|
|
|
|
|
|
for i := 0; i < argsLen; i++ { |
|
|
|
|
|
if args[i] == "-o" && i+1 <= argsLen { |
|
|
|
|
|
options = strings.Split(args[i+1], ",") |
|
|
|
|
|
i++ |
|
|
|
|
|
|
|
|
// 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]) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// for each option passed with -o
|
|
|
|
|
|
for _, option := range options { |
|
|
|
|
|
// split just first = character
|
|
|
|
|
|
parts := strings.SplitN(option, "=", 2) |
|
|
|
|
|
|
|
|
|
|
|
// if doesn't key and value skip
|
|
|
|
|
|
if len(parts) != 2 { |
|
|
|
|
|
continue |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// get residual option data
|
|
|
|
|
|
if option.Len() > 0 { |
|
|
|
|
|
// add value to pending option
|
|
|
|
|
|
options = append(options, parameter{option.String(), "true"}) |
|
|
|
|
|
option.Reset() |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
key, value := parts[0], parts[1] |
|
|
|
|
|
|
|
|
|
|
|
// switch key keeping "weed mount" parameters
|
|
|
|
|
|
switch key { |
|
|
|
|
|
case "filer": |
|
|
|
|
|
mountOptions.filer = &value |
|
|
|
|
|
case "filer.path": |
|
|
|
|
|
mountOptions.filerMountRootPath = &value |
|
|
|
|
|
case "dirAutoCreate": |
|
|
|
|
|
if parsed, err := strconv.ParseBool(value); err != nil { |
|
|
|
|
|
mountOptions.dirAutoCreate = &parsed |
|
|
|
|
|
} else { |
|
|
|
|
|
panic(fmt.Errorf("dirAutoCreate: %s", err)) |
|
|
|
|
|
} |
|
|
|
|
|
case "collection": |
|
|
|
|
|
mountOptions.collection = &value |
|
|
|
|
|
case "replication": |
|
|
|
|
|
mountOptions.replication = &value |
|
|
|
|
|
case "disk": |
|
|
|
|
|
mountOptions.diskType = &value |
|
|
|
|
|
case "ttl": |
|
|
|
|
|
if parsed, err := strconv.ParseInt(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(value, 0, 32); err != nil { |
|
|
|
|
|
intValue := int(parsed) |
|
|
|
|
|
mountOptions.chunkSizeLimitMB = &intValue |
|
|
|
|
|
} else { |
|
|
|
|
|
panic(fmt.Errorf("chunkSizeLimitMB: %s", err)) |
|
|
|
|
|
} |
|
|
|
|
|
case "concurrentWriters": |
|
|
|
|
|
if parsed, err := strconv.ParseInt(value, 0, 32); err != nil { |
|
|
|
|
|
intValue := int(parsed) |
|
|
|
|
|
mountOptions.concurrentWriters = &intValue |
|
|
|
|
|
} else { |
|
|
|
|
|
panic(fmt.Errorf("concurrentWriters: %s", err)) |
|
|
|
|
|
} |
|
|
|
|
|
case "cacheDir": |
|
|
|
|
|
mountOptions.cacheDir = &value |
|
|
|
|
|
case "cacheCapacityMB": |
|
|
|
|
|
if parsed, err := strconv.ParseInt(value, 0, 64); err != nil { |
|
|
|
|
|
mountOptions.cacheSizeMB = &parsed |
|
|
|
|
|
} else { |
|
|
|
|
|
panic(fmt.Errorf("cacheCapacityMB: %s", err)) |
|
|
|
|
|
} |
|
|
|
|
|
case "dataCenter": |
|
|
|
|
|
mountOptions.dataCenter = &value |
|
|
|
|
|
case "allowOthers": |
|
|
|
|
|
if parsed, err := strconv.ParseBool(value); err != nil { |
|
|
|
|
|
mountOptions.allowOthers = &parsed |
|
|
|
|
|
} else { |
|
|
|
|
|
panic(fmt.Errorf("allowOthers: %s", err)) |
|
|
|
|
|
} |
|
|
|
|
|
case "umask": |
|
|
|
|
|
mountOptions.umaskString = &value |
|
|
|
|
|
case "nonempty": |
|
|
|
|
|
if parsed, err := strconv.ParseBool(value); err != nil { |
|
|
|
|
|
mountOptions.nonempty = &parsed |
|
|
|
|
|
} else { |
|
|
|
|
|
panic(fmt.Errorf("nonempty: %s", err)) |
|
|
|
|
|
} |
|
|
|
|
|
case "volumeServerAccess": |
|
|
|
|
|
mountOptions.volumeServerAccess = &value |
|
|
|
|
|
case "map.uid": |
|
|
|
|
|
mountOptions.uidMap = &value |
|
|
|
|
|
case "map.gid": |
|
|
|
|
|
mountOptions.gidMap = &value |
|
|
|
|
|
case "readOnly": |
|
|
|
|
|
if parsed, err := strconv.ParseBool(value); err != nil { |
|
|
|
|
|
mountOptions.readOnly = &parsed |
|
|
|
|
|
} else { |
|
|
|
|
|
panic(fmt.Errorf("readOnly: %s", err)) |
|
|
|
|
|
} |
|
|
|
|
|
case "cpuprofile": |
|
|
|
|
|
mountCpuProfile = &value |
|
|
|
|
|
case "memprofile": |
|
|
|
|
|
mountMemProfile = &value |
|
|
|
|
|
case "readRetryTime": |
|
|
|
|
|
if parsed, err := time.ParseDuration(value); err != nil { |
|
|
|
|
|
mountReadRetryTime = &parsed |
|
|
|
|
|
} else { |
|
|
|
|
|
panic(fmt.Errorf("readRetryTime: %s", err)) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// scan each parameter
|
|
|
|
|
|
for i := 0; i < len(options); i++ { |
|
|
|
|
|
parameter := options[i] |
|
|
|
|
|
|
|
|
|
|
|
switch parameter.name { |
|
|
|
|
|
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.cacheDir = ¶meter.value |
|
|
|
|
|
case "cacheCapacityMB": |
|
|
|
|
|
if parsed, err := strconv.ParseInt(parameter.value, 0, 64); err != nil { |
|
|
|
|
|
mountOptions.cacheSizeMB = &parsed |
|
|
|
|
|
} else { |
|
|
|
|
|
panic(fmt.Errorf("cacheCapacityMB: %s", err)) |
|
|
|
|
|
} |
|
|
|
|
|
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)) |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -160,6 +214,9 @@ var cmdFuse = &Command{ |
|
|
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=/" |
|
|
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" |
|
|
To check valid options look "weed mount --help" |
|
|
`, |
|
|
`, |
|
|
} |
|
|
} |