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