github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/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 err1 = setgroups1(ngroups, groups) 147 if err1 != 0 { 148 goto childerror 149 } 150 err1 = setgid(uintptr(cred.Gid)) 151 if err1 != 0 { 152 goto childerror 153 } 154 err1 = setuid(uintptr(cred.Uid)) 155 if err1 != 0 { 156 goto childerror 157 } 158 } 159 160 // Chdir 161 if dir != nil { 162 err1 = chdir(uintptr(unsafe.Pointer(dir))) 163 if err1 != 0 { 164 goto childerror 165 } 166 } 167 168 // Pass 1: look for fd[i] < i and move those up above len(fd) 169 // so that pass 2 won't stomp on an fd it needs later. 170 if pipe < nextfd { 171 _, err1 = fcntl1(uintptr(pipe), F_DUP2FD, uintptr(nextfd)) 172 if err1 != 0 { 173 goto childerror 174 } 175 fcntl1(uintptr(nextfd), F_SETFD, FD_CLOEXEC) 176 pipe = nextfd 177 nextfd++ 178 } 179 for i = 0; i < len(fd); i++ { 180 if fd[i] >= 0 && fd[i] < int(i) { 181 if nextfd == pipe { // don't stomp on pipe 182 nextfd++ 183 } 184 _, err1 = fcntl1(uintptr(fd[i]), F_DUP2FD, uintptr(nextfd)) 185 if err1 != 0 { 186 goto childerror 187 } 188 fcntl1(uintptr(nextfd), F_SETFD, FD_CLOEXEC) 189 fd[i] = nextfd 190 nextfd++ 191 } 192 } 193 194 // Pass 2: dup fd[i] down onto i. 195 for i = 0; i < len(fd); i++ { 196 if fd[i] == -1 { 197 close(uintptr(i)) 198 continue 199 } 200 if fd[i] == int(i) { 201 // dup2(i, i) won't clear close-on-exec flag on Linux, 202 // probably not elsewhere either. 203 _, err1 = fcntl1(uintptr(fd[i]), F_SETFD, 0) 204 if err1 != 0 { 205 goto childerror 206 } 207 continue 208 } 209 // The new fd is created NOT close-on-exec, 210 // which is exactly what we want. 211 _, err1 = fcntl1(uintptr(fd[i]), F_DUP2FD, uintptr(i)) 212 if err1 != 0 { 213 goto childerror 214 } 215 } 216 217 // By convention, we don't close-on-exec the fds we are 218 // started with, so if len(fd) < 3, close 0, 1, 2 as needed. 219 // Programs that know they inherit fds >= 3 will need 220 // to set them close-on-exec. 221 for i = len(fd); i < 3; i++ { 222 close(uintptr(i)) 223 } 224 225 // Detach fd 0 from tty 226 if sys.Noctty { 227 err1 = ioctl(0, uintptr(TIOCNOTTY), 0) 228 if err1 != 0 { 229 goto childerror 230 } 231 } 232 233 // Set the controlling TTY to Ctty 234 if sys.Setctty { 235 err1 = ioctl(uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0) 236 if err1 != 0 { 237 goto childerror 238 } 239 } 240 241 // Time to exec. 242 err1 = execve( 243 uintptr(unsafe.Pointer(argv0)), 244 uintptr(unsafe.Pointer(&argv[0])), 245 uintptr(unsafe.Pointer(&envv[0]))) 246 247 childerror: 248 // send error code on pipe 249 write1(uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1)) 250 for { 251 exit(253) 252 } 253 } 254 255 // Try to open a pipe with O_CLOEXEC set on both file descriptors. 256 func forkExecPipe(p []int) error { 257 err := Pipe(p) 258 if err != nil { 259 return err 260 } 261 _, err = fcntl(p[0], F_SETFD, FD_CLOEXEC) 262 if err != nil { 263 return err 264 } 265 _, err = fcntl(p[1], F_SETFD, FD_CLOEXEC) 266 return err 267 }