exec_unix.go 7.89 KB
Newer Older
1 2 3 4
// 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.

5 6
// +build darwin freebsd linux netbsd openbsd

7 8 9 10
// Fork, exec, wait, etc.

package syscall

11
import (
12
	"runtime"
13 14 15 16
	"sync"
	"unsafe"
)

17
//sysnb	raw_fork() (pid Pid_t, err Errno)
18 19
//fork() Pid_t

20
//sysnb raw_setsid() (err Errno)
21 22
//setsid() Pid_t

23
//sysnb raw_setpgid(pid int, pgid int) (err Errno)
24
//setpgid(pid Pid_t, pgid Pid_t) _C_int
25 26

//sysnb	raw_chroot(path *byte) (err Errno)
27
//chroot(path *byte) _C_int
28

29
//sysnb	raw_chdir(path *byte) (err Errno)
30
//chdir(path *byte) _C_int
31

32
//sysnb	raw_fcntl(fd int, cmd int, arg int) (val int, err Errno)
33
//fcntl(fd _C_int, cmd _C_int, arg _C_int) _C_int
34

35
//sysnb	raw_close(fd int) (err Errno)
36
//close(fd _C_int) _C_int
37

38
//sysnb	raw_ioctl(fd int, cmd int, val int) (rval int, err Errno)
39
//ioctl(fd _C_int, cmd _C_int, val _C_int) _C_int
40

41
//sysnb	raw_execve(argv0 *byte, argv **byte, envv **byte) (err Errno)
42
//execve(argv0 *byte, argv **byte, envv **byte) _C_int
43

44
//sysnb	raw_write(fd int, buf *byte, count int) (err Errno)
45
//write(fd _C_int, buf *byte, count Size_t) Ssize_t
46 47

//sysnb	raw_exit(status int)
48
//_exit(status _C_int)
49

50
//sysnb raw_dup2(oldfd int, newfd int) (err Errno)
51
//dup2(oldfd _C_int, newfd _C_int) _C_int
52

53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
// 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.
94
// 4) Open.    Can block.  Use O_CLOEXEC if available (GNU/Linux).
95 96
//             Otherwise, live with the race.
// 5) Dup.     Does not block.  Use the ForkLock.
97
//             On GNU/Linux, could use fcntl F_DUPFD_CLOEXEC
98 99 100 101
//             instead of the ForkLock, but only for dup(fd, -1).

var ForkLock sync.RWMutex

102
// StringSlicePtr is deprecated. Use SlicePtrFromStrings instead.
103 104
// If any string contains a NUL byte this function panics instead
// of returning an error.
105 106 107 108 109 110 111 112 113
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
}

114
// SlicePtrFromStrings converts a slice of strings to a slice of
115 116
// pointers to NUL-terminated byte slices. If any string contains
// a NUL byte, it returns (nil, EINVAL).
117
func SlicePtrFromStrings(ss []string) ([]*byte, error) {
118 119 120
	var err error
	bb := make([]*byte, len(ss)+1)
	for i := 0; i < len(ss); i++ {
121
		bb[i], err = BytePtrFromString(ss[i])
122 123 124 125 126 127 128 129
		if err != nil {
			return nil, err
		}
	}
	bb[len(ss)] = nil
	return bb, nil
}

130 131
func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) }

132
func SetNonblock(fd int, nonblocking bool) (err error) {
133
	flag, err := fcntl(fd, F_GETFL, 0)
134
	if err != nil {
135 136 137 138 139 140 141 142 143 144
		return err
	}
	if nonblocking {
		flag |= O_NONBLOCK
	} else {
		flag &= ^O_NONBLOCK
	}
	_, err = fcntl(fd, F_SETFL, flag)
	return err
}
145

146 147 148 149 150 151 152
// 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.
}
153

154 155
// ProcAttr holds attributes that will be applied to a new process started
// by StartProcess.
156
type ProcAttr struct {
157 158 159
	Dir   string    // Current working directory.
	Env   []string  // Environment.
	Files []uintptr // File descriptors.
160
	Sys   *SysProcAttr
161 162
}

