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  	)
   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] >= len(fd) {
   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  }
   610  

View as plain text