...

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		"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	

View as plain text