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  }