github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/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 // 23 //go:nosplit 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 // Offset of the name field in a 9P directory entry - see UnmarshalDir() in dir_plan9.go 36 const nameOffset = 39 37 38 // gdirname returns the first filename from a buffer of directory entries, 39 // and a slice containing the remaining directory entries. 40 // If the buffer doesn't start with a valid directory entry, the returned name is nil. 41 // 42 //go:nosplit 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 // StringSlicePtr converts a slice of strings to a slice of pointers 57 // to NUL-terminated byte arrays. If any string contains a NUL byte 58 // this function panics instead of returning an error. 59 // 60 // Deprecated: Use SlicePtrFromStrings instead. 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 // SlicePtrFromStrings converts a slice of strings to a slice of 71 // pointers to NUL-terminated byte arrays. If any string contains 72 // a NUL byte, it returns (nil, EINVAL). 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 // readdirnames returns the names of files inside the directory represented by dirfd. 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 // name of the directory containing names and control files for all open file descriptors 112 var dupdev, _ = BytePtrFromString("#d") 113 114 // forkAndExecInChild forks the process, calling dup onto 0..len(fd) 115 // and finally invoking exec(argv0, argvv, envv) in the child. 116 // If a dup or exec fails, it writes the error string to pipe. 117 // (The pipe write end is close-on-exec so if exec succeeds, it will be closed.) 118 // 119 // In the child, this function must not acquire any locks, because 120 // they might have been locked at the time of the fork. This means 121 // no rescheduling, no malloc calls, and no new stack segments. 122 // The calls to RawSyscall are okay because they are assembly 123 // functions that do not grow the stack. 124 // 125 //go:norace 126 func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, attr *ProcAttr, pipe int, rflag int) (pid int, err error) { 127 // Declare all variables at top in case any 128 // declarations require heap allocation (e.g., errbuf). 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 // Guard against side effects of shuffling fds below. 141 // Make sure that nextfd is beyond any currently open files so 142 // that we can't run the risk of overwriting any of them. 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 // About to call fork. 158 // No more allocation or calls of non-assembly functions. 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 // parent; return PID 166 return int(r1), nil 167 } 168 169 // Fork succeeded, now in child. 170 171 // Close fds we don't need. 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 // control file for descriptor <N> is named <N>ctl 196 continue 197 } 198 closeFdExcept(int(atoi(s)), pipe, dupdevfd, fd) 199 } 200 } 201 RawSyscall(SYS_CLOSE, uintptr(dupdevfd), 0, 0) 202 203 // Write new environment variables. 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 // Chdir 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 // Pass 1: look for fd[i] < i and move those up above len(fd) 238 // so that pass 2 won't stomp on an fd it needs later. 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 { // don't stomp on 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 // Pass 2: dup fd[i] down onto i. 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 // Pass 3: close fd[i] if it was moved in the previous pass. 278 for i = 0; i < len(fd); i++ { 279 if fd[i] >= 0 && fd[i] != int(i) { 280 RawSyscall(SYS_CLOSE, uintptr(fd[i]), 0, 0) 281 } 282 } 283 284 // Time to exec. 285 r1, _, _ = RawSyscall(SYS_EXEC, 286 uintptr(unsafe.Pointer(argv0)), 287 uintptr(unsafe.Pointer(&argv[0])), 0) 288 289 childerror: 290 // send error string on pipe 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 // close the numbered file descriptor, unless it is fd1, fd2, or a member of fds. 308 // 309 //go:nosplit 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 // Current working directory. 348 Env []string // Environment. 349 Files []uintptr // File descriptors. 350 Sys *SysProcAttr 351 } 352 353 type SysProcAttr struct { 354 Rfork int // additional flags to pass to rfork 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 // Convert args to C form. 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 // Allocate child status pipe close on exec. 422 e := cexecPipe(p[:]) 423 424 if e != nil { 425 return 0, e 426 } 427 428 // Kick off child. 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 // Read child error status from pipe. 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 // Child failed; wait for it to exit, to make sure 452 // the zombies don't accumulate. 453 for wmsg.Pid != pid { 454 Await(&wmsg) 455 } 456 return 0, err 457 } 458 459 // Read got EOF, so pipe closed on exec, so exec succeeded. 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 // startProcess starts a new goroutine, tied to the OS 474 // thread, which runs the process and subsequently waits 475 // for it to finish, communicating the process stats back 476 // to any goroutines that may have been waiting on it. 477 // 478 // Such a dedicated goroutine is needed because on 479 // Plan 9, only the parent thread can wait for a child, 480 // whereas goroutines tend to jump OS threads (e.g., 481 // between starting a process and running Wait(), the 482 // goroutine may have been rescheduled). 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 // If fork fails there is nothing to wait for. 496 if ret.err != nil || ret.pid == 0 { 497 forkc <- ret 498 return 499 } 500 501 waitc := make(chan *waitErr, 1) 502 503 // Mark that the process is running. 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 // Combination of fork and exec, careful to be thread safe. 525 func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { 526 return startProcess(argv0, argv, attr) 527 } 528 529 // StartProcess wraps ForkExec for package os. 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 // Ordinary exec. 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 // WaitProcess waits until the pid of a 580 // running process is found in the queue of 581 // wait messages. It is used in conjunction 582 // with ForkExec/StartProcess to wait for a 583 // running process to exit. 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 // ch was missing or ch is closed 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 }