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