OSDN Git Service

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