OSDN Git Service

2011-01-13 Paolo Carlini <paolo.carlini@oracle.com>
[pf3gnuchains/gcc-fork.git] / libgo / syscalls / exec.go
1 // exec.go -- fork/exec syscall support.
2
3 // Copyright 2009 The Go Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file.
6
7 // Fork, exec, wait, etc.
8
9 package syscall
10
11 import "unsafe"
12
13 func libc_fcntl(fd int, cmd int, arg int) int __asm__ ("fcntl")
14 func libc_fork() Pid_t __asm__ ("fork")
15 func libc_chdir(name *byte) int __asm__ ("chdir");
16 func libc_dup2(int, int) int __asm__ ("dup2")
17 func libc_execve(*byte, **byte, **byte) int __asm__ ("execve")
18 func libc_sysexit(int) __asm__ ("_exit")
19 func libc_wait4(Pid_t, *int, int, *Rusage) Pid_t __asm__ ("wait4")
20
21 // Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
22 // If a dup or exec fails, write the errno int to pipe.
23 // (Pipe is close-on-exec so if exec succeeds, it will be closed.)
24 // In the child, this function must not acquire any locks, because
25 // they might have been locked at the time of the fork.  This means
26 // no rescheduling, no malloc calls, and no new stack segments.
27 func forkAndExecInChild(argv0 *byte, argv []*byte, envv []*byte, traceme bool, dir *byte, fd []int, pipe int) (pid int, err int) {
28         // Declare all variables at top in case any
29         // declarations require heap allocation (e.g., err1).
30         var r1, r2, err1 uintptr;
31         var nextfd int;
32         var i int;
33
34         darwin := OS == "darwin";
35
36         // About to call fork.
37         // No more allocation or calls of non-assembly functions.
38         child := libc_fork();
39         if child == -1 {
40                 return 0, GetErrno();
41         }
42
43         if child != 0 {
44                 // parent; return PID
45                 return int(child), 0
46         }
47
48         // Fork succeeded, now in child.
49
50         // Enable tracing if requested.
51         if traceme {
52                 if libc_ptrace(_PTRACE_TRACEME, 0, 0, nil) < 0 {
53                         goto childerror;
54                 }
55         }
56
57         // Chdir
58         if dir != nil {
59                 r := libc_chdir(dir);
60                 if r < 0 {
61                         goto childerror;
62                 }
63         }
64
65         // Pass 1: look for fd[i] < i and move those up above len(fd)
66         // so that pass 2 won't stomp on an fd it needs later.
67         nextfd = int(len(fd));
68         if pipe < nextfd {
69                 r := libc_dup2(pipe, nextfd);
70                 if r == -1 {
71                         goto childerror;
72                 }
73                 libc_fcntl(nextfd, F_SETFD, FD_CLOEXEC);
74                 pipe = nextfd;
75                 nextfd++;
76         }
77         for i = 0; i < len(fd); i++ {
78                 if fd[i] >= 0 && fd[i] < int(i) {
79                         r := libc_dup2(fd[i], nextfd);
80                         if r == -1 {
81                                 goto childerror;
82                         }
83                         libc_fcntl(nextfd, F_SETFD, FD_CLOEXEC);
84                         fd[i] = nextfd;
85                         nextfd++;
86                         if nextfd == pipe {     // don't stomp on pipe
87                                 nextfd++;
88                         }
89                 }
90         }
91
92         // Pass 2: dup fd[i] down onto i.
93         for i = 0; i < len(fd); i++ {
94                 if fd[i] == -1 {
95                         libc_close(i);
96                         continue;
97                 }
98                 if fd[i] == int(i) {
99                         // dup2(i, i) won't clear close-on-exec flag on Linux,
100                         // probably not elsewhere either.
101                         r := libc_fcntl(fd[i], F_SETFD, 0);
102                         if r != 0 {
103                                 goto childerror;
104                         }
105                         continue;
106                 }
107                 // The new fd is created NOT close-on-exec,
108                 // which is exactly what we want.
109                 r := libc_dup2(fd[i], i);
110                 if r == -1 {
111                         goto childerror;
112                 }
113         }
114
115         // By convention, we don't close-on-exec the fds we are
116         // started with, so if len(fd) < 3, close 0, 1, 2 as needed.
117         // Programs that know they inherit fds >= 3 will need
118         // to set them close-on-exec.
119         for i = len(fd); i < 3; i++ {
120                 libc_close(i);
121         }
122
123         // Time to exec.
124         libc_execve(argv0, &argv[0], &envv[0]);
125
126 childerror:
127         // send error code on pipe
128         var e uintptr = uintptr(GetErrno());
129         libc_write(pipe, (*byte)(unsafe.Pointer(&e)),
130                    Size_t(unsafe.Sizeof(err1)));
131         for {
132                 libc_sysexit(253)
133         }
134
135         // Calling panic is not actually safe,
136         // but the for loop above won't break
137         // and this shuts up the compiler.
138         panic("unreached");
139 }
140
141 func forkExec(argv0 string, argv []string, envv []string, traceme bool, dir string, fd []int) (pid int, err int) {
142         var p [2]int;
143         var r1 int;
144         var err1 uintptr;
145         var wstatus WaitStatus;
146
147         p[0] = -1;
148         p[1] = -1;
149
150         // Convert args to C form.
151         argv0p := StringBytePtr(argv0);
152         argvp := StringArrayPtr(argv);
153         envvp := StringArrayPtr(envv);
154         var dirp *byte;
155         if len(dir) > 0 {
156                 dirp = StringBytePtr(dir);
157         }
158
159         // Acquire the fork lock so that no other threads
160         // create new fds that are not yet close-on-exec
161         // before we fork.
162         ForkLock.Lock();
163
164         // Allocate child status pipe close on exec.
165         if err = Pipe(p[0:]); err != 0 {
166                 goto error;
167         }
168         var val int;
169         if val, err = fcntl(p[0], F_SETFD, FD_CLOEXEC); err != 0 {
170                 goto error;
171         }
172         if val, err = fcntl(p[1], F_SETFD, FD_CLOEXEC); err != 0 {
173                 goto error;
174         }
175
176         // Kick off child.
177         pid, err = forkAndExecInChild(argv0p, argvp, envvp, traceme, dirp, fd, p[1]);
178         if err != 0 {
179         error:
180                 if p[0] >= 0 {
181                         Close(p[0]);
182                         Close(p[1]);
183                 }
184                 ForkLock.Unlock();
185                 return 0, err
186         }
187         ForkLock.Unlock();
188
189         // Read child error status from pipe.
190         Close(p[1]);
191         n := libc_read(p[0], (*byte)(unsafe.Pointer(&err1)),
192                        Size_t(unsafe.Sizeof(err1)));
193         err = 0;
194         if n < 0 {
195                 err = GetErrno();
196         }
197         Close(p[0]);
198         if err != 0 || n != 0 {
199                 if int(n) == unsafe.Sizeof(err1) {
200                         err = int(err1);
201                 }
202                 if err == 0 {
203                         err = EPIPE;
204                 }
205
206                 // Child failed; wait for it to exit, to make sure
207                 // the zombies don't accumulate.
208                 pid1, err1 := Wait4(pid, &wstatus, 0, nil);
209                 for err1 == EINTR {
210                         pid1, err1 = Wait4(pid, &wstatus, 0, nil);
211                 }
212                 return 0, err
213         }
214
215         // Read got EOF, so pipe closed on exec, so exec succeeded.
216         return pid, 0
217 }
218
219 // Combination of fork and exec, careful to be thread safe.
220 func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int) (pid int, err int) {
221         return forkExec(argv0, argv, envv, false, dir, fd);
222 }
223
224 // PtraceForkExec is like ForkExec, but starts the child in a traced state.
225 func PtraceForkExec(argv0 string, argv []string, envv []string, dir string, fd []int) (pid int, err int) {
226         return forkExec(argv0, argv, envv, true, dir, fd);
227 }
228
229 // Ordinary exec.
230 func Exec(argv0 string, argv []string, envv []string) (err int) {
231         argv_arg := StringArrayPtr(argv);
232         envv_arg := StringArrayPtr(envv);
233         libc_execve(StringBytePtr(argv0), &argv_arg[0], &envv_arg[0]);
234         return GetErrno();
235 }
236
237 func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, errno int) {
238         var status int;
239         r := libc_wait4(Pid_t(pid), &status, options, rusage);
240         wpid = int(r);
241         if r < 0 {
242                 errno = GetErrno();
243         }
244         if wstatus != nil {
245                 *wstatus = WaitStatus(status);
246         }
247         return;
248 }