| // +build !windows |
| |
| package utils |
| |
| import ( |
| "fmt" |
| "os" |
| "strconv" |
| |
| "golang.org/x/sys/unix" |
| ) |
| |
| // EnsureProcHandle returns whether or not the given file handle is on procfs. |
| func EnsureProcHandle(fh *os.File) error { |
| var buf unix.Statfs_t |
| if err := unix.Fstatfs(int(fh.Fd()), &buf); err != nil { |
| return fmt.Errorf("ensure %s is on procfs: %v", fh.Name(), err) |
| } |
| if buf.Type != unix.PROC_SUPER_MAGIC { |
| return fmt.Errorf("%s is not on procfs", fh.Name()) |
| } |
| return nil |
| } |
| |
| // CloseExecFrom applies O_CLOEXEC to all file descriptors currently open for |
| // the process (except for those below the given fd value). |
| func CloseExecFrom(minFd int) error { |
| fdDir, err := os.Open("/proc/self/fd") |
| if err != nil { |
| return err |
| } |
| defer fdDir.Close() |
| |
| if err := EnsureProcHandle(fdDir); err != nil { |
| return err |
| } |
| |
| fdList, err := fdDir.Readdirnames(-1) |
| if err != nil { |
| return err |
| } |
| for _, fdStr := range fdList { |
| fd, err := strconv.Atoi(fdStr) |
| // Ignore non-numeric file names. |
| if err != nil { |
| continue |
| } |
| // Ignore descriptors lower than our specified minimum. |
| if fd < minFd { |
| continue |
| } |
| // Intentionally ignore errors from unix.CloseOnExec -- the cases where |
| // this might fail are basically file descriptors that have already |
| // been closed (including and especially the one that was created when |
| // ioutil.ReadDir did the "opendir" syscall). |
| unix.CloseOnExec(fd) |
| } |
| return nil |
| } |
| |
| // NewSockPair returns a new unix socket pair |
| func NewSockPair(name string) (parent *os.File, child *os.File, err error) { |
| fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0) |
| if err != nil { |
| return nil, nil, err |
| } |
| return os.NewFile(uintptr(fds[1]), name+"-p"), os.NewFile(uintptr(fds[0]), name+"-c"), nil |
| } |