github.com/liujq9674git/golang-src-1.7@v0.0.0-20230517174348-17f6ec47f3f8/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 // Calling panic is not actually safe, 303 // but the for loop above won't break 304 // and this shuts up the compiler. 305 panic("unreached") 306 } 307 308 // close the numbered file descriptor, unless it is fd1, fd2, or a member of fds. 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(p[1]), O_CLOEXEC) 329 if e != nil { 330 Close(p[0]) 331 Close(p[1]) 332 return e 333 } 334 335 Close(fd) 336 return nil 337 } 338 339 type envItem struct { 340 name *byte 341 value *byte 342 nvalue int 343 } 344 345 type ProcAttr struct { 346 Dir string // Current working directory. 347 Env []string // Environment. 348 Files []uintptr // File descriptors. 349 Sys *SysProcAttr 350 } 351 352 type SysProcAttr struct { 353 Rfork int // additional flags to pass to rfork 354 } 355 356 var zeroProcAttr ProcAttr 357 var zeroSysProcAttr SysProcAttr 358 359 func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { 360 var ( 361 p [2]int 362 n int 363 errbuf [ERRMAX]byte 364 wmsg Waitmsg 365 ) 366 367 if attr == nil { 368 attr = &zeroProcAttr 369 } 370 sys := attr.Sys 371 if sys == nil { 372 sys = &zeroSysProcAttr 373 } 374 375 p[0] = -1 376 p[1] = -1 377 378 // Convert args to C form. 379 argv0p, err := BytePtrFromString(argv0) 380 if err != nil { 381 return 0, err 382 } 383 argvp, err := SlicePtrFromStrings(argv) 384 if err != nil { 385 return 0, err 386 } 387 388 destDir := attr.Dir 389 if destDir == "" { 390 wdmu.Lock() 391 destDir = wdStr 392 wdmu.Unlock() 393 } 394 var dir *byte 395 if destDir != "" { 396 dir, err = BytePtrFromString(destDir) 397 if err != nil { 398 return 0, err 399 } 400 } 401 var envvParsed []envItem 402 if attr.Env != nil { 403 envvParsed = make([]envItem, 0, len(attr.Env)) 404 for _, v := range attr.Env { 405 i := 0 406 for i < len(v) && v[i] != '=' { 407 i++ 408 } 409 410 envname, err := BytePtrFromString("/env/" + v[:i]) 411 if err != nil { 412 return 0, err 413 } 414 envvalue := make([]byte, len(v)-i) 415 copy(envvalue, v[i+1:]) 416 envvParsed = append(envvParsed, envItem{envname, &envvalue[0], len(v) - i}) 417 } 418 } 419 420 // Allocate child status pipe close on exec. 421 e := cexecPipe(p[:]) 422 423 if e != nil { 424 return 0, e 425 } 426 427 // Kick off child. 428 pid, err = forkAndExecInChild(argv0p, argvp, envvParsed, dir, attr, p[1], sys.Rfork) 429 430 if err != nil { 431 if p[0] >= 0 { 432 Close(p[0]) 433 Close(p[1]) 434 } 435 return 0, err 436 } 437 438 // Read child error status from pipe. 439 Close(p[1]) 440 n, err = Read(p[0], errbuf[:]) 441 Close(p[0]) 442 443 if err != nil || n != 0 { 444 if n > 0 { 445 err = NewError(string(errbuf[:n])) 446 } else if err == nil { 447 err = NewError("failed to read exec status") 448 } 449 450 // Child failed; wait for it to exit, to make sure 451 // the zombies don't accumulate. 452 for wmsg.Pid != pid { 453 Await(&wmsg) 454 } 455 return 0, err 456 } 457 458 // Read got EOF, so pipe closed on exec, so exec succeeded. 459 return pid, nil 460 } 461 462 type waitErr struct { 463 Waitmsg 464 err error 465 } 466 467 var procs struct { 468 sync.Mutex 469 waits map[int]chan *waitErr 470 } 471 472 // startProcess starts a new goroutine, tied to the OS 473 // thread, which runs the process and subsequently waits 474 // for it to finish, communicating the process stats back 475 // to any goroutines that may have been waiting on it. 476 // 477 // Such a dedicated goroutine is needed because on 478 // Plan 9, only the parent thread can wait for a child, 479 // whereas goroutines tend to jump OS threads (e.g., 480 // between starting a process and running Wait(), the 481 // goroutine may have been rescheduled). 482 func startProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { 483 type forkRet struct { 484 pid int 485 err error 486 } 487 488 forkc := make(chan forkRet, 1) 489 go func() { 490 runtime.LockOSThread() 491 var ret forkRet 492 493 ret.pid, ret.err = forkExec(argv0, argv, attr) 494 // If fork fails there is nothing to wait for. 495 if ret.err != nil || ret.pid == 0 { 496 forkc <- ret 497 return 498 } 499 500 waitc := make(chan *waitErr, 1) 501 502 // Mark that the process is running. 503 procs.Lock() 504 if procs.waits == nil { 505 procs.waits = make(map[int]chan *waitErr) 506 } 507 procs.waits[ret.pid] = waitc 508 procs.Unlock() 509 510 forkc <- ret 511 512 var w waitErr 513 for w.err == nil && w.Pid != ret.pid { 514 w.err = Await(&w.Waitmsg) 515 } 516 waitc <- &w 517 close(waitc) 518 }() 519 ret := <-forkc 520 return ret.pid, ret.err 521 } 522 523 // Combination of fork and exec, careful to be thread safe. 524 func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { 525 return startProcess(argv0, argv, attr) 526 } 527 528 // StartProcess wraps ForkExec for package os. 529 func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) { 530 pid, err = startProcess(argv0, argv, attr) 531 return pid, 0, err 532 } 533 534 // Ordinary exec. 535 func Exec(argv0 string, argv []string, envv []string) (err error) { 536 if envv != nil { 537 r1, _, _ := RawSyscall(SYS_RFORK, RFCENVG, 0, 0) 538 if int32(r1) == -1 { 539 return NewError(errstr()) 540 } 541 542 for _, v := range envv { 543 i := 0 544 for i < len(v) && v[i] != '=' { 545 i++ 546 } 547 548 fd, e := Create("/env/"+v[:i], O_WRONLY, 0666) 549 if e != nil { 550 return e 551 } 552 553 _, e = Write(fd, []byte(v[i+1:])) 554 if e != nil { 555 Close(fd) 556 return e 557 } 558 Close(fd) 559 } 560 } 561 562 argv0p, err := BytePtrFromString(argv0) 563 if err != nil { 564 return err 565 } 566 argvp, err := SlicePtrFromStrings(argv) 567 if err != nil { 568 return err 569 } 570 _, _, e1 := Syscall(SYS_EXEC, 571 uintptr(unsafe.Pointer(argv0p)), 572 uintptr(unsafe.Pointer(&argvp[0])), 573 0) 574 575 return e1 576 } 577 578 // WaitProcess waits until the pid of a 579 // running process is found in the queue of 580 // wait messages. It is used in conjunction 581 // with ForkExec/StartProcess to wait for a 582 // running process to exit. 583 func WaitProcess(pid int, w *Waitmsg) (err error) { 584 procs.Lock() 585 ch := procs.waits[pid] 586 procs.Unlock() 587 588 var wmsg *waitErr 589 if ch != nil { 590 wmsg = <-ch 591 procs.Lock() 592 if procs.waits[pid] == ch { 593 delete(procs.waits, pid) 594 } 595 procs.Unlock() 596 } 597 if wmsg == nil { 598 // ch was missing or ch is closed 599 return NewError("process not found") 600 } 601 if wmsg.err != nil { 602 return wmsg.err 603 } 604 if w != nil { 605 *w = wmsg.Waitmsg 606 } 607 return nil 608 }