diff options
author | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 11:54:00 -0700 |
---|---|---|
committer | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 11:54:00 -0700 |
commit | f154da9e12608589e8d5f0508f908a0c3e88a1bb (patch) | |
tree | f8255d51e10c6f1e0ed69702200b966c9556a431 /src/pkg/syscall/exec_unix.go | |
parent | 8d8329ed5dfb9622c82a9fbec6fd99a580f9c9f6 (diff) | |
download | golang-upstream/1.4.tar.gz |
Imported Upstream version 1.4upstream/1.4
Diffstat (limited to 'src/pkg/syscall/exec_unix.go')
-rw-r--r-- | src/pkg/syscall/exec_unix.go | 261 |
1 files changed, 0 insertions, 261 deletions
diff --git a/src/pkg/syscall/exec_unix.go b/src/pkg/syscall/exec_unix.go deleted file mode 100644 index 890bfdc22..000000000 --- a/src/pkg/syscall/exec_unix.go +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build darwin dragonfly freebsd linux netbsd openbsd solaris - -// Fork, exec, wait, etc. - -package syscall - -import ( - "runtime" - "sync" - "unsafe" -) - -// Lock synchronizing creation of new file descriptors with fork. -// -// We want the child in a fork/exec sequence to inherit only the -// file descriptors we intend. To do that, we mark all file -// descriptors close-on-exec and then, in the child, explicitly -// unmark the ones we want the exec'ed program to keep. -// Unix doesn't make this easy: there is, in general, no way to -// allocate a new file descriptor close-on-exec. Instead you -// have to allocate the descriptor and then mark it close-on-exec. -// If a fork happens between those two events, the child's exec -// will inherit an unwanted file descriptor. -// -// This lock solves that race: the create new fd/mark close-on-exec -// operation is done holding ForkLock for reading, and the fork itself -// is done holding ForkLock for writing. At least, that's the idea. -// There are some complications. -// -// Some system calls that create new file descriptors can block -// for arbitrarily long times: open on a hung NFS server or named -// pipe, accept on a socket, and so on. We can't reasonably grab -// the lock across those operations. -// -// It is worse to inherit some file descriptors than others. -// If a non-malicious child accidentally inherits an open ordinary file, -// that's not a big deal. On the other hand, if a long-lived child -// accidentally inherits the write end of a pipe, then the reader -// of that pipe will not see EOF until that child exits, potentially -// causing the parent program to hang. This is a common problem -// in threaded C programs that use popen. -// -// Luckily, the file descriptors that are most important not to -// inherit are not the ones that can take an arbitrarily long time -// to create: pipe returns instantly, and the net package uses -// non-blocking I/O to accept on a listening socket. -// The rules for which file descriptor-creating operations use the -// ForkLock are as follows: -// -// 1) Pipe. Does not block. Use the ForkLock. -// 2) Socket. Does not block. Use the ForkLock. -// 3) Accept. If using non-blocking mode, use the ForkLock. -// Otherwise, live with the race. -// 4) Open. Can block. Use O_CLOEXEC if available (Linux). -// Otherwise, live with the race. -// 5) Dup. Does not block. Use the ForkLock. -// On Linux, could use fcntl F_DUPFD_CLOEXEC -// instead of the ForkLock, but only for dup(fd, -1). - -var ForkLock sync.RWMutex - -// StringSlicePtr is deprecated. Use SlicePtrFromStrings instead. -// If any string contains a NUL byte this function panics instead -// of returning an error. -func StringSlicePtr(ss []string) []*byte { - bb := make([]*byte, len(ss)+1) - for i := 0; i < len(ss); i++ { - bb[i] = StringBytePtr(ss[i]) - } - bb[len(ss)] = nil - return bb -} - -// SlicePtrFromStrings converts a slice of strings to a slice of -// pointers to NUL-terminated byte slices. If any string contains -// a NUL byte, it returns (nil, EINVAL). -func SlicePtrFromStrings(ss []string) ([]*byte, error) { - var err error - bb := make([]*byte, len(ss)+1) - for i := 0; i < len(ss); i++ { - bb[i], err = BytePtrFromString(ss[i]) - if err != nil { - return nil, err - } - } - bb[len(ss)] = nil - return bb, nil -} - -func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) } - -func SetNonblock(fd int, nonblocking bool) (err error) { - flag, err := fcntl(fd, F_GETFL, 0) - if err != nil { - return err - } - if nonblocking { - flag |= O_NONBLOCK - } else { - flag &= ^O_NONBLOCK - } - _, err = fcntl(fd, F_SETFL, flag) - return err -} - -// Credential holds user and group identities to be assumed -// by a child process started by StartProcess. -type Credential struct { - Uid uint32 // User ID. - Gid uint32 // Group ID. - Groups []uint32 // Supplementary group IDs. -} - -// ProcAttr holds attributes that will be applied to a new process started -// by StartProcess. -type ProcAttr struct { - Dir string // Current working directory. - Env []string // Environment. - Files []uintptr // File descriptors. - Sys *SysProcAttr -} - -var zeroProcAttr ProcAttr -var zeroSysProcAttr SysProcAttr - -func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { - var p [2]int - var n int - var err1 Errno - var wstatus WaitStatus - - if attr == nil { - attr = &zeroProcAttr - } - sys := attr.Sys - if sys == nil { - sys = &zeroSysProcAttr - } - - p[0] = -1 - p[1] = -1 - - // Convert args to C form. - argv0p, err := BytePtrFromString(argv0) - if err != nil { - return 0, err - } - argvp, err := SlicePtrFromStrings(argv) - if err != nil { - return 0, err - } - envvp, err := SlicePtrFromStrings(attr.Env) - if err != nil { - return 0, err - } - - if (runtime.GOOS == "freebsd" || runtime.GOOS == "dragonfly") && len(argv[0]) > len(argv0) { - argvp[0] = argv0p - } - - var chroot *byte - if sys.Chroot != "" { - chroot, err = BytePtrFromString(sys.Chroot) - if err != nil { - return 0, err - } - } - var dir *byte - if attr.Dir != "" { - dir, err = BytePtrFromString(attr.Dir) - if err != nil { - return 0, err - } - } - - // Acquire the fork lock so that no other threads - // create new fds that are not yet close-on-exec - // before we fork. - ForkLock.Lock() - - // Allocate child status pipe close on exec. - if err = forkExecPipe(p[:]); err != nil { - goto error - } - - // Kick off child. - pid, err1 = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1]) - if err1 != 0 { - err = Errno(err1) - goto error - } - ForkLock.Unlock() - - // Read child error status from pipe. - Close(p[1]) - n, err = readlen(p[0], (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1))) - Close(p[0]) - if err != nil || n != 0 { - if n == int(unsafe.Sizeof(err1)) { - err = Errno(err1) - } - if err == nil { - err = EPIPE - } - - // Child failed; wait for it to exit, to make sure - // the zombies don't accumulate. - _, err1 := Wait4(pid, &wstatus, 0, nil) - for err1 == EINTR { - _, err1 = Wait4(pid, &wstatus, 0, nil) - } - return 0, err - } - - // Read got EOF, so pipe closed on exec, so exec succeeded. - return pid, nil - -error: - if p[0] >= 0 { - Close(p[0]) - Close(p[1]) - } - ForkLock.Unlock() - return 0, err -} - -// Combination of fork and exec, careful to be thread safe. -func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { - return forkExec(argv0, argv, attr) -} - -// StartProcess wraps ForkExec for package os. -func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) { - pid, err = forkExec(argv0, argv, attr) - return pid, 0, err -} - -// Ordinary exec. -func Exec(argv0 string, argv []string, envv []string) (err error) { - argv0p, err := BytePtrFromString(argv0) - if err != nil { - return err - } - argvp, err := SlicePtrFromStrings(argv) - if err != nil { - return err - } - envvp, err := SlicePtrFromStrings(envv) - if err != nil { - return err - } - _, _, err1 := RawSyscall(SYS_EXECVE, - uintptr(unsafe.Pointer(argv0p)), - uintptr(unsafe.Pointer(&argvp[0])), - uintptr(unsafe.Pointer(&envvp[0]))) - return Errno(err1) -} |