-
Notifications
You must be signed in to change notification settings - Fork 180
/
Copy pathmounthelper.go
92 lines (79 loc) · 2.51 KB
/
mounthelper.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
// An example script showing usage of FUSE file descriptor as a mount point.
//
// Example usage:
// $ go build mounthelper.go
// $ sudo /sbin/setcap 'cap_sys_admin=ep' ./mounthelper # `mount` syscall requires `CAP_SYS_ADMIN`, alternatively, `mounthelper` can be run as root
// $ ./mounthelper -mountpoint /tmp/mountpoint -bucket bucketname
// $ # Mountpoint mounted at /tmp/mountpoint until `mounthelper` is terminated with ctrl+c.
package main
import (
"errors"
"flag"
"fmt"
"io/fs"
"log"
"os"
"os/exec"
"os/signal"
"strings"
"syscall"
)
var mountPoint = flag.String("mountpoint", "", "Path to mount the filesystem at")
var bucket = flag.String("bucket", "", "S3 Bucket to mount")
func main() {
flag.Parse()
if err := os.MkdirAll(*mountPoint, 0644); err != nil && !errors.Is(err, fs.ErrExist) {
log.Panicf("Failed to create target mount point %s: %v\n", *mountPoint, err)
}
// 1. Open FUSE device
fd, err := syscall.Open("/dev/fuse", os.O_RDWR, 0)
if err != nil {
log.Panicf("Failed to open /dev/fuse: %v\n", err)
}
defer syscall.Close(fd)
var stat syscall.Stat_t
err = syscall.Stat(*mountPoint, &stat)
if err != nil {
log.Panicf("Failed to stat mount point %s: %v\n", *mountPoint, err)
}
// 2. Perform `mount` syscall
options := []string{
fmt.Sprintf("fd=%d", fd),
fmt.Sprintf("rootmode=%o", stat.Mode),
fmt.Sprintf("user_id=%d", os.Geteuid()),
fmt.Sprintf("group_id=%d", os.Getegid()),
}
err = syscall.Mount("mountpoint-s3", *mountPoint, "fuse", syscall.MS_NOSUID | syscall.MS_NODEV, strings.Join(options, ","))
if err != nil {
log.Panicf("Failed to call mount syscall: %v\n", err)
}
// 5. Perform `unmount` syscall once Mountpoint terminates
defer func() {
err := syscall.Unmount(*mountPoint, 0)
if err != nil {
log.Printf("Failed to unmount %s: %v\n", *mountPoint, err)
}
log.Printf("Succesfully unmounted %s\n", *mountPoint)
}()
// 3. Spawn Mountpoint with the fd
mountpointCmd := exec.Command("./target/release/mount-s3",
*bucket,
fmt.Sprintf("/dev/fd/%d", fd),
"--allow-delete")
mountpointCmd.Stdout = os.Stdout
mountpointCmd.Stderr = os.Stderr
err = mountpointCmd.Run()
if err != nil {
log.Panicf("Failed to start Mountpoint: %v\n", err)
}
// 4. Close fd on parent
err = syscall.Close(fd)
if err != nil {
log.Panicf("Failed to close fd on parent: %v\n", err)
}
done := make(chan os.Signal, 1)
signal.Notify(done, syscall.SIGINT, syscall.SIGTERM)
log.Print("Filesystem mounted, waiting for ctrl+c signal to terminate")
<-done
// 5. Will run here due to `defer`
}