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