...

Source file src/pkg/syscall/exec_darwin.go

     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		Ptrace     bool        // Enable tracing.
    15		Setsid     bool        // Create session.
    16		Setpgid    bool        // Set process group ID to Pgid, or, if Pgid == 0, to new pid.
    17		Setctty    bool        // Set controlling terminal to fd Ctty
    18		Noctty     bool        // Detach fd 0 from controlling terminal
    19		Ctty       int         // Controlling TTY fd
    20		Foreground bool        // Place child's process group in foreground. (Implies Setpgid. Uses Ctty as fd of controlling TTY)
    21		Pgid       int         // Child's process group ID if Setpgid.
    22	}
    23	
    24	// Implemented in runtime package.
    25	func runtime_BeforeFork()
    26	func runtime_AfterFork()
    27	func runtime_AfterForkInChild()
    28	
    29	// Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
    30	// If a dup or exec fails, write the errno error to pipe.
    31	// (Pipe is close-on-exec so if exec succeeds, it will be closed.)
    32	// In the child, this function must not acquire any locks, because
    33	// they might have been locked at the time of the fork. This means
    34	// no rescheduling, no malloc calls, and no new stack segments.
    35	// For the same reason compiler does not race instrument it.
    36	// The calls to rawSyscall are okay because they are assembly
    37	// functions that do not grow the stack.
    38	//go:norace
    39	func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
    40		// Declare all variables at top in case any
    41		// declarations require heap allocation (e.g., err1).
    42		var (
    43			r1     uintptr
    44			err1   Errno
    45			nextfd int
    46			i      int
    47		)
    48	
    49		// guard against side effects of shuffling fds below.
    50		// Make sure that nextfd is beyond any currently open files so
    51		// that we can't run the risk of overwriting any of them.
    52		fd := make([]int, len(attr.Files))
    53		nextfd = len(attr.Files)
    54		for i, ufd := range attr.Files {
    55			if nextfd < int(ufd) {
    56				nextfd = int(ufd)
    57			}
    58			fd[i] = int(ufd)
    59		}
    60		nextfd++
    61	
    62		// About to call fork.
    63		// No more allocation or calls of non-assembly functions.
    64		runtime_BeforeFork()
    65		r1, _, err1 = rawSyscall(funcPC(libc_fork_trampoline), 0, 0, 0)
    66		if err1 != 0 {
    67			runtime_AfterFork()
    68			return 0, err1
    69		}
    70	
    71		if r1 != 0 {
    72			// parent; return PID
    73			runtime_AfterFork()
    74			return int(r1), 0
    75		}
    76	
    77		// Fork succeeded, now in child.
    78	
    79		runtime_AfterForkInChild()
    80	
    81		// Enable tracing if requested.
    82		if sys.Ptrace {
    83			if err := ptrace(PTRACE_TRACEME, 0, 0, 0); err != nil {
    84				err1 = err.(Errno)
    85				goto childerror
    86			}
    87		}
    88	
    89		// Session ID
    90		if sys.Setsid {
    91			_, _, err1 = rawSyscall(funcPC(libc_setsid_trampoline), 0, 0, 0)
    92			if err1 != 0 {
    93				goto childerror
    94			}
    95		}
    96	
    97		// Set process group
    98		if sys.Setpgid || sys.Foreground {
    99			// Place child in process group.
   100			_, _, err1 = rawSyscall(funcPC(libc_setpgid_trampoline), 0, uintptr(sys.Pgid), 0)
   101			if err1 != 0 {
   102				goto childerror
   103			}
   104		}
   105	
   106		if sys.Foreground {
   107			pgrp := sys.Pgid
   108			if pgrp == 0 {
   109				r1, _, err1 = rawSyscall(funcPC(libc_getpid_trampoline), 0, 0, 0)
   110				if err1 != 0 {
   111					goto childerror
   112				}
   113	
   114				pgrp = int(r1)
   115			}
   116	
   117			// Place process group in foreground.
   118			_, _, err1 = rawSyscall(funcPC(libc_ioctl_trampoline), uintptr(sys.Ctty), uintptr(TIOCSPGRP), uintptr(unsafe.Pointer(&pgrp)))
   119			if err1 != 0 {
   120				goto childerror
   121			}
   122		}
   123	
   124		// Chroot
   125		if chroot != nil {
   126			_, _, err1 = rawSyscall(funcPC(libc_chroot_trampoline), uintptr(unsafe.Pointer(chroot)), 0, 0)
   127			if err1 != 0 {
   128				goto childerror
   129			}
   130		}
   131	
   132		// User and groups
   133		if cred := sys.Credential; cred != nil {
   134			ngroups := uintptr(len(cred.Groups))
   135			groups := uintptr(0)
   136			if ngroups > 0 {
   137				groups = uintptr(unsafe.Pointer(&cred.Groups[0]))
   138			}
   139			if !cred.NoSetGroups {
   140				_, _, err1 = rawSyscall(funcPC(libc_setgroups_trampoline), ngroups, groups, 0)
   141				if err1 != 0 {
   142					goto childerror
   143				}
   144			}
   145			_, _, err1 = rawSyscall(funcPC(libc_setgid_trampoline), uintptr(cred.Gid), 0, 0)
   146			if err1 != 0 {
   147				goto childerror
   148			}
   149			_, _, err1 = rawSyscall(funcPC(libc_setuid_trampoline), uintptr(cred.Uid), 0, 0)
   150			if err1 != 0 {
   151				goto childerror
   152			}
   153		}
   154	
   155		// Chdir
   156		if dir != nil {
   157			_, _, err1 = rawSyscall(funcPC(libc_chdir_trampoline), uintptr(unsafe.Pointer(dir)), 0, 0)
   158			if err1 != 0 {
   159				goto childerror
   160			}
   161		}
   162	
   163		// Pass 1: look for fd[i] < i and move those up above len(fd)
   164		// so that pass 2 won't stomp on an fd it needs later.
   165		if pipe < nextfd {
   166			_, _, err1 = rawSyscall(funcPC(libc_dup2_trampoline), uintptr(pipe), uintptr(nextfd), 0)
   167			if err1 != 0 {
   168				goto childerror
   169			}
   170			rawSyscall(funcPC(libc_fcntl_trampoline), uintptr(nextfd), F_SETFD, FD_CLOEXEC)
   171			pipe = nextfd
   172			nextfd++
   173		}
   174		for i = 0; i < len(fd); i++ {
   175			if fd[i] >= 0 && fd[i] < int(i) {
   176				if nextfd == pipe { // don't stomp on pipe
   177					nextfd++
   178				}
   179				_, _, err1 = rawSyscall(funcPC(libc_dup2_trampoline), uintptr(fd[i]), uintptr(nextfd), 0)
   180				if err1 != 0 {
   181					goto childerror
   182				}
   183				rawSyscall(funcPC(libc_fcntl_trampoline), uintptr(nextfd), F_SETFD, FD_CLOEXEC)
   184				fd[i] = nextfd
   185				nextfd++
   186			}
   187		}
   188	
   189		// Pass 2: dup fd[i] down onto i.
   190		for i = 0; i < len(fd); i++ {
   191			if fd[i] == -1 {
   192				rawSyscall(funcPC(libc_close_trampoline), uintptr(i), 0, 0)
   193				continue
   194			}
   195			if fd[i] == int(i) {
   196				// dup2(i, i) won't clear close-on-exec flag on Linux,
   197				// probably not elsewhere either.
   198				_, _, err1 = rawSyscall(funcPC(libc_fcntl_trampoline), uintptr(fd[i]), F_SETFD, 0)
   199				if err1 != 0 {
   200					goto childerror
   201				}
   202				continue
   203			}
   204			// The new fd is created NOT close-on-exec,
   205			// which is exactly what we want.
   206			_, _, err1 = rawSyscall(funcPC(libc_dup2_trampoline), uintptr(fd[i]), uintptr(i), 0)
   207			if err1 != 0 {
   208				goto childerror
   209			}
   210		}
   211	
   212		// By convention, we don't close-on-exec the fds we are
   213		// started with, so if len(fd) < 3, close 0, 1, 2 as needed.
   214		// Programs that know they inherit fds >= 3 will need
   215		// to set them close-on-exec.
   216		for i = len(fd); i < 3; i++ {
   217			rawSyscall(funcPC(libc_close_trampoline), uintptr(i), 0, 0)
   218		}
   219	
   220		// Detach fd 0 from tty
   221		if sys.Noctty {
   222			_, _, err1 = rawSyscall(funcPC(libc_ioctl_trampoline), 0, uintptr(TIOCNOTTY), 0)
   223			if err1 != 0 {
   224				goto childerror
   225			}
   226		}
   227	
   228		// Set the controlling TTY to Ctty
   229		if sys.Setctty {
   230			_, _, err1 = rawSyscall(funcPC(libc_ioctl_trampoline), uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0)
   231			if err1 != 0 {
   232				goto childerror
   233			}
   234		}
   235	
   236		// Time to exec.
   237		_, _, err1 = rawSyscall(funcPC(libc_execve_trampoline),
   238			uintptr(unsafe.Pointer(argv0)),
   239			uintptr(unsafe.Pointer(&argv[0])),
   240			uintptr(unsafe.Pointer(&envv[0])))
   241	
   242	childerror:
   243		// send error code on pipe
   244		rawSyscall(funcPC(libc_write_trampoline), uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1))
   245		for {
   246			rawSyscall(funcPC(libc_exit_trampoline), 253, 0, 0)
   247		}
   248	}
   249	

View as plain text