Source file src/syscall/exec_plan9.go
1
2
3
4
5
6
7 package syscall
8
9 import (
10 "runtime"
11 "sync"
12 "unsafe"
13 )
14
15
16 var ForkLock sync.RWMutex
17
18
19
20
21
22 func gstringb(b []byte) []byte {
23 if len(b) < 2 {
24 return nil
25 }
26 n, b := gbit16(b)
27 if int(n) > len(b) {
28 return nil
29 }
30 return b[:n]
31 }
32
33
34 const nameOffset = 39
35
36
37
38
39
40 func gdirname(buf []byte) (name []byte, rest []byte) {
41 if len(buf) < 2 {
42 return
43 }
44 size, buf := gbit16(buf)
45 if size < STATFIXLEN || int(size) > len(buf) {
46 return
47 }
48 name = gstringb(buf[nameOffset:size])
49 rest = buf[size:]
50 return
51 }
52
53
54
55
56
57
58 func StringSlicePtr(ss []string) []*byte {
59 bb := make([]*byte, len(ss)+1)
60 for i := 0; i < len(ss); i++ {
61 bb[i] = StringBytePtr(ss[i])
62 }
63 bb[len(ss)] = nil
64 return bb
65 }
66
67
68
69
70 func SlicePtrFromStrings(ss []string) ([]*byte, error) {
71 var err error
72 bb := make([]*byte, len(ss)+1)
73 for i := 0; i < len(ss); i++ {
74 bb[i], err = BytePtrFromString(ss[i])
75 if err != nil {
76 return nil, err
77 }
78 }
79 bb[len(ss)] = nil
80 return bb, nil
81 }
82
83
84 func readdirnames(dirfd int) (names []string, err error) {
85 names = make([]string, 0, 100)
86 var buf [STATMAX]byte
87
88 for {
89 n, e := Read(dirfd, buf[:])
90 if e != nil {
91 return nil, e
92 }
93 if n == 0 {
94 break
95 }
96 for b := buf[:n]; len(b) > 0; {
97 var s []byte
98 s, b = gdirname(b)
99 if s == nil {
100 return nil, ErrBadStat
101 }
102 names = append(names, string(s))
103 }
104 }
105 return
106 }
107
108
109 var dupdev, _ = BytePtrFromString("#d")
110
111
112
113
114
115
116
117
118
119
120
121
122 func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, attr *ProcAttr, pipe int, rflag int) (pid int, err error) {
123
124
125 var (
126 r1 uintptr
127 nextfd int
128 i int
129 clearenv int
130 envfd int
131 errbuf [ERRMAX]byte
132 statbuf [STATMAX]byte
133 dupdevfd int
134 )
135
136
137
138
139 fd := make([]int, len(attr.Files))
140 nextfd = len(attr.Files)
141 for i, ufd := range attr.Files {
142 if nextfd < int(ufd) {
143 nextfd = int(ufd)
144 }
145 fd[i] = int(ufd)
146 }
147 nextfd++
148
149 if envv != nil {
150 clearenv = RFCENVG
151 }
152
153
154
155 r1, _, _ = RawSyscall(SYS_RFORK, uintptr(RFPROC|RFFDG|RFREND|clearenv|rflag), 0, 0)
156
157 if r1 != 0 {
158 if int32(r1) == -1 {
159 return 0, NewError(errstr())
160 }
161
162 return int(r1), nil
163 }
164
165
166
167
168 r1, _, _ = RawSyscall(SYS_OPEN, uintptr(unsafe.Pointer(dupdev)), uintptr(O_RDONLY), 0)
169 dupdevfd = int(r1)
170 if dupdevfd == -1 {
171 goto childerror
172 }
173 dirloop:
174 for {
175 r1, _, _ = RawSyscall6(SYS_PREAD, uintptr(dupdevfd), uintptr(unsafe.Pointer(&statbuf[0])), uintptr(len(statbuf)), ^uintptr(0), ^uintptr(0), 0)
176 n := int(r1)
177 switch n {
178 case -1:
179 goto childerror
180 case 0:
181 break dirloop
182 }
183 for b := statbuf[:n]; len(b) > 0; {
184 var s []byte
185 s, b = gdirname(b)
186 if s == nil {
187 copy(errbuf[:], ErrBadStat.Error())
188 goto childerror1
189 }
190 if s[len(s)-1] == 'l' {
191
192 continue
193 }
194 closeFdExcept(int(atoi(s)), pipe, dupdevfd, fd)
195 }
196 }
197 RawSyscall(SYS_CLOSE, uintptr(dupdevfd), 0, 0)
198
199
200 if envv != nil {
201 for i = 0; i < len(envv); i++ {
202 r1, _, _ = RawSyscall(SYS_CREATE, uintptr(unsafe.Pointer(envv[i].name)), uintptr(O_WRONLY), uintptr(0666))
203
204 if int32(r1) == -1 {
205 goto childerror
206 }
207
208 envfd = int(r1)
209
210 r1, _, _ = RawSyscall6(SYS_PWRITE, uintptr(envfd), uintptr(unsafe.Pointer(envv[i].value)), uintptr(envv[i].nvalue),
211 ^uintptr(0), ^uintptr(0), 0)
212
213 if int32(r1) == -1 || int(r1) != envv[i].nvalue {
214 goto childerror
215 }
216
217 r1, _, _ = RawSyscall(SYS_CLOSE, uintptr(envfd), 0, 0)
218
219 if int32(r1) == -1 {
220 goto childerror
221 }
222 }
223 }
224
225
226 if dir != nil {
227 r1, _, _ = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0)
228 if int32(r1) == -1 {
229 goto childerror
230 }
231 }
232
233
234
235 if pipe < nextfd {
236 r1, _, _ = RawSyscall(SYS_DUP, uintptr(pipe), uintptr(nextfd), 0)
237 if int32(r1) == -1 {
238 goto childerror
239 }
240 pipe = nextfd
241 nextfd++
242 }
243 for i = 0; i < len(fd); i++ {
244 if fd[i] >= 0 && fd[i] < int(i) {
245 if nextfd == pipe {
246 nextfd++
247 }
248 r1, _, _ = RawSyscall(SYS_DUP, uintptr(fd[i]), uintptr(nextfd), 0)
249 if int32(r1) == -1 {
250 goto childerror
251 }
252
253 fd[i] = nextfd
254 nextfd++
255 }
256 }
257
258
259 for i = 0; i < len(fd); i++ {
260 if fd[i] == -1 {
261 RawSyscall(SYS_CLOSE, uintptr(i), 0, 0)
262 continue
263 }
264 if fd[i] == int(i) {
265 continue
266 }
267 r1, _, _ = RawSyscall(SYS_DUP, uintptr(fd[i]), uintptr(i), 0)
268 if int32(r1) == -1 {
269 goto childerror
270 }
271 }
272
273
274 for i = 0; i < len(fd); i++ {
275 if fd[i] >= 0 && fd[i] != int(i) {
276 RawSyscall(SYS_CLOSE, uintptr(fd[i]), 0, 0)
277 }
278 }
279
280
281 r1, _, _ = RawSyscall(SYS_EXEC,
282 uintptr(unsafe.Pointer(argv0)),
283 uintptr(unsafe.Pointer(&argv[0])), 0)
284
285 childerror:
286
287 RawSyscall(SYS_ERRSTR, uintptr(unsafe.Pointer(&errbuf[0])), uintptr(len(errbuf)), 0)
288 childerror1:
289 errbuf[len(errbuf)-1] = 0
290 i = 0
291 for i < len(errbuf) && errbuf[i] != 0 {
292 i++
293 }
294
295 RawSyscall6(SYS_PWRITE, uintptr(pipe), uintptr(unsafe.Pointer(&errbuf[0])), uintptr(i),
296 ^uintptr(0), ^uintptr(0), 0)
297
298 for {
299 RawSyscall(SYS_EXITS, 0, 0, 0)
300 }
301 }
302
303
304
305 func closeFdExcept(n int, fd1 int, fd2 int, fds []int) {
306 if n == fd1 || n == fd2 {
307 return
308 }
309 for _, fd := range fds {
310 if n == fd {
311 return
312 }
313 }
314 RawSyscall(SYS_CLOSE, uintptr(n), 0, 0)
315 }
316
317 func cexecPipe(p []int) error {
318 e := Pipe(p)
319 if e != nil {
320 return e
321 }
322
323 fd, e := Open("#d/"+itoa(p[1]), O_CLOEXEC)
324 if e != nil {
325 Close(p[0])
326 Close(p[1])
327 return e
328 }
329
330 Close(fd)
331 return nil
332 }
333
334 type envItem struct {
335 name *byte
336 value *byte
337 nvalue int
338 }
339
340 type ProcAttr struct {
341 Dir string
342 Env []string
343 Files []uintptr
344 Sys *SysProcAttr
345 }
346
347 type SysProcAttr struct {
348 Rfork int
349 }
350
351 var zeroProcAttr ProcAttr
352 var zeroSysProcAttr SysProcAttr
353
354 func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
355 var (
356 p [2]int
357 n int
358 errbuf [ERRMAX]byte
359 wmsg Waitmsg
360 )
361
362 if attr == nil {
363 attr = &zeroProcAttr
364 }
365 sys := attr.Sys
366 if sys == nil {
367 sys = &zeroSysProcAttr
368 }
369
370 p[0] = -1
371 p[1] = -1
372
373
374 argv0p, err := BytePtrFromString(argv0)
375 if err != nil {
376 return 0, err
377 }
378 argvp, err := SlicePtrFromStrings(argv)
379 if err != nil {
380 return 0, err
381 }
382
383 destDir := attr.Dir
384 if destDir == "" {
385 wdmu.Lock()
386 destDir = wdStr
387 wdmu.Unlock()
388 }
389 var dir *byte
390 if destDir != "" {
391 dir, err = BytePtrFromString(destDir)
392 if err != nil {
393 return 0, err
394 }
395 }
396 var envvParsed []envItem
397 if attr.Env != nil {
398 envvParsed = make([]envItem, 0, len(attr.Env))
399 for _, v := range attr.Env {
400 i := 0
401 for i < len(v) && v[i] != '=' {
402 i++
403 }
404
405 envname, err := BytePtrFromString("/env/" + v[:i])
406 if err != nil {
407 return 0, err
408 }
409 envvalue := make([]byte, len(v)-i)
410 copy(envvalue, v[i+1:])
411 envvParsed = append(envvParsed, envItem{envname, &envvalue[0], len(v) - i})
412 }
413 }
414
415
416 e := cexecPipe(p[:])
417
418 if e != nil {
419 return 0, e
420 }
421
422
423 pid, err = forkAndExecInChild(argv0p, argvp, envvParsed, dir, attr, p[1], sys.Rfork)
424
425 if err != nil {
426 if p[0] >= 0 {
427 Close(p[0])
428 Close(p[1])
429 }
430 return 0, err
431 }
432
433
434 Close(p[1])
435 n, err = Read(p[0], errbuf[:])
436 Close(p[0])
437
438 if err != nil || n != 0 {
439 if n > 0 {
440 err = NewError(string(errbuf[:n]))
441 } else if err == nil {
442 err = NewError("failed to read exec status")
443 }
444
445
446
447 for wmsg.Pid != pid {
448 Await(&wmsg)
449 }
450 return 0, err
451 }
452
453
454 return pid, nil
455 }
456
457 type waitErr struct {
458 Waitmsg
459 err error
460 }
461
462 var procs struct {
463 sync.Mutex
464 waits map[int]chan *waitErr
465 }
466
467
468
469
470
471
472
473
474
475
476
477 func startProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
478 type forkRet struct {
479 pid int
480 err error
481 }
482
483 forkc := make(chan forkRet, 1)
484 go func() {
485 runtime.LockOSThread()
486 var ret forkRet
487
488 ret.pid, ret.err = forkExec(argv0, argv, attr)
489
490 if ret.err != nil || ret.pid == 0 {
491 forkc <- ret
492 return
493 }
494
495 waitc := make(chan *waitErr, 1)
496
497
498 procs.Lock()
499 if procs.waits == nil {
500 procs.waits = make(map[int]chan *waitErr)
501 }
502 procs.waits[ret.pid] = waitc
503 procs.Unlock()
504
505 forkc <- ret
506
507 var w waitErr
508 for w.err == nil && w.Pid != ret.pid {
509 w.err = Await(&w.Waitmsg)
510 }
511 waitc <- &w
512 close(waitc)
513 }()
514 ret := <-forkc
515 return ret.pid, ret.err
516 }
517
518
519 func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
520 return startProcess(argv0, argv, attr)
521 }
522
523
524 func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
525 pid, err = startProcess(argv0, argv, attr)
526 return pid, 0, err
527 }
528
529
530 func Exec(argv0 string, argv []string, envv []string) (err error) {
531 if envv != nil {
532 r1, _, _ := RawSyscall(SYS_RFORK, RFCENVG, 0, 0)
533 if int32(r1) == -1 {
534 return NewError(errstr())
535 }
536
537 for _, v := range envv {
538 i := 0
539 for i < len(v) && v[i] != '=' {
540 i++
541 }
542
543 fd, e := Create("/env/"+v[:i], O_WRONLY, 0666)
544 if e != nil {
545 return e
546 }
547
548 _, e = Write(fd, []byte(v[i+1:]))
549 if e != nil {
550 Close(fd)
551 return e
552 }
553 Close(fd)
554 }
555 }
556
557 argv0p, err := BytePtrFromString(argv0)
558 if err != nil {
559 return err
560 }
561 argvp, err := SlicePtrFromStrings(argv)
562 if err != nil {
563 return err
564 }
565 _, _, e1 := Syscall(SYS_EXEC,
566 uintptr(unsafe.Pointer(argv0p)),
567 uintptr(unsafe.Pointer(&argvp[0])),
568 0)
569
570 return e1
571 }
572
573
574
575
576
577
578 func WaitProcess(pid int, w *Waitmsg) (err error) {
579 procs.Lock()
580 ch := procs.waits[pid]
581 procs.Unlock()
582
583 var wmsg *waitErr
584 if ch != nil {
585 wmsg = <-ch
586 procs.Lock()
587 if procs.waits[pid] == ch {
588 delete(procs.waits, pid)
589 }
590 procs.Unlock()
591 }
592 if wmsg == nil {
593
594 return NewError("process not found")
595 }
596 if wmsg.err != nil {
597 return wmsg.err
598 }
599 if w != nil {
600 *w = wmsg.Waitmsg
601 }
602 return nil
603 }
604
View as plain text