1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // +build darwin freebsd netbsd openbsd
13 type SysProcAttr struct {
14 Chroot string // Chroot.
15 Credential *Credential // Credential.
16 Ptrace bool // Enable tracing.
17 Setsid bool // Create session.
18 Setpgid bool // Set process group ID to new pid (SYSV setpgrp)
19 Setctty bool // Set controlling terminal to fd 0
20 Noctty bool // Detach fd 0 from controlling terminal
23 // Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
24 // If a dup or exec fails, write the errno error to pipe.
25 // (Pipe is close-on-exec so if exec succeeds, it will be closed.)
26 // In the child, this function must not acquire any locks, because
27 // they might have been locked at the time of the fork. This means
28 // no rescheduling, no malloc calls, and no new stack segments.
29 // The calls to RawSyscall are okay because they are assembly
30 // functions that do not grow the stack.
31 func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
32 // Declare all variables at top in case any
33 // declarations require heap allocation (e.g., err1).
41 fd := make([]int, len(attr.Files))
42 for i, ufd := range attr.Files {
46 // About to call fork.
47 // No more allocation or calls of non-assembly functions.
58 // Fork succeeded, now in child.
60 // Enable tracing if requested.
62 err1 = raw_ptrace(_PTRACE_TRACEME, 0, nil, nil)
78 err1 = raw_setpgid(0, 0)
86 err1 = raw_chroot(chroot)
93 if cred := sys.Credential; cred != nil {
94 ngroups := len(cred.Groups)
96 err2 := setgroups(0, nil)
103 groups := make([]Gid_t, ngroups)
104 for i, v := range cred.Groups {
107 err2 := setgroups(ngroups, &groups[0])
117 err2 := Setgid(int(cred.Gid))
122 err2 = Setuid(int(cred.Uid))
131 err1 = raw_chdir(dir)
137 // Pass 1: look for fd[i] < i and move those up above len(fd)
138 // so that pass 2 won't stomp on an fd it needs later.
139 nextfd = int(len(fd))
141 err1 = raw_dup2(pipe, nextfd)
145 raw_fcntl(nextfd, F_SETFD, FD_CLOEXEC)
149 for i = 0; i < len(fd); i++ {
150 if fd[i] >= 0 && fd[i] < int(i) {
151 err1 = raw_dup2(fd[i], nextfd)
155 raw_fcntl(nextfd, F_SETFD, FD_CLOEXEC)
158 if nextfd == pipe { // don't stomp on pipe
164 // Pass 2: dup fd[i] down onto i.
165 for i = 0; i < len(fd); i++ {
171 // dup2(i, i) won't clear close-on-exec flag on Linux,
172 // probably not elsewhere either.
173 _, err1 = raw_fcntl(fd[i], F_SETFD, 0)
179 // The new fd is created NOT close-on-exec,
180 // which is exactly what we want.
181 err1 = raw_dup2(fd[i], i)
187 // By convention, we don't close-on-exec the fds we are
188 // started with, so if len(fd) < 3, close 0, 1, 2 as needed.
189 // Programs that know they inherit fds >= 3 will need
190 // to set them close-on-exec.
191 for i = len(fd); i < 3; i++ {
195 // Detach fd 0 from tty
197 _, err1 = raw_ioctl(0, TIOCNOTTY, 0)
205 _, err1 = raw_ioctl(0, TIOCSCTTY, 0)
212 err1 = raw_execve(argv0, &argv[0], &envv[0])
215 // send error code on pipe
216 raw_write(pipe, (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1)))
221 // Calling panic is not actually safe,
222 // but the for loop above won't break
223 // and this shuts up the compiler.