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