committed by
GitHub
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 280 additions and 261 deletions
-
260weed/command/fuse.go
-
15weed/command/fuse_notsupported.go
-
264weed/command/fuse_std.go
-
2weed/command/mount_std.go
@ -0,0 +1,15 @@ |
|||||
|
//go:build !linux && !darwin
|
||||
|
// +build !linux,!darwin
|
||||
|
|
||||
|
package command |
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
"runtime" |
||||
|
) |
||||
|
|
||||
|
func runFuse(cmd *Command, args []string) bool { |
||||
|
fmt.Printf("Fuse is not supported on %s %s\n", runtime.GOOS, runtime.GOARCH) |
||||
|
|
||||
|
return true |
||||
|
} |
@ -0,0 +1,264 @@ |
|||||
|
//go:build linux || darwin
|
||||
|
// +build linux darwin
|
||||
|
|
||||
|
package command |
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
"math" |
||||
|
"os" |
||||
|
"os/signal" |
||||
|
"strconv" |
||||
|
"strings" |
||||
|
"syscall" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
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 |
||||
|
if parsed, err := strconv.ParseInt(parameter.value, 10, 64); err == nil { |
||||
|
if parsed > math.MaxInt || parsed <= 0 { |
||||
|
panic(fmt.Errorf("parent PID %d is invalid", parsed)) |
||||
|
} |
||||
|
mountOptions.fuseCommandPid = int(parsed) |
||||
|
} else { |
||||
|
panic(fmt.Errorf("parent PID %s is invalid: %w", parameter.value, err)) |
||||
|
} |
||||
|
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) |
||||
|
} |
||||
|
|
||||
|
// pass our PID to the child process
|
||||
|
pid := os.Getpid() |
||||
|
argv := append(os.Args, "-o", "child="+strconv.Itoa(pid)) |
||||
|
|
||||
|
c := make(chan os.Signal, 1) |
||||
|
signal.Notify(c, syscall.SIGTERM) |
||||
|
|
||||
|
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)) |
||||
|
} |
||||
|
|
||||
|
select { |
||||
|
case <-c: |
||||
|
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{}) |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue