Home | History | Annotate | Download | only in syscall
      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 }
    604