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