aboutsummaryrefslogtreecommitdiff
path: root/internal/ensurefds012/ensurefds012.go
blob: 54a1ac165a0579947cb6bd59b4f1e1dd5859846a (plain)
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
// 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/v2/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.
package ensurefds012

import (
	"os"
	"syscall"

	"github.com/rfjakob/gocryptfs/v2/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)
}