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