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