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