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 p[0] = -1
157 p[1] = -1
158
159
160 argv0p, err := BytePtrFromString(argv0)
161 if err != nil {
162 return 0, err
163 }
164 argvp, err := SlicePtrFromStrings(argv)
165 if err != nil {
166 return 0, err
167 }
168 envvp, err := SlicePtrFromStrings(attr.Env)
169 if err != nil {
170 return 0, err
171 }
172
173 if (runtime.GOOS == "freebsd" || runtime.GOOS == "dragonfly") && len(argv[0]) > len(argv0) {
174 argvp[0] = argv0p
175 }
176
177 var chroot *byte
178 if sys.Chroot != "" {
179 chroot, err = BytePtrFromString(sys.Chroot)
180 if err != nil {
181 return 0, err
182 }
183 }
184 var dir *byte
185 if attr.Dir != "" {
186 dir, err = BytePtrFromString(attr.Dir)
187 if err != nil {
188 return 0, err
189 }
190 }
191
192
193
194 if sys.Setctty && sys.Foreground {
195 return 0, errorspkg.New("both Setctty and Foreground set in SysProcAttr")
196 }
197 if sys.Setctty && sys.Ctty >= len(attr.Files) {
198 return 0, errorspkg.New("Setctty set but Ctty not valid in child")
199 }
200
201
202
203
204 ForkLock.Lock()
205
206
207 if err = forkExecPipe(p[:]); err != nil {
208 goto error
209 }
210
211
212 pid, err1 = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1])
213 if err1 != 0 {
214 err = Errno(err1)
215 goto error
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 error:
249 if p[0] >= 0 {
250 Close(p[0])
251 Close(p[1])
252 }
253 ForkLock.Unlock()
254 return 0, err
255 }
256
257
258 func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
259 return forkExec(argv0, argv, attr)
260 }
261
262
263 func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
264 pid, err = forkExec(argv0, argv, attr)
265 return pid, 0, err
266 }
267
268
269 func runtime_BeforeExec()
270 func runtime_AfterExec()
271
272
273
274 var execveLibc func(path uintptr, argv uintptr, envp uintptr) Errno
275 var execveDarwin func(path *byte, argv **byte, envp **byte) error
276 var execveOpenBSD func(path *byte, argv **byte, envp **byte) error
277
278
279 func Exec(argv0 string, argv []string, envv []string) (err error) {
280 argv0p, err := BytePtrFromString(argv0)
281 if err != nil {
282 return err
283 }
284 argvp, err := SlicePtrFromStrings(argv)
285 if err != nil {
286 return err
287 }
288 envvp, err := SlicePtrFromStrings(envv)
289 if err != nil {
290 return err
291 }
292 runtime_BeforeExec()
293
294 var err1 error
295 if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" || runtime.GOOS == "aix" {
296
297 err1 = execveLibc(
298 uintptr(unsafe.Pointer(argv0p)),
299 uintptr(unsafe.Pointer(&argvp[0])),
300 uintptr(unsafe.Pointer(&envvp[0])))
301 } else if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
302
303 err1 = execveDarwin(argv0p, &argvp[0], &envvp[0])
304 } else if runtime.GOOS == "openbsd" && (runtime.GOARCH == "386" || runtime.GOARCH == "amd64" || runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
305
306 err1 = execveOpenBSD(argv0p, &argvp[0], &envvp[0])
307 } else {
308 _, _, err1 = RawSyscall(SYS_EXECVE,
309 uintptr(unsafe.Pointer(argv0p)),
310 uintptr(unsafe.Pointer(&argvp[0])),
311 uintptr(unsafe.Pointer(&envvp[0])))
312 }
313 runtime_AfterExec()
314 return err1
315 }
316
View as plain text