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