github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/cmd/cammount/cammount.go (about) 1 // +build linux darwin 2 3 /* 4 Copyright 2011 Google Inc. 5 6 Licensed under the Apache License, Version 2.0 (the "License"); 7 you may not use this file except in compliance with the License. 8 You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 See the License for the specific language governing permissions and 16 limitations under the License. 17 */ 18 19 package main 20 21 import ( 22 "flag" 23 "fmt" 24 "io/ioutil" 25 "log" 26 "net/http" 27 "os" 28 "os/exec" 29 "os/signal" 30 "runtime" 31 "strings" 32 "syscall" 33 "time" 34 35 "camlistore.org/pkg/blob" 36 "camlistore.org/pkg/cacher" 37 "camlistore.org/pkg/client" 38 "camlistore.org/pkg/fs" 39 "camlistore.org/pkg/search" 40 "camlistore.org/third_party/code.google.com/p/rsc/fuse" 41 ) 42 43 var ( 44 debug = flag.Bool("debug", false, "print debugging messages.") 45 xterm = flag.Bool("xterm", false, "Run an xterm in the mounted directory. Shut down when xterm ends.") 46 open = flag.Bool("open", false, "Open a GUI window") 47 ) 48 49 func usage() { 50 fmt.Fprint(os.Stderr, "usage: cammount [opts] [<mountpoint> [<root-blobref>|<share URL>|<root-name>]]\n") 51 flag.PrintDefaults() 52 os.Exit(2) 53 } 54 55 func main() { 56 var conn *fuse.Conn 57 58 // Scans the arg list and sets up flags 59 client.AddFlags() 60 flag.Usage = usage 61 flag.Parse() 62 63 narg := flag.NArg() 64 if narg > 2 { 65 usage() 66 } 67 68 var mountPoint string 69 var err error 70 if narg > 0 { 71 mountPoint = flag.Arg(0) 72 } else { 73 mountPoint, err = ioutil.TempDir("", "cammount") 74 if err != nil { 75 log.Fatal(err) 76 } 77 log.Printf("No mount point given. Using: %s", mountPoint) 78 defer os.Remove(mountPoint) 79 } 80 81 errorf := func(msg string, args ...interface{}) { 82 fmt.Fprintf(os.Stderr, msg, args...) 83 fmt.Fprint(os.Stderr, "\n") 84 usage() 85 } 86 87 var ( 88 cl *client.Client 89 root blob.Ref // nil if only one arg 90 camfs *fs.CamliFileSystem 91 ) 92 if narg == 2 { 93 rootArg := flag.Arg(1) 94 // not trying very hard since NewFromShareRoot will do it better with a regex 95 if strings.HasPrefix(rootArg, "http://") || 96 strings.HasPrefix(rootArg, "https://") { 97 if client.ExplicitServer() != "" { 98 errorf("Can't use an explicit blobserver with a share URL; the blobserver is implicit from the share URL.") 99 } 100 var err error 101 cl, root, err = client.NewFromShareRoot(rootArg) 102 if err != nil { 103 log.Fatal(err) 104 } 105 } else { 106 cl = client.NewOrFail() // automatic from flags 107 cl.SetHTTPClient(&http.Client{Transport: cl.TransportForConfig(nil)}) 108 109 var ok bool 110 root, ok = blob.Parse(rootArg) 111 112 if !ok { 113 // not a blobref, check for root name instead 114 req := &search.WithAttrRequest{N: 1, Attr: "camliRoot", Value: rootArg} 115 wres, err := cl.GetPermanodesWithAttr(req) 116 117 if err != nil { 118 log.Fatal("could not query search") 119 } 120 121 if wres.WithAttr != nil { 122 root = wres.WithAttr[0].Permanode 123 } else { 124 log.Fatalf("root specified is not a blobref or name of a root: %q\n", rootArg) 125 } 126 } 127 } 128 } else { 129 cl = client.NewOrFail() // automatic from flags 130 cl.SetHTTPClient(&http.Client{Transport: cl.TransportForConfig(nil)}) 131 } 132 133 diskCacheFetcher, err := cacher.NewDiskCache(cl) 134 if err != nil { 135 log.Fatalf("Error setting up local disk cache: %v", err) 136 } 137 defer diskCacheFetcher.Clean() 138 if root.Valid() { 139 var err error 140 camfs, err = fs.NewRootedCamliFileSystem(cl, diskCacheFetcher, root) 141 if err != nil { 142 log.Fatalf("Error creating root with %v: %v", root, err) 143 } 144 } else { 145 camfs = fs.NewDefaultCamliFileSystem(cl, diskCacheFetcher) 146 } 147 148 if *debug { 149 fuse.Debugf = log.Printf 150 // TODO: set fs's logger 151 } 152 153 // This doesn't appear to work on OS X: 154 sigc := make(chan os.Signal, 1) 155 156 conn, err = fuse.Mount(mountPoint) 157 if err != nil { 158 if err.Error() == "cannot find load_fusefs" && runtime.GOOS == "darwin" { 159 log.Fatal("FUSE not available; install from http://osxfuse.github.io/") 160 } 161 log.Fatalf("Mount: %v", err) 162 } 163 164 xtermDone := make(chan bool, 1) 165 if *xterm { 166 cmd := exec.Command("xterm") 167 cmd.Dir = mountPoint 168 if err := cmd.Start(); err != nil { 169 log.Printf("Error starting xterm: %v", err) 170 } else { 171 go func() { 172 cmd.Wait() 173 xtermDone <- true 174 }() 175 defer cmd.Process.Kill() 176 } 177 } 178 if *open { 179 if runtime.GOOS == "darwin" { 180 cmd := exec.Command("open", mountPoint) 181 go cmd.Run() 182 } 183 } 184 185 signal.Notify(sigc, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT) 186 187 doneServe := make(chan error, 1) 188 go func() { 189 doneServe <- conn.Serve(camfs) 190 }() 191 192 quitKey := make(chan bool, 1) 193 go awaitQuitKey(quitKey) 194 195 select { 196 case err := <-doneServe: 197 log.Printf("conn.Serve returned %v", err) 198 case sig := <-sigc: 199 log.Printf("Signal %s received, shutting down.", sig) 200 case <-quitKey: 201 log.Printf("Quit key pressed. Shutting down.") 202 case <-xtermDone: 203 log.Printf("xterm done") 204 } 205 206 time.AfterFunc(2*time.Second, func() { 207 os.Exit(1) 208 }) 209 log.Printf("Unmounting...") 210 err = fs.Unmount(mountPoint) 211 log.Printf("Unmount = %v", err) 212 213 log.Printf("cammount FUSE process ending.") 214 } 215 216 func awaitQuitKey(done chan<- bool) { 217 var buf [1]byte 218 for { 219 _, err := os.Stdin.Read(buf[:]) 220 if err != nil { 221 return 222 } 223 if buf[0] == 'q' { 224 done <- true 225 return 226 } 227 } 228 }