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