OSDN Git Service

libgo: Update to weekly.2012-01-15.
[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         "runtime"
11         "unsafe"
12 )
13
14 type SysProcAttr struct {
15         Chroot     string      // Chroot.
16         Credential *Credential // Credential.
17         Ptrace     bool        // Enable tracing.
18         Setsid     bool        // Create session.
19         Setpgid    bool        // Set process group ID to new pid (SYSV setpgrp)
20         Setctty    bool        // Set controlling terminal to fd 0
21         Noctty     bool        // Detach fd 0 from controlling terminal
22 }
23
24 // Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
25 // If a dup or exec fails, write the errno error to pipe.
26 // (Pipe is close-on-exec so if exec succeeds, it will be closed.)
27 // In the child, this function must not acquire any locks, because
28 // they might have been locked at the time of the fork.  This means
29 // no rescheduling, no malloc calls, and no new stack segments.
30 // The calls to RawSyscall are okay because they are assembly
31 // functions that do not grow the stack.
32 func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
33         // Declare all variables at top in case any
34         // declarations require heap allocation (e.g., err1).
35         var (
36                 r1     Pid_t
37                 err1   Errno
38                 nextfd int
39                 i      int
40         )
41
42         // guard against side effects of shuffling fds below.
43         fd := append([]int(nil), attr.Files...)
44
45         // About to call fork.
46         // No more allocation or calls of non-assembly functions.
47         r1, err1 = raw_fork()
48         if err1 != 0 {
49                 return 0, err1
50         }
51
52         if r1 != 0 {
53                 // parent; return PID
54                 return int(r1), 0
55         }
56
57         // Fork succeeded, now in child.
58
59         // Enable tracing if requested.
60         if sys.Ptrace {
61                 err1 = raw_trace(_PTRACE_TRACEME, 0, nil, nil)
62                 if err1 != 0 {
63                         goto childerror
64                 }
65         }
66
67         // Session ID
68         if sys.Setsid {
69                 err1 = raw_setsid()
70                 if err1 != 0 {
71                         goto childerror
72                 }
73         }
74
75         // Set process group
76         if sys.Setpgid {
77                 err1 = raw_setpgid(0, 0)
78                 if err1 != 0 {
79                         goto childerror
80                 }
81         }
82
83         // Chroot
84         if chroot != nil {
85                 err1 = raw_chroot(chroot)
86                 if err1 != 0 {
87                         goto childerror
88                 }
89         }
90
91         // User and groups
92         if cred := sys.Credential; cred != nil {
93                 ngroups := len(cred.Groups)
94                 if ngroups == 0 {
95                         err2 := setgroups(0, nil)
96                         if err2 == nil {
97                                 err1 = 0
98                         } else {
99                                 err1 = err2.(Errno)
100                         }
101                 } else {
102                         groups := make([]Gid_t, ngroups)
103                         for i, v := range cred.Groups {
104                                 groups[i] = Gid_t(v)
105                         }
106                         err2 := setgroups(ngroups, &groups[0])
107                         if err2 == nil {
108                                 err1 = 0
109                         } else {
110                                 err1 = err2.(Errno)
111                         }
112                 }
113                 if err1 != 0 {
114                         goto childerror
115                 }
116                 err2 := Setgid(int(cred.Gid))
117                 if err2 != nil {
118                         err1 = err2.(Errno)
119                         goto childerror
120                 }
121                 err2 = Setuid(int(cred.Uid))
122                 if err2 != nil {
123                         err1 = err2.(Errno)
124                         goto childerror
125                 }
126         }
127
128         // Chdir
129         if dir != nil {
130                 err1 = raw_chdir(dir)
131                 if err1 != 0 {
132                         goto childerror
133                 }
134         }
135
136         // Pass 1: look for fd[i] < i and move those up above len(fd)
137         // so that pass 2 won't stomp on an fd it needs later.
138         nextfd = int(len(fd))
139         if pipe < nextfd {
140                 _, err2 := Dup2(pipe, nextfd)
141                 if err2 != nil {
142                         err1 = err2.(Errno)
143                         goto childerror
144                 }
145                 raw_fcntl(nextfd, F_SETFD, FD_CLOEXEC)
146                 pipe = nextfd
147                 nextfd++
148         }
149         for i = 0; i < len(fd); i++ {
150                 if fd[i] >= 0 && fd[i] < int(i) {
151                         _, err2 := Dup2(fd[i], nextfd)
152                         if err2 != nil {
153                                 err1 = err2.(Errno)
154                                 goto childerror
155                         }
156                         raw_fcntl(nextfd, F_SETFD, F_CLOEXEC)
157                         fd[i] = nextfd
158                         nextfd++
159                         if nextfd == pipe { // don't stomp on pipe
160                                 nextfd++
161                         }
162                 }
163         }
164
165         // Pass 2: dup fd[i] down onto i.
166         for i = 0; i < len(fd); i++ {
167                 if fd[i] == -1 {
168                         raw_close(i)
169                         continue
170                 }
171                 if fd[i] == int(i) {
172                         // dup2(i, i) won't clear close-on-exec flag on Linux,
173                         // probably not elsewhere either.
174                         _, err1 = raw_fcntl(fd[i], F_SETFD, 0)
175                         if err1 != 0 {
176                                 goto childerror
177                         }
178                         continue
179                 }
180                 // The new fd is created NOT close-on-exec,
181                 // which is exactly what we want.
182                 _, err2 := Dup2(fd[i], i)
183                 if err1 != 0 {
184                         err1 = err2.(Errno)
185                         goto childerror
186                 }
187         }
188
189         // By convention, we don't close-on-exec the fds we are
190         // started with, so if len(fd) < 3, close 0, 1, 2 as needed.
191         // Programs that know they inherit fds >= 3 will need
192         // to set them close-on-exec.
193         for i = len(fd); i < 3; i++ {
194                 raw_close(i)
195         }
196
197         // Detach fd 0 from tty
198         if sys.Noctty {
199                 _, err1 = raw_ioctl(0, IOTCNOTTY, 0)
200                 if err1 != 0 {
201                         goto childerror
202                 }
203         }
204
205         // Make fd 0 the tty
206         if sys.Setctty {
207                 _, err1 = raw_ioctl(TIOCSCTTY, 0)
208                 if err1 != 0 {
209                         goto childerror
210                 }
211         }
212
213         // Time to exec.
214         err1 = raw_execve(argv0, &argv[0], &envv[0])
215
216 childerror:
217         // send error code on pipe
218         raw_write(pipe, (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1)))
219         for {
220                 raw_exit(253)
221         }
222
223         // Calling panic is not actually safe,
224         // but the for loop above won't break
225         // and this shuts up the compiler.
226         panic("unreached")
227 }