github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/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 n int 139 b []byte 140 ) 141 142 // Guard against side effects of shuffling fds below. 143 // Make sure that nextfd is beyond any currently open files so 144 // that we can't run the risk of overwriting any of them. 145 fd := make([]int, len(attr.Files)) 146 nextfd = len(attr.Files) 147 for i, ufd := range attr.Files { 148 if nextfd < int(ufd) { 149 nextfd = int(ufd) 150 } 151 fd[i] = int(ufd) 152 } 153 nextfd++ 154 155 if envv != nil { 156 clearenv = RFCENVG 157 } 158 159 // About to call fork. 160 // No more allocation or calls of non-assembly functions. 161 r1, _, _ = RawSyscall(SYS_RFORK, uintptr(RFPROC|RFFDG|RFREND|clearenv|rflag), 0, 0) 162 163 if r1 != 0 { 164 if int32(r1) == -1 { 165 return 0, NewError(errstr()) 166 } 167 // parent; return PID 168 return int(r1), nil 169 } 170 171 // Fork succeeded, now in child. 172 173 // Close fds we don't need. 174 r1, _, _ = RawSyscall(SYS_OPEN, uintptr(unsafe.Pointer(dupdev)), uintptr(O_RDONLY), 0) 175 dupdevfd = int(r1) 176 if dupdevfd == -1 { 177 goto childerror 178 } 179 dirloop: 180 for { 181 r1, _, _ = RawSyscall6(SYS_PREAD, uintptr(dupdevfd), uintptr(unsafe.Pointer(&statbuf[0])), uintptr(len(statbuf)), ^uintptr(0), ^uintptr(0), 0) 182 n = int(r1) 183 switch n { 184 case -1: 185 goto childerror 186 case 0: 187 break dirloop 188 } 189 for b = statbuf[:n]; len(b) > 0; { 190 var s []byte 191 s, b = gdirname(b) 192 if s == nil { 193 copy(errbuf[:], ErrBadStat.Error()) 194 goto childerror1 195 } 196 if s[len(s)-1] == 'l' { 197 // control file for descriptor <N> is named <N>ctl 198 continue 199 } 200 closeFdExcept(int(atoi(s)), pipe, dupdevfd, fd) 201 } 202 } 203 RawSyscall(SYS_CLOSE, uintptr(dupdevfd), 0, 0) 204 205 // Write new environment variables. 206 if envv != nil { 207 for i = 0; i < len(envv); i++ { 208 r1, _, _ = RawSyscall(SYS_CREATE, uintptr(unsafe.Pointer(envv[i].name)), uintptr(O_WRONLY), uintptr(0666)) 209 210 if int32(r1) == -1 { 211 goto childerror 212 } 213 214 envfd = int(r1) 215 216 r1, _, _ = RawSyscall6(SYS_PWRITE, uintptr(envfd), uintptr(unsafe.Pointer(envv[i].value)), uintptr(envv[i].nvalue), 217 ^uintptr(0), ^uintptr(0), 0) 218 219 if int32(r1) == -1 || int(r1) != envv[i].nvalue { 220 goto childerror 221 } 222 223 r1, _, _ = RawSyscall(SYS_CLOSE, uintptr(envfd), 0, 0) 224 225 if int32(r1) == -1 { 226 goto childerror 227 } 228 } 229 } 230 231 // Chdir 232 if dir != nil { 233 r1, _, _ = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0) 234 if int32(r1) == -1 { 235 goto childerror 236 } 237 } 238 239 // Pass 1: look for fd[i] < i and move those up above len(fd) 240 // so that pass 2 won't stomp on an fd it needs later. 241 if pipe < nextfd { 242 r1, _, _ = RawSyscall(SYS_DUP, uintptr(pipe), uintptr(nextfd), 0) 243 if int32(r1) == -1 { 244 goto childerror 245 } 246 pipe = nextfd 247 nextfd++ 248 } 249 for i = 0; i < len(fd); i++ { 250 if fd[i] >= 0 && fd[i] < i { 251 if nextfd == pipe { // don't stomp on pipe 252 nextfd++ 253 } 254 r1, _, _ = RawSyscall(SYS_DUP, uintptr(fd[i]), uintptr(nextfd), 0) 255 if int32(r1) == -1 { 256 goto childerror 257 } 258 259 fd[i] = nextfd 260 nextfd++ 261 } 262 } 263 264 // Pass 2: dup fd[i] down onto i. 265 for i = 0; i < len(fd); i++ { 266 if fd[i] == -1 { 267 RawSyscall(SYS_CLOSE, uintptr(i), 0, 0) 268 continue 269 } 270 if fd[i] == i { 271 continue 272 } 273 r1, _, _ = RawSyscall(SYS_DUP, uintptr(fd[i]), uintptr(i), 0) 274 if int32(r1) == -1 { 275 goto childerror 276 } 277 } 278 279 // Pass 3: close fd[i] if it was moved in the previous pass. 280 for i = 0; i < len(fd); i++ { 281 if fd[i] >= len(fd) { 282 RawSyscall(SYS_CLOSE, uintptr(fd[i]), 0, 0) 283 } 284 } 285 286 // Time to exec. 287 r1, _, _ = RawSyscall(SYS_EXEC, 288 uintptr(unsafe.Pointer(argv0)), 289 uintptr(unsafe.Pointer(&argv[0])), 0) 290 291 childerror: 292 // send error string on pipe 293 RawSyscall(SYS_ERRSTR, uintptr(unsafe.Pointer(&errbuf[0])), uintptr(len(errbuf)), 0) 294 childerror1: 295 errbuf[len(errbuf)-1] = 0 296 i = 0 297 for i < len(errbuf) && errbuf[i] != 0 { 298 i++ 299 } 300 301 RawSyscall6(SYS_PWRITE, uintptr(pipe), uintptr(unsafe.Pointer(&errbuf[0])), uintptr(i), 302 ^uintptr(0), ^uintptr(0), 0) 303 304 for { 305 RawSyscall(SYS_EXITS, 0, 0, 0) 306 } 307 } 308 309 // close the numbered file descriptor, unless it is fd1, fd2, or a member of fds. 310 // 311 //go:nosplit 312 func closeFdExcept(n int, fd1 int, fd2 int, fds []int) { 313 if n == fd1 || n == fd2 { 314 return 315 } 316 for _, fd := range fds { 317 if n == fd { 318 return 319 } 320 } 321 RawSyscall(SYS_CLOSE, uintptr(n), 0, 0) 322 } 323 324 func cexecPipe(p []int) error { 325 e := Pipe(p) 326 if e != nil { 327 return e 328 } 329 330 fd, e := Open("#d/"+itoa.Itoa(p[1]), O_RDWR|O_CLOEXEC) 331 if e != nil { 332 Close(p[0]) 333 Close(p[1]) 334 return e 335 } 336 337 Close(p[1]) 338 p[1] = fd 339 return nil 340 } 341 342 type envItem struct { 343 name *byte 344 value *byte 345 nvalue int 346 } 347 348 type ProcAttr struct { 349 Dir string // Current working directory. 350 Env []string // Environment. 351 Files []uintptr // File descriptors. 352 Sys *SysProcAttr 353 } 354 355 type SysProcAttr struct { 356 Rfork int // additional flags to pass to rfork 357 } 358 359 var zeroProcAttr ProcAttr 360 var zeroSysProcAttr SysProcAttr 361 362 func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { 363 var ( 364 p [2]int 365 n int 366 errbuf [ERRMAX]byte 367 wmsg Waitmsg 368 ) 369 370 if attr == nil { 371 attr = &zeroProcAttr 372 } 373 sys := attr.Sys 374 if sys == nil { 375 sys = &zeroSysProcAttr 376 } 377 378 p[0] = -1 379 p[1] = -1 380 381 // Convert args to C form. 382 argv0p, err := BytePtrFromString(argv0) 383 if err != nil { 384 return 0, err 385 } 386 argvp, err := SlicePtrFromStrings(argv) 387 if err != nil { 388 return 0, err 389 } 390 391 destDir := attr.Dir 392 if destDir == "" { 393 wdmu.Lock() 394 destDir = wdStr 395 wdmu.Unlock() 396 } 397 var dir *byte 398 if destDir != "" { 399 dir, err = BytePtrFromString(destDir) 400 if err != nil { 401 return 0, err 402 } 403 } 404 var envvParsed []envItem 405 if attr.Env != nil { 406 envvParsed = make([]envItem, 0, len(attr.Env)) 407 for _, v := range attr.Env { 408 i := 0 409 for i < len(v) && v[i] != '=' { 410 i++ 411 } 412 413 envname, err := BytePtrFromString("/env/" + v[:i]) 414 if err != nil { 415 return 0, err 416 } 417 envvalue := make([]byte, len(v)-i) 418 copy(envvalue, v[i+1:]) 419 envvParsed = append(envvParsed, envItem{envname, &envvalue[0], len(v) - i}) 420 } 421 } 422 423 // Allocate child status pipe close on exec. 424 e := cexecPipe(p[:]) 425 426 if e != nil { 427 return 0, e 428 } 429 430 // Kick off child. 431 pid, err = forkAndExecInChild(argv0p, argvp, envvParsed, dir, attr, p[1], sys.Rfork) 432 433 if err != nil { 434 if p[0] >= 0 { 435 Close(p[0]) 436 Close(p[1]) 437 } 438 return 0, err 439 } 440 441 // Read child error status from pipe. 442 Close(p[1]) 443 n, err = Read(p[0], errbuf[:]) 444 Close(p[0]) 445 446 if err != nil || n != 0 { 447 if n > 0 { 448 err = NewError(string(errbuf[:n])) 449 } else if err == nil { 450 err = NewError("failed to read exec status") 451 } 452 453 // Child failed; wait for it to exit, to make sure 454 // the zombies don't accumulate. 455 for wmsg.Pid != pid { 456 Await(&wmsg) 457 } 458 return 0, err 459 } 460 461 // Read got EOF, so pipe closed on exec, so exec succeeded. 462 return pid, nil 463 } 464 465 type waitErr struct { 466 Waitmsg 467 err error 468 } 469 470 var procs struct { 471 sync.Mutex 472 waits map[int]chan *waitErr 473 } 474 475 // startProcess starts a new goroutine, tied to the OS 476 // thread, which runs the process and subsequently waits 477 // for it to finish, communicating the process stats back 478 // to any goroutines that may have been waiting on it. 479 // 480 // Such a dedicated goroutine is needed because on 481 // Plan 9, only the parent thread can wait for a child, 482 // whereas goroutines tend to jump OS threads (e.g., 483 // between starting a process and running Wait(), the 484 // goroutine may have been rescheduled). 485 func startProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { 486 type forkRet struct { 487 pid int 488 err error 489 } 490 491 forkc := make(chan forkRet, 1) 492 go func() { 493 runtime.LockOSThread() 494 var ret forkRet 495 496 ret.pid, ret.err = forkExec(argv0, argv, attr) 497 // If fork fails there is nothing to wait for. 498 if ret.err != nil || ret.pid == 0 { 499 forkc <- ret 500 return 501 } 502 503 waitc := make(chan *waitErr, 1) 504 505 // Mark that the process is running. 506 procs.Lock() 507 if procs.waits == nil { 508 procs.waits = make(map[int]chan *waitErr) 509 } 510 procs.waits[ret.pid] = waitc 511 procs.Unlock() 512 513 forkc <- ret 514 515 var w waitErr 516 for w.err == nil && w.Pid != ret.pid { 517 w.err = Await(&w.Waitmsg) 518 } 519 waitc <- &w 520 close(waitc) 521 }() 522 ret := <-forkc 523 return ret.pid, ret.err 524 } 525 526 // Combination of fork and exec, careful to be thread safe. 527 func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { 528 return startProcess(argv0, argv, attr) 529 } 530 531 // StartProcess wraps [ForkExec] for package os. 532 func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) { 533 pid, err = startProcess(argv0, argv, attr) 534 return pid, 0, err 535 } 536 537 // Ordinary exec. 538 func Exec(argv0 string, argv []string, envv []string) (err error) { 539 if envv != nil { 540 r1, _, _ := RawSyscall(SYS_RFORK, RFCENVG, 0, 0) 541 if int32(r1) == -1 { 542 return NewError(errstr()) 543 } 544 545 for _, v := range envv { 546 i := 0 547 for i < len(v) && v[i] != '=' { 548 i++ 549 } 550 551 fd, e := Create("/env/"+v[:i], O_WRONLY, 0666) 552 if e != nil { 553 return e 554 } 555 556 _, e = Write(fd, []byte(v[i+1:])) 557 if e != nil { 558 Close(fd) 559 return e 560 } 561 Close(fd) 562 } 563 } 564 565 argv0p, err := BytePtrFromString(argv0) 566 if err != nil { 567 return err 568 } 569 argvp, err := SlicePtrFromStrings(argv) 570 if err != nil { 571 return err 572 } 573 _, _, e1 := Syscall(SYS_EXEC, 574 uintptr(unsafe.Pointer(argv0p)), 575 uintptr(unsafe.Pointer(&argvp[0])), 576 0) 577 578 return e1 579 } 580 581 // WaitProcess waits until the pid of a 582 // running process is found in the queue of 583 // wait messages. It is used in conjunction 584 // with [ForkExec]/[StartProcess] to wait for a 585 // running process to exit. 586 func WaitProcess(pid int, w *Waitmsg) (err error) { 587 procs.Lock() 588 ch := procs.waits[pid] 589 procs.Unlock() 590 591 var wmsg *waitErr 592 if ch != nil { 593 wmsg = <-ch 594 procs.Lock() 595 if procs.waits[pid] == ch { 596 delete(procs.waits, pid) 597 } 598 procs.Unlock() 599 } 600 if wmsg == nil { 601 // ch was missing or ch is closed 602 return NewError("process not found") 603 } 604 if wmsg.err != nil { 605 return wmsg.err 606 } 607 if w != nil { 608 *w = wmsg.Waitmsg 609 } 610 return nil 611 }