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
|
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 (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"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() {
|
func (e *dirCacheEntryStruct) Clear() {
|
||||||
// An earlier clear may have already closed the fd, or the cache
|
// An earlier clear may have already closed the fd, or the cache
|
||||||
// has never been filled (fd is 0 in that case).
|
// 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 {
|
if e.fd > 0 {
|
||||||
err := syscall.Close(e.fd)
|
err := syscall.Close(e.fd)
|
||||||
if err != nil {
|
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
|
// Store the entry in the cache. The passed "fd" will be Dup()ed, and the caller
|
||||||
// can close their copy at will.
|
// can close their copy at will.
|
||||||
func (d *dirCacheStruct) Store(dirRelPath string, fd int, iv []byte) {
|
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 {
|
if fd <= 0 || len(iv) != nametransform.DirIVLen {
|
||||||
log.Panicf("Store sanity check failed: fd=%d len=%d", fd, len(iv))
|
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"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/hanwen/go-fuse/fuse"
|
"github.com/hanwen/go-fuse/fuse"
|
||||||
|
|
||||||
@ -150,7 +149,6 @@ func printVersion() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
ensureStdFds()
|
|
||||||
mxp := runtime.GOMAXPROCS(0)
|
mxp := runtime.GOMAXPROCS(0)
|
||||||
if mxp < 4 {
|
if mxp < 4 {
|
||||||
// On a 2-core machine, setting maxprocs to 4 gives 10% better performance
|
// On a 2-core machine, setting maxprocs to 4 gives 10% better performance
|
||||||
@ -330,26 +328,3 @@ func main() {
|
|||||||
os.Exit(0)
|
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