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