github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/core/commands/mount_darwin.go (about) 1 // +build !nofuse 2 3 package commands 4 5 import ( 6 "bytes" 7 "fmt" 8 "os/exec" 9 "runtime" 10 "strings" 11 "syscall" 12 13 core "github.com/ipfs/go-ipfs/core" 14 ) 15 16 func init() { 17 // this is a hack, but until we need to do it another way, this works. 18 platformFuseChecks = darwinFuseCheckVersion 19 } 20 21 // dontCheckOSXFUSEConfigKey is a key used to let the user tell us to 22 // skip fuse checks. 23 var dontCheckOSXFUSEConfigKey = "DontCheckOSXFUSE" 24 25 // fuseVersionPkg is the go pkg url for fuse-version 26 var fuseVersionPkg = "github.com/jbenet/go-fuse-version/fuse-version" 27 28 // errStrFuseRequired is returned when we're sure the user does not have fuse. 29 var errStrFuseRequired = `OSXFUSE not found. 30 31 OSXFUSE is required to mount, please install it. 32 Note: version 2.7.2 or higher required; prior versions are known to kernel panic! 33 It is recommended you install it from the OSXFUSE website: 34 35 http://osxfuse.github.io/ 36 37 For more help, see: 38 39 https://github.com/ipfs/go-ipfs/issues/177 40 ` 41 42 // errStrNoFuseHeaders is included in the output of `go get <fuseVersionPkg>` if there 43 // are no fuse headers. this means they dont have OSXFUSE installed. 44 var errStrNoFuseHeaders = "no such file or directory: '/usr/local/lib/libosxfuse.dylib'" 45 46 var errStrUpgradeFuse = `OSXFUSE version %s not supported. 47 48 OSXFUSE versions <2.7.2 are known to cause kernel panics! 49 Please upgrade to the latest OSXFUSE version. 50 It is recommended you install it from the OSXFUSE website: 51 52 http://osxfuse.github.io/ 53 54 For more help, see: 55 56 https://github.com/ipfs/go-ipfs/issues/177 57 ` 58 59 var errStrNeedFuseVersion = `unable to check fuse version. 60 61 Dear User, 62 63 Before mounting, we must check your version of OSXFUSE. We are protecting 64 you from a nasty kernel panic we found in OSXFUSE versions <2.7.2.[1]. To 65 make matters worse, it's harder than it should be to check whether you have 66 the right version installed...[2]. We've automated the process with the 67 help of a little tool. We tried to install it, but something went wrong[3]. 68 Please install it yourself by running: 69 70 go get %s 71 72 You can also stop ipfs from running these checks and use whatever OSXFUSE 73 version you have by running: 74 75 ipfs config %s true 76 77 [1]: https://github.com/ipfs/go-ipfs/issues/177 78 [2]: https://github.com/ipfs/go-ipfs/pull/533 79 [3]: %s 80 ` 81 82 var errStrFailedToRunFuseVersion = `unable to check fuse version. 83 84 Dear User, 85 86 Before mounting, we must check your version of OSXFUSE. We are protecting 87 you from a nasty kernel panic we found in OSXFUSE versions <2.7.2.[1]. To 88 make matters worse, it's harder than it should be to check whether you have 89 the right version installed...[2]. We've automated the process with the 90 help of a little tool. We tried to run it, but something went wrong[3]. 91 Please, try to run it yourself with: 92 93 go get %s 94 fuse-version 95 96 You should see something like this: 97 98 > fuse-version 99 fuse-version -only agent 100 OSXFUSE.AgentVersion: 2.7.3 101 102 Just make sure the number is 2.7.2 or higher. You can then stop ipfs from 103 trying to run these checks with: 104 105 ipfs config %s true 106 107 [1]: https://github.com/ipfs/go-ipfs/issues/177 108 [2]: https://github.com/ipfs/go-ipfs/pull/533 109 [3]: %s 110 ` 111 112 var errStrFixConfig = `config key invalid: %s %s 113 You may be able to get this error to go away by setting it again: 114 115 ipfs config %s true 116 117 Either way, please tell us at: http://github.com/ipfs/go-ipfs/issues 118 ` 119 120 func darwinFuseCheckVersion(node *core.IpfsNode) error { 121 // on OSX, check FUSE version. 122 if runtime.GOOS != "darwin" { 123 return nil 124 } 125 126 ov, errGFV := tryGFV() 127 if errGFV != nil { 128 // if we failed AND the user has told us to ignore the check we 129 // continue. this is in case fuse-version breaks or the user cannot 130 // install it, but is sure their fuse version will work. 131 if skip, err := userAskedToSkipFuseCheck(node); err != nil { 132 return err 133 } else if skip { 134 return nil // user told us not to check version... ok.... 135 } else { 136 return errGFV 137 } 138 } 139 140 log.Debug("mount: osxfuse version:", ov) 141 if strings.HasPrefix(ov, "2.7.") || strings.HasPrefix(ov, "2.8.") { 142 return nil 143 } 144 145 return fmt.Errorf(errStrUpgradeFuse, ov) 146 } 147 148 func tryGFV() (string, error) { 149 // first try sysctl. it may work! 150 ov, err := trySysctl() 151 if err == nil { 152 return ov, nil 153 } 154 log.Debug(err) 155 156 return tryGFVFromFuseVersion() 157 } 158 159 func trySysctl() (string, error) { 160 v, err := syscall.Sysctl("osxfuse.version.number") 161 if err != nil { 162 log.Debug("mount: sysctl osxfuse.version.number:", "failed") 163 return "", err 164 } 165 log.Debug("mount: sysctl osxfuse.version.number:", v) 166 return v, nil 167 } 168 169 func tryGFVFromFuseVersion() (string, error) { 170 if err := ensureFuseVersionIsInstalled(); err != nil { 171 return "", err 172 } 173 174 cmd := exec.Command("fuse-version", "-q", "-only", "agent", "-s", "OSXFUSE") 175 out := new(bytes.Buffer) 176 cmd.Stdout = out 177 if err := cmd.Run(); err != nil { 178 return "", fmt.Errorf(errStrFailedToRunFuseVersion, fuseVersionPkg, dontCheckOSXFUSEConfigKey, err) 179 } 180 181 return out.String(), nil 182 } 183 184 func ensureFuseVersionIsInstalled() error { 185 // see if fuse-version is there 186 if _, err := exec.LookPath("fuse-version"); err == nil { 187 return nil // got it! 188 } 189 190 // try installing it... 191 log.Debug("fuse-version: no fuse-version. attempting to install.") 192 cmd := exec.Command("go", "get", "github.com/jbenet/go-fuse-version/fuse-version") 193 cmdout := new(bytes.Buffer) 194 cmd.Stdout = cmdout 195 cmd.Stderr = cmdout 196 if err := cmd.Run(); err != nil { 197 // Ok, install fuse-version failed. is it they dont have fuse? 198 cmdoutstr := cmdout.String() 199 if strings.Contains(cmdoutstr, errStrNoFuseHeaders) { 200 // yes! it is! they dont have fuse! 201 return fmt.Errorf(errStrFuseRequired) 202 } 203 204 log.Debug("fuse-version: failed to install.") 205 s := err.Error() + "\n" + cmdoutstr 206 return fmt.Errorf(errStrNeedFuseVersion, fuseVersionPkg, dontCheckOSXFUSEConfigKey, s) 207 } 208 209 // ok, try again... 210 if _, err := exec.LookPath("fuse-version"); err != nil { 211 log.Debug("fuse-version: failed to install?") 212 return fmt.Errorf(errStrNeedFuseVersion, fuseVersionPkg, dontCheckOSXFUSEConfigKey, err) 213 } 214 215 log.Debug("fuse-version: install success") 216 return nil 217 } 218 219 func userAskedToSkipFuseCheck(node *core.IpfsNode) (skip bool, err error) { 220 val, err := node.Repo.GetConfigKey(dontCheckOSXFUSEConfigKey) 221 if err != nil { 222 return false, nil // failed to get config value. dont skip check. 223 } 224 s, ok := val.(string) 225 if !ok { 226 // got config value, but it's invalid... dont skip check, ask the user to fix it... 227 return false, fmt.Errorf(errStrFixConfig, dontCheckOSXFUSEConfigKey, val, 228 dontCheckOSXFUSEConfigKey) 229 } 230 // only "true" counts as telling us to skip. 231 return s == "true", nil 232 }