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