src/pkg/syscall/exec_unix.go - The Go Programming Language

Golang

Source file src/pkg/syscall/exec_unix.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	// +build darwin freebsd linux netbsd openbsd
     6	
     7	// Fork, exec, wait, etc.
     8	
     9	package syscall
    10	
    11	import (
    12		"runtime"
    13		"sync"
    14		"unsafe"
    15	)
    16	
    17	// Lock synchronizing creation of new file descriptors with fork.
    18	//
    19	// We want the child in a fork/exec sequence to inherit only the
    20	// file descriptors we intend.  To do that, we mark all file
    21	// descriptors close-on-exec and then, in the child, explicitly
    22	// unmark the ones we want the exec'ed program to keep.
    23	// Unix doesn't make this easy: there is, in general, no way to
    24	// allocate a new file descriptor close-on-exec.  Instead you
    25	// have to allocate the descriptor and then mark it close-on-exec.
    26	// If a fork happens between those two events, the child's exec
    27	// will inherit an unwanted file descriptor.
    28	//
    29	// This lock solves that race: the create new fd/mark close-on-exec
    30	// operation is done holding ForkLock for reading, and the fork itself
    31	// is done holding ForkLock for writing.  At least, that's the idea.
    32	// There are some complications.
    33	//
    34	// Some system calls that create new file descriptors can block
    35	// for arbitrarily long times: open on a hung NFS server or named
    36	// pipe, accept on a socket, and so on.  We can't reasonably grab
    37	// the lock across those operations.
    38	//
    39	// It is worse to inherit some file descriptors than others.
    40	// If a non-malicious child accidentally inherits an open ordinary file,
    41	// that's not a big deal.  On the other hand, if a long-lived child
    42	// accidentally inherits the write end of a pipe, then the reader
    43	// of that pipe will not see EOF until that child exits, potentially
    44	// causing the parent program to hang.  This is a common problem
    45	// in threaded C programs that use popen.
    46	//
    47	// Luckily, the file descriptors that are most important not to
    48	// inherit are not the ones that can take an arbitrarily long time
    49	// to create: pipe returns instantly, and the net package uses
    50	// non-blocking I/O to accept on a listening socket.
    51	// The rules for which file descriptor-creating operations use the
    52	// ForkLock are as follows:
    53	//
    54	// 1) Pipe.    Does not block.  Use the ForkLock.
    55	// 2) Socket.  Does not block.  Use the ForkLock.
    56	// 3) Accept.  If using non-blocking mode, use the ForkLock.
    57	//             Otherwise, live with the race.
    58	// 4) Open.    Can block.  Use O_CLOEXEC if available (Linux).
    59	//             Otherwise, live with the race.
    60	// 5) Dup.     Does not block.  Use the ForkLock.
    61	//             On Linux, could use fcntl F_DUPFD_CLOEXEC
    62	//             instead of the ForkLock, but only for dup(fd, -1).
    63	
    64	var ForkLock sync.RWMutex
    65	
    66	// Convert array of string to array
    67	// of NUL-terminated byte pointer.
    68	func StringSlicePtr(ss []string) []*byte {
    69		bb := make([]*byte, len(ss)+1)
    70		for i := 0; i < len(ss); i++ {
    71			bb[i] = StringBytePtr(ss[i])
    72		}
    73		bb[len(ss)] = nil
    74		return bb
    75	}
    76	
    77	func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) }
    78	
    79	func SetNonblock(fd int, nonblocking bool) (err error) {
    80		flag, err := fcntl(fd, F_GETFL, 0)
    81		if err != nil {
    82			return err
    83		}
    84		if nonblocking {
    85			flag |= O_NONBLOCK
    86		} else {
    87			flag &= ^O_NONBLOCK
    88		}
    89		_, err = fcntl(fd, F_SETFL, flag)
    90		return err
    91	}
    92	
    93	// Credential holds user and group identities to be assumed
    94	// by a child process started by StartProcess.
    95	type Credential struct {
    96		Uid    uint32   // User ID.
    97		Gid    uint32   // Group ID.
    98		Groups []uint32 // Supplementary group IDs.
    99	}
   100	
   101	// ProcAttr holds attributes that will be applied to a new process started
   102	// by StartProcess.
   103	type ProcAttr struct {
   104		Dir   string    // Current working directory.
   105		Env   []string  // Environment.
   106		Files []uintptr // File descriptors.
   107		Sys   *SysProcAttr
   108	}
   109	
   110	var zeroProcAttr ProcAttr
   111	var zeroSysProcAttr SysProcAttr
   112	
   113	func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
   114		var p [2]int
   115		var n int
   116		var err1 Errno
   117		var wstatus WaitStatus
   118	
   119		if attr == nil {
   120			attr = &zeroProcAttr
   121		}
   122		sys := attr.Sys
   123		if sys == nil {
   124			sys = &zeroSysProcAttr
   125		}
   126	
   127		p[0] = -1
   128		p[1] = -1
   129	
   130		// Convert args to C form.
   131		argv0p := StringBytePtr(argv0)
   132		argvp := StringSlicePtr(argv)
   133		envvp := StringSlicePtr(attr.Env)
   134	
   135		if runtime.GOOS == "freebsd" && len(argv[0]) > len(argv0) {
   136			argvp[0] = argv0p
   137		}
   138	
   139		var chroot *byte
   140		if sys.Chroot != "" {
   141			chroot = StringBytePtr(sys.Chroot)
   142		}
   143		var dir *byte
   144		if attr.Dir != "" {
   145			dir = StringBytePtr(attr.Dir)
   146		}
   147	
   148		// Acquire the fork lock so that no other threads
   149		// create new fds that are not yet close-on-exec
   150		// before we fork.
   151		ForkLock.Lock()
   152	
   153		// Allocate child status pipe close on exec.
   154		if err = Pipe(p[0:]); err != nil {
   155			goto error
   156		}
   157		if _, err = fcntl(p[0], F_SETFD, FD_CLOEXEC); err != nil {
   158			goto error
   159		}
   160		if _, err = fcntl(p[1], F_SETFD, FD_CLOEXEC); err != nil {
   161			goto error
   162		}
   163	
   164		// Kick off child.
   165		pid, err1 = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1])
   166		if err1 != 0 {
   167			err = Errno(err1)
   168			goto error
   169		}
   170		ForkLock.Unlock()
   171	
   172		// Read child error status from pipe.
   173		Close(p[1])
   174		n, err = read(p[0], (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1)))
   175		Close(p[0])
   176		if err != nil || n != 0 {
   177			if n == int(unsafe.Sizeof(err1)) {
   178				err = Errno(err1)
   179			}
   180			if err == nil {
   181				err = EPIPE
   182			}
   183	
   184			// Child failed; wait for it to exit, to make sure
   185			// the zombies don't accumulate.
   186			_, err1 := Wait4(pid, &wstatus, 0, nil)
   187			for err1 == EINTR {
   188				_, err1 = Wait4(pid, &wstatus, 0, nil)
   189			}
   190			return 0, err
   191		}
   192	
   193		// Read got EOF, so pipe closed on exec, so exec succeeded.
   194		return pid, nil
   195	
   196	error:
   197		if p[0] >= 0 {
   198			Close(p[0])
   199			Close(p[1])
   200		}
   201		ForkLock.Unlock()
   202		return 0, err
   203	}
   204	
   205	// Combination of fork and exec, careful to be thread safe.
   206	func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
   207		return forkExec(argv0, argv, attr)
   208	}
   209	
   210	// StartProcess wraps ForkExec for package os.
   211	func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
   212		pid, err = forkExec(argv0, argv, attr)
   213		return pid, 0, err
   214	}
   215	
   216	// Ordinary exec.
   217	func Exec(argv0 string, argv []string, envv []string) (err error) {
   218		_, _, err1 := RawSyscall(SYS_EXECVE,
   219			uintptr(unsafe.Pointer(StringBytePtr(argv0))),
   220			uintptr(unsafe.Pointer(&StringSlicePtr(argv)[0])),
   221			uintptr(unsafe.Pointer(&StringSlicePtr(envv)[0])))
   222		return Errno(err1)
   223	}