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