main: Run 'ensure fds' code early during the program startup.
The files are apparently processed in alphabetic order, so cli_args.go is processed before main.go. In order to run before the go-fuse imports, put the 'ensure fds' code in a separate package. Debug messages are omitted to avoid additional imports (that might contain other code messing up our file descriptors).
This commit is contained in:
parent
ad15ad9985
commit
7e05e809b7
@ -1,5 +1,10 @@
|
||||
package main
|
||||
|
||||
// Should be initialized before anything else.
|
||||
// This import line MUST be in the alphabitcally first source code file of
|
||||
// package main!
|
||||
import _ "github.com/rfjakob/gocryptfs/internal/ensurefds012"
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
|
52
internal/ensurefds012/ensurefds012.go
Normal file
52
internal/ensurefds012/ensurefds012.go
Normal file
@ -0,0 +1,52 @@
|
||||
package ensurefds012
|
||||
|
||||
// Package ensurefds012 ensures that file descriptors 0,1,2 are open. It opens
|
||||
// multiple copies of /dev/null as required.
|
||||
// The Go stdlib as well as the gocryptfs code rely on the fact that
|
||||
// fds 0,1,2 are always open.
|
||||
//
|
||||
// Use like this:
|
||||
//
|
||||
// import _ "github.com/rfjakob/gocryptfs/internal/ensurefds012"
|
||||
//
|
||||
// The import line MUST be in the alphabitcally first source code file of
|
||||
// package main!
|
||||
//
|
||||
// You can test if it works as expected by inserting a long sleep into main,
|
||||
// startings gocryptfs with all fds closed like this,
|
||||
//
|
||||
// $ ./gocryptfs 0<&- 1>&- 2>&-
|
||||
//
|
||||
// and then checking the open fds. It should look like this:
|
||||
//
|
||||
// $ ls -l /proc/$(pgrep gocryptfs)/fd
|
||||
// total 0
|
||||
// lrwx------. 1 jakob jakob 64 Jan 5 15:54 0 -> /dev/null
|
||||
// lrwx------. 1 jakob jakob 64 Jan 5 15:54 1 -> /dev/null
|
||||
// lrwx------. 1 jakob jakob 64 Jan 5 15:54 2 -> /dev/null
|
||||
// l-wx------. 1 jakob jakob 64 Jan 5 15:54 3 -> /dev/null
|
||||
// lrwx------. 1 jakob jakob 64 Jan 5 15:54 4 -> 'anon_inode:[eventpoll]'
|
||||
//
|
||||
// See https://github.com/rfjakob/gocryptfs/issues/320 for details.
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/rfjakob/gocryptfs/internal/exitcodes"
|
||||
)
|
||||
|
||||
func init() {
|
||||
fd, err := syscall.Open("/dev/null", syscall.O_RDWR, 0)
|
||||
if err != nil {
|
||||
os.Exit(exitcodes.DevNull)
|
||||
}
|
||||
for fd <= 2 {
|
||||
fd, err = syscall.Dup(fd)
|
||||
if err != nil {
|
||||
os.Exit(exitcodes.DevNull)
|
||||
}
|
||||
}
|
||||
// Close excess fd (usually fd 3)
|
||||
syscall.Close(fd)
|
||||
}
|
@ -35,6 +35,8 @@ type dirCacheEntryStruct struct {
|
||||
func (e *dirCacheEntryStruct) Clear() {
|
||||
// An earlier clear may have already closed the fd, or the cache
|
||||
// has never been filled (fd is 0 in that case).
|
||||
// Note: package ensurefds012, imported from main, guarantees that dirCache
|
||||
// can never get fds 0,1,2.
|
||||
if e.fd > 0 {
|
||||
err := syscall.Close(e.fd)
|
||||
if err != nil {
|
||||
@ -72,6 +74,8 @@ func (d *dirCacheStruct) Clear() {
|
||||
// Store the entry in the cache. The passed "fd" will be Dup()ed, and the caller
|
||||
// can close their copy at will.
|
||||
func (d *dirCacheStruct) Store(dirRelPath string, fd int, iv []byte) {
|
||||
// Note: package ensurefds012, imported from main, guarantees that dirCache
|
||||
// can never get fds 0,1,2.
|
||||
if fd <= 0 || len(iv) != nametransform.DirIVLen {
|
||||
log.Panicf("Store sanity check failed: fd=%d len=%d", fd, len(iv))
|
||||
}
|
||||
|
25
main.go
25
main.go
@ -8,7 +8,6 @@ import (
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/hanwen/go-fuse/fuse"
|
||||
|
||||
@ -150,7 +149,6 @@ func printVersion() {
|
||||
}
|
||||
|
||||
func main() {
|
||||
ensureStdFds()
|
||||
mxp := runtime.GOMAXPROCS(0)
|
||||
if mxp < 4 {
|
||||
// On a 2-core machine, setting maxprocs to 4 gives 10% better performance
|
||||
@ -330,26 +328,3 @@ func main() {
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
// ensureStdFds ensures that file descriptors 0,1,2 are open. The Go stdlib,
|
||||
// as well as the gocryptfs code, relies on the fact that fds 0,1,2 are always
|
||||
// open.
|
||||
// See https://github.com/rfjakob/gocryptfs/issues/320 for details.
|
||||
//
|
||||
// This function should be called as the first thing from main().
|
||||
func ensureStdFds() {
|
||||
fd, err := syscall.Open("/dev/null", syscall.O_RDWR, 0)
|
||||
if err != nil {
|
||||
tlog.Fatal.Printf("ensureStdFds: open /dev/null failed: %v", err)
|
||||
os.Exit(exitcodes.DevNull)
|
||||
}
|
||||
for fd <= 2 {
|
||||
fd, err = syscall.Dup(fd)
|
||||
if err != nil {
|
||||
tlog.Fatal.Printf("ensureStdFds: dup failed: %v", err)
|
||||
os.Exit(exitcodes.DevNull)
|
||||
}
|
||||
}
|
||||
// Close excess fd (usually fd 3)
|
||||
syscall.Close(fd)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user