-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmain.go
170 lines (152 loc) · 4.54 KB
/
main.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
package main
import (
"fmt"
"log/syslog"
"os"
"os/exec"
"os/signal"
"runtime"
"strings"
"syscall"
"time"
"github.com/declan94/cfcryptfs/cffuse"
"github.com/declan94/cfcryptfs/internal/cli"
"github.com/declan94/cfcryptfs/internal/exitcode"
"github.com/declan94/cfcryptfs/internal/tlog"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/fuse/nodefs"
"github.com/hanwen/go-fuse/fuse/pathfs"
)
func main() {
var args = cli.ParseArgs()
if args.Init {
cli.InitCipherDir(args.CipherDir)
return
}
if args.Info {
cli.InfoCipherDir(args.CipherDir)
return
}
if args.ChangePwd {
cli.ChangeCipherPwd(args.CipherDir)
return
}
if args.Export {
cli.ExportEmergencyFile(args.CipherDir, args.Emergency)
return
}
if args.Recover {
cli.RecoverCipherDir(args.CipherDir, args.Emergency)
return
}
if !args.Foreground {
os.Exit(forkChild())
}
var conf cli.CipherConfig
var key []byte
if args.Emergency != "" {
conf, key = cli.LoadEmergencyFile(args.Emergency)
} else {
conf = cli.LoadConf(args.CipherDir)
if conf.KeyCryptType == cli.KeyCryptTypePWD {
key = cli.LoadKey(args.CipherDir, args.PwdFile, args.Password)
} else {
key = cli.LoadKeySSS(args.KeyFiles)
}
}
// Check mountpoint
// We cannot mount "/home/user/.cipher" at "/home/user" because the mount
// will hide ".cipher" also for us.
if args.CipherDir == args.MountPoint || strings.HasPrefix(args.CipherDir, args.MountPoint+"/") {
tlog.Fatal.Printf("Mountpoint %q would shadow cipherdir %q, this is not supported",
args.MountPoint, args.CipherDir)
os.Exit(exitcode.MountPoint)
}
var fsConf = cffuse.FsConfig{
CipherDir: args.CipherDir,
AllowOther: args.AllowOther,
CryptKey: key,
CryptType: conf.CryptType,
PlainBS: conf.PlainBS,
PlainPath: conf.PlainPath,
}
var fs = cffuse.NewFS(fsConf, nil)
var finalFs pathfs.FileSystem
finalFs = fs
pathFsOpts := &pathfs.PathNodeFsOptions{ClientInodes: true}
pathFs := pathfs.NewPathNodeFs(finalFs, pathFsOpts)
fuseOpts := &nodefs.Options{
// These options are to be compatible with libfuse defaults,
// making benchmarking easier.
NegativeTimeout: time.Second,
AttrTimeout: time.Second,
EntryTimeout: time.Second,
}
conn := nodefs.NewFileSystemConnector(pathFs.Root(), fuseOpts)
mOpts := fuse.MountOptions{
// Bigger writes mean fewer calls and better throughput.
// Capped to 128KiB on Linux.
MaxWrite: fuse.MAX_KERNEL_WRITE,
Name: "cfcryptfs",
}
if args.AllowOther {
mOpts.AllowOther = true
// Make the kernel check the file permissions for us
mOpts.Options = append(mOpts.Options, "default_permissions")
}
srv, err := fuse.NewServer(conn.RawFS(), args.MountPoint, &mOpts)
if err != nil {
fmt.Printf("Start fuse server failed: %v\n", err)
os.Exit(exitcode.Fuse)
}
srv.SetDebug(args.DebugFuse)
// All FUSE file and directory create calls carry explicit permission
// information. We need an unrestricted umask to create the files and
// directories with the requested permissions.
syscall.Umask(0000)
// Wait for SIGINT in the background and unmount ourselves if we get it.
// This prevents a dangling "Transport endpoint is not connected"
// mountpoint if the user hits CTRL-C.
handleSigint(srv, args.MountPoint)
if args.ParentPid > 0 {
// Chdir to the root directory so we don't block unmounting the CWD
os.Chdir("/")
// Switch all of our logs and the generic logger to syslog
tlog.Info.SwitchToSyslog(syslog.LOG_USER | syslog.LOG_INFO)
tlog.Debug.SwitchToSyslog(syslog.LOG_USER | syslog.LOG_DEBUG)
tlog.Warn.SwitchToSyslog(syslog.LOG_USER | syslog.LOG_WARNING)
tlog.SwitchLoggerToSyslog(syslog.LOG_USER | syslog.LOG_WARNING)
// Disconnect from the controlling terminal by creating a new session.
// This prevents us from getting SIGINT when the user presses Ctrl-C
// to exit a running script that has called cfcryptfs.
_, err = syscall.Setsid()
if err != nil {
tlog.Warn.Printf("Setsid failed: %v", err)
}
// Send SIGUSR1 to our parent
sendUsr1(args.ParentPid)
}
fmt.Println("Filesystem Mounted")
srv.Serve()
}
func handleSigint(srv *fuse.Server, mountpoint string) {
ch := make(chan os.Signal, 1)
signal.Notify(ch, os.Interrupt)
signal.Notify(ch, syscall.SIGTERM)
go func() {
<-ch
err := srv.Unmount()
if err != nil {
tlog.Warn.Print(err)
if runtime.GOOS == "linux" {
// MacOSX does not support lazy unmount
tlog.Info.Printf("Trying lazy unmount")
cmd := exec.Command("fusermount", "-u", "-z", mountpoint)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Run()
}
}
os.Exit(0)
}()
}