// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin openbsd,amd64 openbsd,arm64

package syscall

import (
	
)

type SysProcAttr struct {
	Chroot     string      // Chroot.
	Credential *Credential // Credential.
	Ptrace     bool        // Enable tracing.
	Setsid     bool        // Create session.
	// Setpgid sets the process group ID of the child to Pgid,
	// or, if Pgid == 0, to the new child's process ID.
	Setpgid bool
	// Setctty sets the controlling terminal of the child to
	// file descriptor Ctty. Ctty must be a descriptor number
	// in the child process: an index into ProcAttr.Files.
	// This is only meaningful if Setsid is true.
	Setctty bool
	Noctty  bool // Detach fd 0 from controlling terminal
	Ctty    int  // Controlling TTY fd
	// Foreground places the child process group in the foreground.
	// This implies Setpgid. The Ctty field must be set to
	// the descriptor of the controlling TTY.
	// Unlike Setctty, in this case Ctty must be a descriptor
	// number in the parent process.
	Foreground bool
	Pgid       int // Child's process group ID if Setpgid.
}

// Implemented in runtime package.
func ()
func ()
func ()

// Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
// If a dup or exec fails, write the errno error to pipe.
// (Pipe is close-on-exec so if exec succeeds, it will be closed.)
// In the child, this function must not acquire any locks, because
// they might have been locked at the time of the fork. This means
// no rescheduling, no malloc calls, and no new stack segments.
// For the same reason compiler does not race instrument it.
// The calls to rawSyscall are okay because they are assembly
// functions that do not grow the stack.
//go:norace
func ( *byte, ,  []*byte, ,  *byte,  *ProcAttr,  *SysProcAttr,  int) ( int,  Errno) {
	// Declare all variables at top in case any
	// declarations require heap allocation (e.g., err1).
	var (
		     uintptr
		   Errno
		 int
		      int
	)

	// guard against side effects of shuffling fds below.
	// Make sure that nextfd is beyond any currently open files so
	// that we can't run the risk of overwriting any of them.
	 := make([]int, len(.Files))
	 = len(.Files)
	for ,  := range .Files {
		if  < int() {
			 = int()
		}
		[] = int()
	}
	++

	// About to call fork.
	// No more allocation or calls of non-assembly functions.
	runtime_BeforeFork()
	, _,  = rawSyscall(funcPC(libc_fork_trampoline), 0, 0, 0)
	if  != 0 {
		runtime_AfterFork()
		return 0, 
	}

	if  != 0 {
		// parent; return PID
		runtime_AfterFork()
		return int(), 0
	}

	// Fork succeeded, now in child.

	runtime_AfterForkInChild()

	// Enable tracing if requested.
	if .Ptrace {
		if  := ptrace(PTRACE_TRACEME, 0, 0, 0);  != nil {
			 = .(Errno)
			goto 
		}
	}

	// Session ID
	if .Setsid {
		_, _,  = rawSyscall(funcPC(libc_setsid_trampoline), 0, 0, 0)
		if  != 0 {
			goto 
		}
	}

	// Set process group
	if .Setpgid || .Foreground {
		// Place child in process group.
		_, _,  = rawSyscall(funcPC(libc_setpgid_trampoline), 0, uintptr(.Pgid), 0)
		if  != 0 {
			goto 
		}
	}

	if .Foreground {
		 := .Pgid
		if  == 0 {
			, _,  = rawSyscall(funcPC(libc_getpid_trampoline), 0, 0, 0)
			if  != 0 {
				goto 
			}

			 = int()
		}

		// Place process group in foreground.
		_, _,  = rawSyscall(funcPC(libc_ioctl_trampoline), uintptr(.Ctty), uintptr(TIOCSPGRP), uintptr(unsafe.Pointer(&)))
		if  != 0 {
			goto 
		}
	}

	// Chroot
	if  != nil {
		_, _,  = rawSyscall(funcPC(libc_chroot_trampoline), uintptr(unsafe.Pointer()), 0, 0)
		if  != 0 {
			goto 
		}
	}

	// User and groups
	if  := .Credential;  != nil {
		 := uintptr(len(.Groups))
		 := uintptr(0)
		if  > 0 {
			 = uintptr(unsafe.Pointer(&.Groups[0]))
		}
		if !.NoSetGroups {
			_, _,  = rawSyscall(funcPC(libc_setgroups_trampoline), , , 0)
			if  != 0 {
				goto 
			}
		}
		_, _,  = rawSyscall(funcPC(libc_setgid_trampoline), uintptr(.Gid), 0, 0)
		if  != 0 {
			goto 
		}
		_, _,  = rawSyscall(funcPC(libc_setuid_trampoline), uintptr(.Uid), 0, 0)
		if  != 0 {
			goto 
		}
	}

	// Chdir
	if  != nil {
		_, _,  = rawSyscall(funcPC(libc_chdir_trampoline), uintptr(unsafe.Pointer()), 0, 0)
		if  != 0 {
			goto 
		}
	}

	// Pass 1: look for fd[i] < i and move those up above len(fd)
	// so that pass 2 won't stomp on an fd it needs later.
	if  <  {
		_, _,  = rawSyscall(funcPC(libc_dup2_trampoline), uintptr(), uintptr(), 0)
		if  != 0 {
			goto 
		}
		rawSyscall(funcPC(libc_fcntl_trampoline), uintptr(), F_SETFD, FD_CLOEXEC)
		 = 
		++
	}
	for  = 0;  < len(); ++ {
		if [] >= 0 && [] < int() {
			if  ==  { // don't stomp on pipe
				++
			}
			_, _,  = rawSyscall(funcPC(libc_dup2_trampoline), uintptr([]), uintptr(), 0)
			if  != 0 {
				goto 
			}
			rawSyscall(funcPC(libc_fcntl_trampoline), uintptr(), F_SETFD, FD_CLOEXEC)
			[] = 
			++
		}
	}

	// Pass 2: dup fd[i] down onto i.
	for  = 0;  < len(); ++ {
		if [] == -1 {
			rawSyscall(funcPC(libc_close_trampoline), uintptr(), 0, 0)
			continue
		}
		if [] == int() {
			// dup2(i, i) won't clear close-on-exec flag on Linux,
			// probably not elsewhere either.
			_, _,  = rawSyscall(funcPC(libc_fcntl_trampoline), uintptr([]), F_SETFD, 0)
			if  != 0 {
				goto 
			}
			continue
		}
		// The new fd is created NOT close-on-exec,
		// which is exactly what we want.
		_, _,  = rawSyscall(funcPC(libc_dup2_trampoline), uintptr([]), uintptr(), 0)
		if  != 0 {
			goto 
		}
	}

	// By convention, we don't close-on-exec the fds we are
	// started with, so if len(fd) < 3, close 0, 1, 2 as needed.
	// Programs that know they inherit fds >= 3 will need
	// to set them close-on-exec.
	for  = len();  < 3; ++ {
		rawSyscall(funcPC(libc_close_trampoline), uintptr(), 0, 0)
	}

	// Detach fd 0 from tty
	if .Noctty {
		_, _,  = rawSyscall(funcPC(libc_ioctl_trampoline), 0, uintptr(TIOCNOTTY), 0)
		if  != 0 {
			goto 
		}
	}

	// Set the controlling TTY to Ctty
	if .Setctty {
		_, _,  = rawSyscall(funcPC(libc_ioctl_trampoline), uintptr(.Ctty), uintptr(TIOCSCTTY), 0)
		if  != 0 {
			goto 
		}
	}

	// Time to exec.
	_, _,  = rawSyscall(funcPC(libc_execve_trampoline),
		uintptr(unsafe.Pointer()),
		uintptr(unsafe.Pointer(&[0])),
		uintptr(unsafe.Pointer(&[0])))

:
	// send error code on pipe
	rawSyscall(funcPC(libc_write_trampoline), uintptr(), uintptr(unsafe.Pointer(&)), unsafe.Sizeof())
	for {
		rawSyscall(funcPC(libc_exit_trampoline), 253, 0, 0)
	}
}