163 164
var zeroProcAttr ProcAttr
var zeroSysProcAttr SysProcAttr
165

166
func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
167
	var p [2]int
168
	var n int
169
	var err1 Errno
170
	var wstatus WaitStatus
171

172
	if attr == nil {
173 174 175 176 177
		attr = &zeroProcAttr
	}
	sys := attr.Sys
	if sys == nil {
		sys = &zeroSysProcAttr
178 179
	}

180 181
	p[0] = -1
	p[1] = -1
182 183

	// Convert args to C form.
184
	argv0p, err := BytePtrFromString(argv0)
185 186 187
	if err != nil {
		return 0, err
	}
188
	argvp, err := SlicePtrFromStrings(argv)
189 190 191
	if err != nil {
		return 0, err
	}
192
	envvp, err := SlicePtrFromStrings(attr.Env)
193 194 195
	if err != nil {
		return 0, err
	}
196

197
	if runtime.GOOS == "freebsd" && len(argv[0]) > len(argv0) {
198 199 200
		argvp[0] = argv0p
	}

201 202
	var chroot *byte
	if sys.Chroot != "" {
203
		chroot, err = BytePtrFromString(sys.Chroot)
204 205 206
		if err != nil {
			return 0, err
		}
207
	}
208 209
	var dir *byte
	if attr.Dir != "" {
210
		dir, err = BytePtrFromString(attr.Dir)
211 212 213
		if err != nil {
			return 0, err
		}
214 215 216 217 218
	}

	// Acquire the fork lock so that no other threads
	// create new fds that are not yet close-on-exec
	// before we fork.
219
	ForkLock.Lock()
220 221

	// Allocate child status pipe close on exec.
222
	if err = forkExecPipe(p[:]); err != nil {
223
		goto error
224 225 226
	}

	// Kick off child.
227 228
	pid, err1 = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1])
	if err1 != 0 {
229
		goto error
230
	}
231
	ForkLock.Unlock()
232 233

	// Read child error status from pipe.
234
	Close(p[1])
235
	n, err = readlen(p[0], (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1)))
236
	Close(p[0])
237
	if err != nil || n != 0 {
238
		if n == int(unsafe.Sizeof(err1)) {
239
			err = Errno(err1)
240
		}
241
		if err == nil {
242
			err = EPIPE
243 244 245 246
		}

		// Child failed; wait for it to exit, to make sure
		// the zombies don't accumulate.
247
		_, err1 := Wait4(pid, &wstatus, 0, nil)
248
		for err1 == EINTR {
249
			_, err1 = Wait4(pid, &wstatus, 0, nil)
250 251 252 253 254
		}
		return 0, err
	}

	// Read got EOF, so pipe closed on exec, so exec succeeded.
255
	return pid, nil
256 257 258 259 260 261 262 263

error:
	if p[0] >= 0 {
		Close(p[0])
		Close(p[1])
	}
	ForkLock.Unlock()
	return 0, err
264 265 266
}

// Combination of fork and exec, careful to be thread safe.
267
func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
268
	return forkExec(argv0, argv, attr)
269 270
}

271
// StartProcess wraps ForkExec for package os.
272
func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
273 274
	pid, err = forkExec(argv0, argv, attr)
	return pid, 0, err
275 276 277
}

// Ordinary exec.
278
func Exec(argv0 string, argv []string, envv []string) (err error) {
279
	argv0p, err := BytePtrFromString(argv0)
280 281 282
	if err != nil {
		return err
	}
283
	argvp, err := SlicePtrFromStrings(argv)
284 285 286
	if err != nil {
		return err
	}
287
	envvp, err := SlicePtrFromStrings(envv)
288 289 290 291
	if err != nil {
		return err
	}
	err1 := raw_execve(argv0p, &argvp[0], &envvp[0])
292
	return Errno(err1)
293
}