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