OSDN Git Service

75f0f45adaff6a25143f87784147e41e16b61f6f
[pf3gnuchains/gcc-fork.git] / libgo / go / syscall / exec_unix.go
1 // Copyright 2009 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 linux netbsd openbsd
6
7 // Fork, exec, wait, etc.
8
9 package syscall
10
11 import (
12         "runtime"
13         "sync"
14         "unsafe"
15 )
16
17 //sysnb raw_fork() (pid Pid_t, err Errno)
18 //fork() Pid_t
19
20 //sysnb raw_setsid() (err Errno)
21 //setsid() Pid_t
22
23 //sysnb raw_setpgid(pid int, pgid int) (err Errno)
24 //setpgid(pid Pid_t, pgid Pid_t) int
25
26 //sysnb raw_chroot(path *byte) (err Errno)
27 //chroot(path *byte) int
28
29 //sysnb raw_chdir(path *byte) (err Errno)
30 //chdir(path *byte) int
31
32 //sysnb raw_fcntl(fd int, cmd int, arg int) (val int, err Errno)
33 //fcntl(fd int, cmd int, arg int) int
34
35 //sysnb raw_close(fd int) (err Errno)
36 //close(fd int) int
37
38 //sysnb raw_ioctl(fd int, cmd int, val int) (rval int, err Errno)
39 //ioctl(fd int, cmd int, val int) int
40
41 //sysnb raw_execve(argv0 *byte, argv **byte, envv **byte) (err Errno)
42 //execve(argv0 *byte, argv **byte, envv **byte) int
43
44 //sysnb raw_write(fd int, buf *byte, count int) (err Errno)
45 //write(fd int, buf *byte, count Size_t) Ssize_t
46
47 //sysnb raw_exit(status int)
48 //_exit(status int)
49
50 // Note: not raw, returns error rather than Errno.
51 //sys   read(fd int, p *byte, np int) (n int, err error)
52 //read(fd int, buf *byte, count Size_t) Ssize_t
53
54 // Lock synchronizing creation of new file descriptors with fork.
55 //
56 // We want the child in a fork/exec sequence to inherit only the
57 // file descriptors we intend.  To do that, we mark all file
58 // descriptors close-on-exec and then, in the child, explicitly
59 // unmark the ones we want the exec'ed program to keep.
60 // Unix doesn't make this easy: there is, in general, no way to
61 // allocate a new file descriptor close-on-exec.  Instead you
62 // have to allocate the descriptor and then mark it close-on-exec.
63 // If a fork happens between those two events, the child's exec
64 // will inherit an unwanted file descriptor.
65 //
66 // This lock solves that race: the create new fd/mark close-on-exec
67 // operation is done holding ForkLock for reading, and the fork itself
68 // is done holding ForkLock for writing.  At least, that's the idea.
69 // There are some complications.
70 //
71 // Some system calls that create new file descriptors can block
72 // for arbitrarily long times: open on a hung NFS server or named
73 // pipe, accept on a socket, and so on.  We can't reasonably grab
74 // the lock across those operations.
75 //
76 // It is worse to inherit some file descriptors than others.
77 // If a non-malicious child accidentally inherits an open ordinary file,
78 // that's not a big deal.  On the other hand, if a long-lived child
79 // accidentally inherits the write end of a pipe, then the reader
80 // of that pipe will not see EOF until that child exits, potentially
81 // causing the parent program to hang.  This is a common problem
82 // in threaded C programs that use popen.
83 //
84 // Luckily, the file descriptors that are most important not to
85 // inherit are not the ones that can take an arbitrarily long time
86 // to create: pipe returns instantly, and the net package uses
87 // non-blocking I/O to accept on a listening socket.
88 // The rules for which file descriptor-creating operations use the
89 // ForkLock are as follows:
90 //
91 // 1) Pipe.    Does not block.  Use the ForkLock.
92 // 2) Socket.  Does not block.  Use the ForkLock.
93 // 3) Accept.  If using non-blocking mode, use the ForkLock.
94 //             Otherwise, live with the race.
95 // 4) Open.    Can block.  Use O_CLOEXEC if available (GNU/Linux).
96 //             Otherwise, live with the race.
97 // 5) Dup.     Does not block.  Use the ForkLock.
98 //             On GNU/Linux, could use fcntl F_DUPFD_CLOEXEC
99 //             instead of the ForkLock, but only for dup(fd, -1).
100
101 var ForkLock sync.RWMutex
102
103 // Convert array of string to array
104 // of NUL-terminated byte pointer.
105 func StringSlicePtr(ss []string) []*byte {
106         bb := make([]*byte, len(ss)+1)
107         for i := 0; i < len(ss); i++ {
108                 bb[i] = StringBytePtr(ss[i])
109         }
110         bb[len(ss)] = nil
111         return bb
112 }
113
114 func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) }
115
116 func SetNonblock(fd int, nonblocking bool) (err error) {
117         flag, err := fcntl(fd, F_GETFL, 0)
118         if err != nil {
119                 return err
120         }
121         if nonblocking {
122                 flag |= O_NONBLOCK
123         } else {
124                 flag &= ^O_NONBLOCK
125         }
126         _, err = fcntl(fd, F_SETFL, flag)
127         return err
128 }
129
130 // Credential holds user and group identities to be assumed
131 // by a child process started by StartProcess.
132 type Credential struct {
133         Uid    uint32   // User ID.
134         Gid    uint32   // Group ID.
135         Groups []uint32 // Supplementary group IDs.
136 }
137
138 // ProcAttr holds attributes that will be applied to a new process started
139 // by StartProcess.
140 type ProcAttr struct {
141         Dir   string   // Current working directory.
142         Env   []string // Environment.
143         Files []int    // File descriptors.
144         Sys   *SysProcAttr
145 }
146
147 var zeroProcAttr ProcAttr
148 var zeroSysProcAttr SysProcAttr
149
150 func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
151         var p [2]int
152         var n int
153         var err1 Errno
154         var wstatus WaitStatus
155
156         if attr == nil {
157                 attr = &zeroProcAttr
158         }
159         sys := attr.Sys
160         if sys == nil {
161                 sys = &zeroSysProcAttr
162         }
163
164         p[0] = -1
165         p[1] = -1
166
167         // Convert args to C form.
168         argv0p := StringBytePtr(argv0)
169         argvp := StringSlicePtr(argv)
170         envvp := StringSlicePtr(attr.Env)
171
172         if runtime.GOOS == "freebsd" && len(argv[0]) > len(argv0) {
173                 argvp[0] = argv0p
174         }
175
176         var chroot *byte
177         if sys.Chroot != "" {
178                 chroot = StringBytePtr(sys.Chroot)
179         }
180         var dir *byte
181         if attr.Dir != "" {
182                 dir = StringBytePtr(attr.Dir)
183         }
184
185         // Acquire the fork lock so that no other threads
186         // create new fds that are not yet close-on-exec
187         // before we fork.
188         ForkLock.Lock()
189
190         // Allocate child status pipe close on exec.
191         if err = Pipe(p[0:]); err != nil {
192                 goto error
193         }
194         if _, err = fcntl(p[0], F_SETFD, FD_CLOEXEC); err != nil {
195                 goto error
196         }
197         if _, err = fcntl(p[1], F_SETFD, FD_CLOEXEC); err != nil {
198                 goto error
199         }
200
201         // Kick off child.
202         pid, err1 = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1])
203         if err1 != 0 {
204                 goto error
205         }
206         ForkLock.Unlock()
207
208         // Read child error status from pipe.
209         Close(p[1])
210         n, err = read(p[0], (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1)))
211         Close(p[0])
212         if err != nil || n != 0 {
213                 if n == int(unsafe.Sizeof(err1)) {
214                         err = Errno(err1)
215                 }
216                 if err == nil {
217                         err = EPIPE
218                 }
219
220                 // Child failed; wait for it to exit, to make sure
221                 // the zombies don't accumulate.
222                 _, err1 := Wait4(pid, &wstatus, 0, nil)
223                 for err1 == EINTR {
224                         _, err1 = Wait4(pid, &wstatus, 0, nil)
225                 }
226                 return 0, err
227         }
228
229         // Read got EOF, so pipe closed on exec, so exec succeeded.
230         return pid, nil
231
232 error:
233         if p[0] >= 0 {
234                 Close(p[0])
235                 Close(p[1])
236         }
237         ForkLock.Unlock()
238         return 0, err
239 }
240
241 // Combination of fork and exec, careful to be thread safe.
242 func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
243         return forkExec(argv0, argv, attr)
244 }
245
246 // StartProcess wraps ForkExec for package os.
247 func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
248         pid, err = forkExec(argv0, argv, attr)
249         return pid, 0, err
250 }
251
252 // Ordinary exec.
253 func Exec(argv0 string, argv []string, envv []string) (err error) {
254         err1 := raw_execve(StringBytePtr(argv0),
255                 &StringSlicePtr(argv)[0],
256                 &StringSlicePtr(envv)[0])
257         return Errno(err1)
258 }