github.com/ActiveState/go@v0.0.0-20170614201249-0b81c023a722/src/syscall/exec_solaris.go (about)

     1  // Copyright 2011 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  package syscall
     6  
     7  import (
     8  	"unsafe"
     9  )
    10  
    11  type SysProcAttr struct {
    12  	Chroot     string      // Chroot.
    13  	Credential *Credential // Credential.
    14  	Setsid     bool        // Create session.
    15  	Setpgid    bool        // Set process group ID to Pgid, or, if Pgid == 0, to new pid.
    16  	Setctty    bool        // Set controlling terminal to fd Ctty
    17  	Noctty     bool        // Detach fd 0 from controlling terminal
    18  	Ctty       int         // Controlling TTY fd
    19  	Foreground bool        // Place child's process group in foreground. (Implies Setpgid. Uses Ctty as fd of controlling TTY)
    20  	Pgid       int         // Child's process group ID if Setpgid.
    21  }
    22  
    23  // Implemented in runtime package.
    24  func runtime_BeforeFork()
    25  func runtime_AfterFork()
    26  func runtime_AfterForkInChild()
    27  
    28  func chdir(path uintptr) (err Errno)
    29  func chroot1(path uintptr) (err Errno)
    30  func close(fd uintptr) (err Errno)
    31  func execve(path uintptr, argv uintptr, envp uintptr) (err Errno)
    32  func exit(code uintptr)
    33  func fcntl1(fd uintptr, cmd uintptr, arg uintptr) (val uintptr, err Errno)
    34  func forkx(flags uintptr) (pid uintptr, err Errno)
    35  func getpid() (pid uintptr, err Errno)
    36  func ioctl(fd uintptr, req uintptr, arg uintptr) (err Errno)
    37  func setgid(gid uintptr) (err Errno)
    38  func setgroups1(ngid uintptr, gid uintptr) (err Errno)
    39  func setsid() (pid uintptr, err Errno)
    40  func setuid(uid uintptr) (err Errno)
    41  func setpgid(pid uintptr, pgid uintptr) (err Errno)
    42  func write1(fd uintptr, buf uintptr, nbyte uintptr) (n uintptr, err Errno)
    43  
    44  // Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
    45  // If a dup or exec fails, write the errno error to pipe.
    46  // (Pipe is close-on-exec so if exec succeeds, it will be closed.)
    47  // In the child, this function must not acquire any locks, because
    48  // they might have been locked at the time of the fork. This means
    49  // no rescheduling, no malloc calls, and no new stack segments.
    50  //
    51  // We call hand-crafted syscalls, implemented in
    52  // ../runtime/syscall_solaris.go, rather than generated libc wrappers
    53  // because we need to avoid lazy-loading the functions (might malloc,
    54  // split the stack, or acquire mutexes). We can't call RawSyscall
    55  // because it's not safe even for BSD-subsystem calls.
    56  //go:norace
    57  func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
    58  	// Declare all variables at top in case any
    59  	// declarations require heap allocation (e.g., err1).
    60  	var (
    61  		r1     uintptr
    62  		err1   Errno
    63  		nextfd int
    64  		i      int
    65  	)
    66  
    67  	// guard against side effects of shuffling fds below.
    68  	// Make sure that nextfd is beyond any currently open files so
    69  	// that we can't run the risk of overwriting any of them.
    70  	fd := make([]int, len(attr.Files))
    71  	nextfd = len(attr.Files)
    72  	for i, ufd := range attr.Files {
    73  		if nextfd < int(ufd) {
    74  			nextfd = int(ufd)
    75  		}
    76  		fd[i] = int(ufd)
    77  	}
    78  	nextfd++
    79  
    80  	// About to call fork.
    81  	// No more allocation or calls of non-assembly functions.
    82  	runtime_BeforeFork()
    83  	r1, err1 = forkx(0x1) // FORK_NOSIGCHLD
    84  	if err1 != 0 {
    85  		runtime_AfterFork()
    86  		return 0, err1
    87  	}
    88  
    89  	if r1 != 0 {
    90  		// parent; return PID
    91  		runtime_AfterFork()
    92  		return int(r1), 0
    93  	}
    94  
    95  	// Fork succeeded, now in child.
    96  
    97  	runtime_AfterForkInChild()
    98  
    99  	// Session ID
   100  	if sys.Setsid {
   101  		_, err1 = setsid()
   102  		if err1 != 0 {
   103  			goto childerror
   104  		}
   105  	}
   106  
   107  	// Set process group
   108  	if sys.Setpgid || sys.Foreground {
   109  		// Place child in process group.
   110  		err1 = setpgid(0, uintptr(sys.Pgid))
   111  		if err1 != 0 {
   112  			goto childerror
   113  		}
   114  	}
   115  
   116  	if sys.Foreground {
   117  		pgrp := sys.Pgid
   118  		if pgrp == 0 {
   119  			r1, err1 = getpid()
   120  			if err1 != 0 {
   121  				goto childerror
   122  			}
   123  
   124  			pgrp = int(r1)
   125  		}
   126  
   127  		// Place process group in foreground.
   128  		err1 = ioctl(uintptr(sys.Ctty), uintptr(TIOCSPGRP), uintptr(unsafe.Pointer(&pgrp)))
   129  		if err1 != 0 {
   130  			goto childerror
   131  		}
   132  	}
   133  
   134  	// Chroot
   135  	if chroot != nil {
   136  		err1 = chroot1(uintptr(unsafe.Pointer(chroot)))
   137  		if err1 != 0 {
   138  			goto childerror
   139  		}
   140  	}
   141  
   142  	// User and groups
   143  	if cred := sys.Credential; cred != nil {
   144  		ngroups := uintptr(len(cred.Groups))
   145  		groups := uintptr(0)
   146  		if ngroups > 0 {
   147  			groups = uintptr(unsafe.Pointer(&cred.Groups[0]))
   148  		}
   149  		if !cred.NoSetGroups {
   150  			err1 = setgroups1(ngroups, groups)
   151  			if err1 != 0 {
   152  				goto childerror
   153  			}
   154  		}
   155  		err1 = setgid(uintptr(cred.Gid))
   156  		if err1 != 0 {
   157  			goto childerror
   158  		}
   159  		err1 = setuid(uintptr(cred.Uid))
   160  		if err1 != 0 {
   161  			goto childerror
   162  		}
   163  	}
   164  
   165  	// Chdir
   166  	if dir != nil {
   167  		err1 = chdir(uintptr(unsafe.Pointer(dir)))
   168  		if err1 != 0 {
   169  			goto childerror
   170  		}
   171  	}
   172  
   173  	// Pass 1: look for fd[i] < i and move those up above len(fd)
   174  	// so that pass 2 won't stomp on an fd it needs later.
   175  	if pipe < nextfd {
   176  		_, err1 = fcntl1(uintptr(pipe), F_DUP2FD, uintptr(nextfd))
   177  		if err1 != 0 {
   178  			goto childerror
   179  		}
   180  		fcntl1(uintptr(nextfd), F_SETFD, FD_CLOEXEC)
   181  		pipe = nextfd
   182  		nextfd++
   183  	}
   184  	for i = 0; i < len(fd); i++ {
   185  		if fd[i] >= 0 && fd[i] < int(i) {
   186  			if nextfd == pipe { // don't stomp on pipe
   187  				nextfd++
   188  			}
   189  			_, err1 = fcntl1(uintptr(fd[i]), F_DUP2FD, uintptr(nextfd))
   190  			if err1 != 0 {
   191  				goto childerror
   192  			}
   193  			fcntl1(uintptr(nextfd), F_SETFD, FD_CLOEXEC)
   194  			fd[i] = nextfd
   195  			nextfd++
   196  		}
   197  	}
   198  
   199  	// Pass 2: dup fd[i] down onto i.
   200  	for i = 0; i < len(fd); i++ {
   201  		if fd[i] == -1 {
   202  			close(uintptr(i))
   203  			continue
   204  		}
   205  		if fd[i] == int(i) {
   206  			// dup2(i, i) won't clear close-on-exec flag on Linux,
   207  			// probably not elsewhere either.
   208  			_, err1 = fcntl1(uintptr(fd[i]), F_SETFD, 0)
   209  			if err1 != 0 {
   210  				goto childerror
   211  			}
   212  			continue
   213  		}
   214  		// The new fd is created NOT close-on-exec,
   215  		// which is exactly what we want.
   216  		_, err1 = fcntl1(uintptr(fd[i]), F_DUP2FD, uintptr(i))
   217  		if err1 != 0 {
   218  			goto childerror
   219  		}
   220  	}
   221  
   222  	// By convention, we don't close-on-exec the fds we are
   223  	// started with, so if len(fd) < 3, close 0, 1, 2 as needed.
   224  	// Programs that know they inherit fds >= 3 will need
   225  	// to set them close-on-exec.
   226  	for i = len(fd); i < 3; i++ {
   227  		close(uintptr(i))
   228  	}
   229  
   230  	// Detach fd 0 from tty
   231  	if sys.Noctty {
   232  		err1 = ioctl(0, uintptr(TIOCNOTTY), 0)
   233  		if err1 != 0 {
   234  			goto childerror
   235  		}
   236  	}
   237  
   238  	// Set the controlling TTY to Ctty
   239  	if sys.Setctty {
   240  		err1 = ioctl(uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0)
   241  		if err1 != 0 {
   242  			goto childerror
   243  		}
   244  	}
   245  
   246  	// Time to exec.
   247  	err1 = execve(
   248  		uintptr(unsafe.Pointer(argv0)),
   249  		uintptr(unsafe.Pointer(&argv[0])),
   250  		uintptr(unsafe.Pointer(&envv[0])))
   251  
   252  childerror:
   253  	// send error code on pipe
   254  	write1(uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1))
   255  	for {
   256  		exit(253)
   257  	}
   258  }
   259  
   260  // Try to open a pipe with O_CLOEXEC set on both file descriptors.
   261  func forkExecPipe(p []int) error {
   262  	err := Pipe(p)
   263  	if err != nil {
   264  		return err
   265  	}
   266  	_, err = fcntl(p[0], F_SETFD, FD_CLOEXEC)
   267  	if err != nil {
   268  		return err
   269  	}
   270  	_, err = fcntl(p[1], F_SETFD, FD_CLOEXEC)
   271  	return err
   272  }