Source file src/syscall/exec_plan9.go

     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  }
   612  

View as plain text