gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/runner/fuse/fuse.go (about) 1 // Copyright 2022 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Binary main starts a fuse server that forwards filesystem operations from 16 // /tmp to /fuse. 17 package main 18 19 import ( 20 "flag" 21 golog "log" 22 "os" 23 "os/exec" 24 "strings" 25 26 "github.com/hanwen/go-fuse/v2/fs" 27 "github.com/hanwen/go-fuse/v2/fuse" 28 "golang.org/x/sys/unix" 29 "gvisor.dev/gvisor/pkg/log" 30 "gvisor.dev/gvisor/runsc/specutils" 31 ) 32 33 var ( 34 dir = flag.String("dir", "/tmp", "The directory to mount the fuse filesystem on.") 35 cmd = flag.String("cmd", "", "Command to execute after starting the fuse server. If empty, just wait after starting.") 36 debug = flag.Bool("debug", true, "Whether to log FUSE traffic. Set to false for benchmarks.") 37 ) 38 39 func waitOnMount(s *fuse.Server) { 40 if _, _, err := specutils.RetryEintr(func() (uintptr, uintptr, error) { 41 if err := s.WaitMount(); err != nil { 42 return 0, 0, err 43 } 44 return 0, 0, nil 45 }); err != nil { 46 // We don't shutdown the serve loop. If the mount does 47 // not succeed, the loop won't work and exit. 48 log.Warningf(`Could not mount fuse submount "/tmp": %v`, err) 49 os.Exit(1) 50 } 51 } 52 53 func main() { 54 flag.Parse() 55 loopbackRoot, err := fs.NewLoopbackRoot("/fuse") 56 if err != nil { 57 log.Warningf("could not create loopback root: %v", err) 58 os.Exit(1) 59 } 60 opts := &fuse.MountOptions{ 61 DirectMountStrict: true, 62 Debug: *debug, 63 AllowOther: true, 64 // SingleThreaded adds locking the fuse server handler. We need to 65 // enable this so that the go race detector doesn't detect a data race, even 66 // if there isn't a logical race. 67 SingleThreaded: true, 68 Options: []string{"default_permissions"}, 69 } 70 rawFS := fs.NewNodeFS(loopbackRoot, &fs.Options{NullPermissions: true, Logger: golog.Default()}) 71 server, err := fuse.NewServer(rawFS, *dir, opts) 72 if err != nil { 73 log.Warningf("could not create fuse server: %v", err) 74 os.Exit(1) 75 } 76 // Clear umask so that it doesn't affect the mode bits twice. 77 unix.Umask(0) 78 79 if *cmd == "" { 80 server.Serve() 81 waitOnMount(server) 82 return 83 } 84 go server.Serve() 85 waitOnMount(server) 86 defer func() { 87 server.Unmount() 88 server.Wait() 89 }() 90 91 cmdArgs := strings.Split(strings.Trim(*cmd, "\""), " ") 92 c := exec.Command(cmdArgs[0], cmdArgs[1:]...) 93 c.Stdout = os.Stdout 94 c.Stderr = os.Stderr 95 if err := c.Run(); err != nil { 96 log.Warningf(err.Error()) 97 os.Exit(1) 98 } 99 os.Exit(0) 100 }