Source file
src/syscall/exec_unix.go
Documentation: syscall
1
2
3
4
5
6
7
8
9
10 package syscall
11
12 import (
13 errorspkg "errors"
14 "internal/bytealg"
15 "runtime"
16 "sync"
17 "unsafe"
18 )
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67 var ForkLock sync.RWMutex
68
69
70
71
72
73
74 func StringSlicePtr(ss []string) []*byte {
75 bb := make([]*byte, len(ss)+1)
76 for i := 0; i < len(ss); i++ {
77 bb[i] = StringBytePtr(ss[i])
78 }
79 bb[len(ss)] = nil
80 return bb
81 }
82
83
84
85
86 func SlicePtrFromStrings(ss []string) ([]*byte, error) {
87 n := 0
88 for _, s := range ss {
89 if bytealg.IndexByteString(s, 0) != -1 {
90 return nil, EINVAL
91 }
92 n += len(s) + 1
93 }
94 bb := make([]*byte, len(ss)+1)
95 b := make([]byte, n)
96 n = 0
97 for i, s := range ss {
98 bb[i] = &b[n]
99 copy(b[n:], s)
100 n += len(s) + 1
101 }
102 return bb, nil
103 }
104
105 func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) }
106
107 func SetNonblock(fd int, nonblocking bool) (err error) {
108 flag, err := fcntl(fd, F_GETFL, 0)
109 if err != nil {
110 return err
111 }
112 if nonblocking {
113 flag |= O_NONBLOCK
114 } else {
115 flag &^= O_NONBLOCK
116 }
117 _, err = fcntl(fd, F_SETFL, flag)
118 return err
119 }
120
121
122
123 type Credential struct {
124 Uid uint32
125 Gid uint32
126 Groups []uint32
127 NoSetGroups bool
128 }
129
130
131
132 type ProcAttr struct {
133 Dir string
134 Env []string
135 Files []uintptr
136 Sys *SysProcAttr
137 }
138
139 var zeroProcAttr ProcAttr
140 var zeroSysProcAttr SysProcAttr
141
142 func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
143 var p [2]int
144 var n int
145 var err1 Errno
146 var wstatus WaitStatus
147
148 if attr == nil {
149 attr = &zeroProcAttr
150 }
151 sys := attr.Sys
152 if sys == nil {
153 sys = &zeroSysProcAttr
154 }
155
156
157 argv0p, err := BytePtrFromString(argv0)
158 if err != nil {
159 return 0, err
160 }
161 argvp, err := SlicePtrFromStrings(argv)
162 if err != nil {
163 return 0, err
164 }
165 envvp, err := SlicePtrFromStrings(attr.Env)
166 if err != nil {
167 return 0, err
168 }
169
170 if (runtime.GOOS == "freebsd" || runtime.GOOS == "dragonfly") && len(argv[0]) > len(argv0) {
171 argvp[0] = argv0p
172 }
173
174 var chroot *byte
175 if sys.Chroot != "" {
176 chroot, err = BytePtrFromString(sys.Chroot)
177 if err != nil {
178 return 0, err
179 }
180 }
181 var dir *byte
182 if attr.Dir != "" {
183 dir, err = BytePtrFromString(attr.Dir)
184 if err != nil {
185 return 0, err
186 }
187 }
188
189
190
191 if sys.Setctty && sys.Foreground {
192 return 0, errorspkg.New("both Setctty and Foreground set in SysProcAttr")
193 }
194 if sys.Setctty && sys.Ctty >= len(attr.Files) {
195 return 0, errorspkg.New("Setctty set but Ctty not valid in child")
196 }
197
198
199
200
201 ForkLock.Lock()
202
203
204 if err = forkExecPipe(p[:]); err != nil {
205 ForkLock.Unlock()
206 return 0, err
207 }
208
209
210 pid, err1 = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1])
211 if err1 != 0 {
212 Close(p[0])
213 Close(p[1])
214 ForkLock.Unlock()
215 return 0, Errno(err1)
216 }
217 ForkLock.Unlock()
218
219
220 Close(p[1])
221 for {
222 n, err = readlen(p[0], (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1)))
223 if err != EINTR {
224 break
225 }
226 }
227 Close(p[0])
228 if err != nil || n != 0 {
229 if n == int(unsafe.Sizeof(err1)) {
230 err = Errno(err1)
231 }
232 if err == nil {
233 err = EPIPE
234 }
235
236
237
238 _, err1 := Wait4(pid, &wstatus, 0, nil)
239 for err1 == EINTR {
240 _, err1 = Wait4(pid, &wstatus, 0, nil)
241 }
242 return 0, err
243 }
244
245
246 return pid, nil
247 }
248
249
250 func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
251 return forkExec(argv0, argv, attr)
252 }
253
254
255 func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
256 pid, err = forkExec(argv0, argv, attr)
257 return pid, 0, err
258 }
259
260
261 func runtime_BeforeExec()
262 func runtime_AfterExec()
263
264
265
266 var execveLibc func(path uintptr, argv uintptr, envp uintptr) Errno
267 var execveDarwin func(path *byte, argv **byte, envp **byte) error
268 var execveOpenBSD func(path *byte, argv **byte, envp **byte) error
269
270
271 func Exec(argv0 string, argv []string, envv []string) (err error) {
272 argv0p, err := BytePtrFromString(argv0)
273 if err != nil {
274 return err
275 }
276 argvp, err := SlicePtrFromStrings(argv)
277 if err != nil {
278 return err
279 }
280 envvp, err := SlicePtrFromStrings(envv)
281 if err != nil {
282 return err
283 }
284 runtime_BeforeExec()
285
286 var err1 error
287 if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" || runtime.GOOS == "aix" {
288
289 err1 = execveLibc(
290 uintptr(unsafe.Pointer(argv0p)),
291 uintptr(unsafe.Pointer(&argvp[0])),
292 uintptr(unsafe.Pointer(&envvp[0])))
293 } else if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
294
295 err1 = execveDarwin(argv0p, &argvp[0], &envvp[0])
296 } else if runtime.GOOS == "openbsd" {
297
298 err1 = execveOpenBSD(argv0p, &argvp[0], &envvp[0])
299 } else {
300 _, _, err1 = RawSyscall(SYS_EXECVE,
301 uintptr(unsafe.Pointer(argv0p)),
302 uintptr(unsafe.Pointer(&argvp[0])),
303 uintptr(unsafe.Pointer(&envvp[0])))
304 }
305 runtime_AfterExec()
306 return err1
307 }
308
View as plain text