OSDN Git Service

9ef3eb006522906ef526281567104b8e5afad964
[pf3gnuchains/gcc-fork.git] / libgo / go / syscall / exec_bsd.go
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.
4
5 // +build darwin freebsd netbsd openbsd
6
7 package syscall
8
9 import (
10         "unsafe"
11 )
12
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
21 }
22
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).
34         var (
35                 r1     Pid_t
36                 err1   Errno
37                 nextfd int
38                 i      int
39         )
40
41         // guard against side effects of shuffling fds below.
42         fd := append([]int(nil), attr.Files...)
43
44         // About to call fork.
45         // No more allocation or calls of non-assembly functions.
46         r1, err1 = raw_fork()
47         if err1 != 0 {
48                 return 0, err1
49         }
50
51         if r1 != 0 {
52                 // parent; return PID
53                 return int(r1), 0
54         }
55
56         // Fork succeeded, now in child.
57
58         // Enable tracing if requested.
59         if sys.Ptrace {
60                 err1 = raw_ptrace(_PTRACE_TRACEME, 0, nil, nil)
61                 if err1 != 0 {
62                         goto childerror
63                 }
64         }
65
66         // Session ID
67         if sys.Setsid {
68                 err1 = raw_setsid()
69                 if err1 != 0 {
70                         goto childerror
71                 }
72         }
73
74         // Set process group
75         if sys.Setpgid {
76                 err1 = raw_setpgid(0, 0)
77                 if err1 != 0 {
78                         goto childerror
79                 }
80         }
81
82         // Chroot
83         if chroot != nil {
84                 err1 = raw_chroot(chroot)
85                 if err1 != 0 {
86                         goto childerror
87                 }
88         }
89
90         // User and groups
91         if cred := sys.Credential; cred != nil {
92                 ngroups := len(cred.Groups)
93                 if ngroups == 0 {
94                         err2 := setgroups(0, nil)
95                         if err2 == nil {
96                                 err1 = 0
97                         } else {
98                                 err1 = err2.(Errno)
99                         }
100                 } else {
101                         groups := make([]Gid_t, ngroups)
102                         for i, v := range cred.Groups {
103                                 groups[i] = Gid_t(v)
104                         }
105                         err2 := setgroups(ngroups, &groups[0])
106                         if err2 == nil {
107                                 err1 = 0
108                         } else {
109                                 err1 = err2.(Errno)
110                         }
111                 }
112                 if err1 != 0 {
113                         goto childerror
114                 }
115                 err2 := Setgid(int(cred.Gid))
116                 if err2 != nil {
117                         err1 = err2.(Errno)
118                         goto childerror
119                 }
120                 err2 = Setuid(int(cred.Uid))
121                 if err2 != nil {
122                         err1 = err2.(Errno)
123                         goto childerror
124                 }
125         }
126
127         // Chdir
128         if dir != nil {
129                 err1 = raw_chdir(dir)
130                 if err1 != 0 {
131                         goto childerror
132                 }
133         }
134
135         // Pass 1: look for fd[i] < i and move those up above len(fd)
136         // so that pass 2 won't stomp on an fd it needs later.
137         nextfd = int(len(fd))
138         if pipe < nextfd {
139                 _, err2 := Dup2(pipe, nextfd)
140                 if err2 != nil {
141                         err1 = err2.(Errno)
142                         goto childerror
143                 }
144                 raw_fcntl(nextfd, F_SETFD, FD_CLOEXEC)
145                 pipe = nextfd
146                 nextfd++
147         }
148         for i = 0; i < len(fd); i++ {
149                 if fd[i] >= 0 && fd[i] < int(i) {
150                         _, err2 := Dup2(fd[i], nextfd)
151                         if err2 != nil {
152                                 err1 = err2.(Errno)
153                                 goto childerror
154                         }
155                         raw_fcntl(nextfd, F_SETFD, FD_CLOEXEC)
156                         fd[i] = nextfd
157                         nextfd++
158                         if nextfd == pipe { // don't stomp on pipe
159                                 nextfd++
160                         }
161                 }
162         }
163
164         // Pass 2: dup fd[i] down onto i.
165         for i = 0; i < len(fd); i++ {
166                 if fd[i] == -1 {
167                         raw_close(i)
168                         continue
169                 }
170                 if fd[i] == int(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)
174                         if err1 != 0 {
175                                 goto childerror
176                         }
177                         continue
178                 }
179                 // The new fd is created NOT close-on-exec,
180                 // which is exactly what we want.
181                 _, err2 := Dup2(fd[i], i)
182                 if err1 != 0 {
183                         err1 = err2.(Errno)
184                         goto childerror
185                 }
186         }
187
188         // By convention, we don't close-on-exec the fds we are
189         // started with, so if len(fd) < 3, close 0, 1, 2 as needed.
190         // Programs that know they inherit fds >= 3 will need
191         // to set them close-on-exec.
192         for i = len(fd); i < 3; i++ {
193                 raw_close(i)
194         }
195
196         // Detach fd 0 from tty
197         if sys.Noctty {
198                 _, err1 = raw_ioctl(0, TIOCNOTTY, 0)
199                 if err1 != 0 {
200                         goto childerror
201                 }
202         }
203
204         // Make fd 0 the tty
205         if sys.Setctty {
206                 _, err1 = raw_ioctl(0, TIOCSCTTY, 0)
207                 if err1 != 0 {
208                         goto childerror
209                 }
210         }
211
212         // Time to exec.
213         err1 = raw_execve(argv0, &argv[0], &envv[0])
214
215 childerror:
216         // send error code on pipe
217         raw_write(pipe, (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1)))
218         for {
219                 raw_exit(253)
220         }
221
222         // Calling panic is not actually safe,
223         // but the for loop above won't break
224         // and this shuts up the compiler.
225         panic("unreached")
226 }