github.com/mangodowner/go-gm@v0.0.0-20180818020936-8baa2bd4408c/src/syscall/exec_plan9.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Fork, exec, wait, etc. 6 7 package syscall 8 9 import ( 10 "runtime" 11 "sync" 12 "unsafe" 13 ) 14 15 // ForkLock is not used on plan9. 16 var ForkLock sync.RWMutex 17 18 // gstringb reads a non-empty string from b, prefixed with a 16-bit length in little-endian order. 19 // It returns the string as a byte slice, or nil if b is too short to contain the length or 20 // the full string. 21 //go:nosplit 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 // Offset of the name field in a 9P directory entry - see UnmarshalDir() in dir_plan9.go 34 const nameOffset = 39 35 36 // gdirname returns the first filename from a buffer of directory entries, 37 // and a slice containing the remaining directory entries. 38 // If the buffer doesn't start with a valid directory entry, the returned name is nil. 39 //go:nosplit 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 // StringSlicePtr converts a slice of strings to a slice of pointers 54 // to NUL-terminated byte arrays. If any string contains a NUL byte 55 // this function panics instead of returning an error. 56 // 57 // Deprecated: Use SlicePtrFromStrings instead. 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 // SlicePtrFromStrings converts a slice of strings to a slice of 68 // pointers to NUL-terminated byte arrays. If any string contains 69 // a NUL byte, it returns (nil, EINVAL). 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 // readdirnames returns the names of files inside the directory represented by dirfd. 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 // name of the directory containing names and control files for all open file descriptors 109 var dupdev, _ = BytePtrFromString("#d") 110 111 // forkAndExecInChild forks the process, calling dup onto 0..len(fd) 112 // and finally invoking exec(argv0, argvv, envv) in the child. 113 // If a dup or exec fails, it writes the error string to pipe. 114 // (The pipe write end is close-on-exec so if exec succeeds, it will be closed.) 115 // 116 // In the child, this function must not acquire any locks, because 117 // they might have been locked at the time of the fork. This means 118 // no rescheduling, no malloc calls, and no new stack segments. 119 // The calls to RawSyscall are okay because they are assembly 120 // functions that do not grow the stack. 121 //go:norace 122 func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, attr *ProcAttr, pipe int, rflag int) (pid int, err error) { 123 // Declare all variables at top in case any 124 // declarations require heap allocation (e.g., errbuf). 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 // Guard against side effects of shuffling fds below. 137 // Make sure that nextfd is beyond any currently open files so 138 // that we can't run the risk of overwriting any of them. 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 // About to call fork. 154 // No more allocation or calls of non-assembly functions. 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 // parent; return PID 162 return int(r1), nil 163 } 164 165 // Fork succeeded, now in child. 166 167 // Close fds we don't need. 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 // control file for descriptor <N> is named <N>ctl 192 continue 193 } 194 closeFdExcept(int(atoi(s)), pipe, dupdevfd, fd) 195 } 196 } 197 RawSyscall(SYS_CLOSE, uintptr(dupdevfd), 0, 0) 198 199 // Write new environment variables. 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 // Chdir 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 // Pass 1: look for fd[i] < i and move those up above len(fd) 234 // so that pass 2 won't stomp on an fd it needs later. 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 { // don't stomp on 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 // Pass 2: dup fd[i] down onto i. 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 // Pass 3: close fd[i] if it was moved in the previous pass. 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 // Time to exec. 281 r1, _, _ = RawSyscall(SYS_EXEC, 282 uintptr(unsafe.Pointer(argv0)), 283 uintptr(unsafe.Pointer(&argv[0])), 0) 284 285 childerror: 286 // send error string on pipe 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 // close the numbered file descriptor, unless it is fd1, fd2, or a member of fds. 304 //go:nosplit 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 // Current working directory. 342 Env []string // Environment. 343 Files []uintptr // File descriptors. 344 Sys *SysProcAttr 345 } 346 347 type SysProcAttr struct { 348 Rfork int // additional flags to pass to rfork 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 // Convert args to C form. 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 // Allocate child status pipe close on exec. 416 e := cexecPipe(p[:]) 417 418 if e != nil { 419 return 0, e 420 } 421 422 // Kick off child. 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 // Read child error status from pipe. 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 // Child failed; wait for it to exit, to make sure 446 // the zombies don't accumulate. 447 for wmsg.Pid != pid { 448 Await(&wmsg) 449 } 450 return 0, err 451 } 452 453 // Read got EOF, so pipe closed on exec, so exec succeeded. 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 // startProcess starts a new goroutine, tied to the OS 468 // thread, which runs the process and subsequently waits 469 // for it to finish, communicating the process stats back 470 // to any goroutines that may have been waiting on it. 471 // 472 // Such a dedicated goroutine is needed because on 473 // Plan 9, only the parent thread can wait for a child, 474 // whereas goroutines tend to jump OS threads (e.g., 475 // between starting a process and running Wait(), the 476 // goroutine may have been rescheduled). 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 // If fork fails there is nothing to wait for. 490 if ret.err != nil || ret.pid == 0 { 491 forkc <- ret 492 return 493 } 494 495 waitc := make(chan *waitErr, 1) 496 497 // Mark that the process is running. 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 // Combination of fork and exec, careful to be thread safe. 519 func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { 520 return startProcess(argv0, argv, attr) 521 } 522 523 // StartProcess wraps ForkExec for package os. 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 // Ordinary exec. 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 // WaitProcess waits until the pid of a 574 // running process is found in the queue of 575 // wait messages. It is used in conjunction 576 // with ForkExec/StartProcess to wait for a 577 // running process to exit. 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 // ch was missing or ch is closed 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 }