This repository has been archived by the owner on Feb 12, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 137
/
mounter.go
108 lines (97 loc) · 2.88 KB
/
mounter.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
// Copyright 2016 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.
package libfuse
import (
"errors"
"fmt"
"os"
"os/exec"
"path"
"runtime"
"bazil.org/fuse"
"github.com/keybase/client/go/libkb"
"github.com/keybase/client/go/logger"
)
type mounter struct {
options StartOptions
c *fuse.Conn
log logger.Logger
runMode libkb.RunMode
}
// fuseMount tries to mount the mountpoint.
// On a force mount then unmount, re-mount if unsuccessful
func (m *mounter) Mount() (err error) {
m.c, err = fuseMountDir(m.options.MountPoint, m.options.PlatformParams)
// Exit if we were succesful or we are not a force mounting on error.
// Otherwise, try unmounting and mounting again.
if err == nil || !m.options.ForceMount {
return err
}
// Mount failed, let's try to unmount and then try mounting again, even
// if unmounting errors here.
m.Unmount()
// In case we are on darwin, ask the installer to reinstall the mount dir
// and try again as the last resort. This specifically fixes a situation
// where /keybase gets created and owned by root after Keybase app is
// started, and `kbfs` later fails to mount because of a permission error.
m.reinstallMountDirIfPossible()
m.c, err = fuseMountDir(m.options.MountPoint, m.options.PlatformParams)
return err
}
func fuseMountDir(dir string, platformParams PlatformParams) (*fuse.Conn, error) {
fi, err := os.Stat(dir)
if err != nil {
return nil, err
}
if !fi.IsDir() {
return nil, errors.New("mount point is not a directory")
}
options, err := getPlatformSpecificMountOptions(dir, platformParams)
if err != nil {
return nil, err
}
c, err := fuse.Mount(dir, options...)
if err != nil {
err = translatePlatformSpecificError(err, platformParams)
return nil, err
}
return c, nil
}
func (m *mounter) Unmount() (err error) {
dir := m.options.MountPoint
// Try normal unmount
switch runtime.GOOS {
case "darwin":
_, err = exec.Command("/sbin/umount", dir).Output()
case "linux":
_, err = exec.Command("fusermount", "-u", dir).Output()
default:
err = fuse.Unmount(dir)
}
if err != nil && m.options.ForceMount {
// Unmount failed, so let's try and force it.
switch runtime.GOOS {
case "darwin":
_, err = exec.Command(
"/usr/sbin/diskutil", "unmountDisk", "force", dir).Output()
case "linux":
_, err = exec.Command("fusermount", "-ul", dir).Output()
default:
err = errors.New("Forced unmount is not supported on this platform yet")
}
}
if execErr, ok := err.(*exec.ExitError); ok && execErr.Stderr != nil {
err = fmt.Errorf("%s (%s)", execErr, execErr.Stderr)
}
return
}
// volumeName returns the directory (base) name
func volumeName(dir string) (string, error) {
volName := path.Base(dir)
if volName == "." || volName == "/" {
err := fmt.Errorf("Bad volume name: %v", volName)
return "", err
}
return volName, nil
}