github.com/golang-haiku/go-1.4.3@v0.0.0-20190609233734-1f5ae41cc308/src/syscall/exec_unix.go (about) 1 // Copyright 2009 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 // +build darwin dragonfly freebsd haiku linux netbsd openbsd solaris 6 7 // Fork, exec, wait, etc. 8 9 package syscall 10 11 import ( 12 "runtime" 13 "sync" 14 "unsafe" 15 ) 16 17 // Lock synchronizing creation of new file descriptors with fork. 18 // 19 // We want the child in a fork/exec sequence to inherit only the 20 // file descriptors we intend. To do that, we mark all file 21 // descriptors close-on-exec and then, in the child, explicitly 22 // unmark the ones we want the exec'ed program to keep. 23 // Unix doesn't make this easy: there is, in general, no way to 24 // allocate a new file descriptor close-on-exec. Instead you 25 // have to allocate the descriptor and then mark it close-on-exec. 26 // If a fork happens between those two events, the child's exec 27 // will inherit an unwanted file descriptor. 28 // 29 // This lock solves that race: the create new fd/mark close-on-exec 30 // operation is done holding ForkLock for reading, and the fork itself 31 // is done holding ForkLock for writing. At least, that's the idea. 32 // There are some complications. 33 // 34 // Some system calls that create new file descriptors can block 35 // for arbitrarily long times: open on a hung NFS server or named 36 // pipe, accept on a socket, and so on. We can't reasonably grab 37 // the lock across those operations. 38 // 39 // It is worse to inherit some file descriptors than others. 40 // If a non-malicious child accidentally inherits an open ordinary file, 41 // that's not a big deal. On the other hand, if a long-lived child 42 // accidentally inherits the write end of a pipe, then the reader 43 // of that pipe will not see EOF until that child exits, potentially 44 // causing the parent program to hang. This is a common problem 45 // in threaded C programs that use popen. 46 // 47 // Luckily, the file descriptors that are most important not to 48 // inherit are not the ones that can take an arbitrarily long time 49 // to create: pipe returns instantly, and the net package uses 50 // non-blocking I/O to accept on a listening socket. 51 // The rules for which file descriptor-creating operations use the 52 // ForkLock are as follows: 53 // 54 // 1) Pipe. Does not block. Use the ForkLock. 55 // 2) Socket. Does not block. Use the ForkLock. 56 // 3) Accept. If using non-blocking mode, use the ForkLock. 57 // Otherwise, live with the race. 58 // 4) Open. Can block. Use O_CLOEXEC if available (Linux). 59 // Otherwise, live with the race. 60 // 5) Dup. Does not block. Use the ForkLock. 61 // On Linux, could use fcntl F_DUPFD_CLOEXEC 62 // instead of the ForkLock, but only for dup(fd, -1). 63 64 var ForkLock sync.RWMutex 65 66 // StringSlicePtr is deprecated. Use SlicePtrFromStrings instead. 67 // If any string contains a NUL byte this function panics instead 68 // of returning an error. 69 func StringSlicePtr(ss []string) []*byte { 70 bb := make([]*byte, len(ss)+1) 71 for i := 0; i < len(ss); i++ { 72 bb[i] = StringBytePtr(ss[i]) 73 } 74 bb[len(ss)] = nil 75 return bb 76 } 77 78 // SlicePtrFromStrings converts a slice of strings to a slice of 79 // pointers to NUL-terminated byte slices. If any string contains 80 // a NUL byte, it returns (nil, EINVAL). 81 func SlicePtrFromStrings(ss []string) ([]*byte, error) { 82 var err error 83 bb := make([]*byte, len(ss)+1) 84 for i := 0; i < len(ss); i++ { 85 bb[i], err = BytePtrFromString(ss[i]) 86 if err != nil { 87 return nil, err 88 } 89 } 90 bb[len(ss)] = nil 91 return bb, nil 92 } 93 94 func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) } 95 96 func SetNonblock(fd int, nonblocking bool) (err error) { 97 if runtime.GOOS == "haiku" { 98 // FIXME: Haiku does not have a working netpoller yet. 99 return nil 100 } 101 flag, err := fcntl(fd, F_GETFL, 0) 102 if err != nil { 103 return err 104 } 105 if nonblocking { 106 flag |= O_NONBLOCK 107 } else { 108 flag &= ^O_NONBLOCK 109 } 110 _, err = fcntl(fd, F_SETFL, flag) 111 return err 112 } 113 114 // Credential holds user and group identities to be assumed 115 // by a child process started by StartProcess. 116 type Credential struct { 117 Uid uint32 // User ID. 118 Gid uint32 // Group ID. 119 Groups []uint32 // Supplementary group IDs. 120 } 121 122 // ProcAttr holds attributes that will be applied to a new process started 123 // by StartProcess. 124 type ProcAttr struct { 125 Dir string // Current working directory. 126 Env []string // Environment. 127 Files []uintptr // File descriptors. 128 Sys *SysProcAttr 129 } 130 131 var zeroProcAttr ProcAttr 132 var zeroSysProcAttr SysProcAttr 133 134 func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { 135 var p [2]int 136 var n int 137 var err1 Errno 138 var wstatus WaitStatus 139 140 if attr == nil { 141 attr = &zeroProcAttr 142 } 143 sys := attr.Sys 144 if sys == nil { 145 sys = &zeroSysProcAttr 146 } 147 148 p[0] = -1 149 p[1] = -1 150 151 // Convert args to C form. 152 argv0p, err := BytePtrFromString(argv0) 153 if err != nil { 154 return 0, err 155 } 156 argvp, err := SlicePtrFromStrings(argv) 157 if err != nil { 158 return 0, err 159 } 160 envvp, err := SlicePtrFromStrings(attr.Env) 161 if err != nil { 162 return 0, err 163 } 164 165 if (runtime.GOOS == "freebsd" || runtime.GOOS == "dragonfly") && len(argv[0]) > len(argv0) { 166 argvp[0] = argv0p 167 } 168 169 var chroot *byte 170 if sys.Chroot != "" { 171 chroot, err = BytePtrFromString(sys.Chroot) 172 if err != nil { 173 return 0, err 174 } 175 } 176 var dir *byte 177 if attr.Dir != "" { 178 dir, err = BytePtrFromString(attr.Dir) 179 if err != nil { 180 return 0, err 181 } 182 } 183 184 // Acquire the fork lock so that no other threads 185 // create new fds that are not yet close-on-exec 186 // before we fork. 187 ForkLock.Lock() 188 189 // Allocate child status pipe close on exec. 190 if err = forkExecPipe(p[:]); err != nil { 191 goto error 192 } 193 194 // Kick off child. 195 pid, err1 = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1]) 196 if err1 != 0 { 197 err = Errno(err1) 198 goto error 199 } 200 ForkLock.Unlock() 201 202 // Read child error status from pipe. 203 Close(p[1]) 204 n, err = readlen(p[0], (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1))) 205 Close(p[0]) 206 if err != nil || n != 0 { 207 if n == int(unsafe.Sizeof(err1)) { 208 err = Errno(err1) 209 } 210 if err == nil { 211 err = EPIPE 212 } 213 214 // Child failed; wait for it to exit, to make sure 215 // the zombies don't accumulate. 216 _, err1 := Wait4(pid, &wstatus, 0, nil) 217 for err1 == EINTR { 218 _, err1 = Wait4(pid, &wstatus, 0, nil) 219 } 220 return 0, err 221 } 222 223 // Read got EOF, so pipe closed on exec, so exec succeeded. 224 return pid, nil 225 226 error: 227 if p[0] >= 0 { 228 Close(p[0]) 229 Close(p[1]) 230 } 231 ForkLock.Unlock() 232 return 0, err 233 } 234 235 // Combination of fork and exec, careful to be thread safe. 236 func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { 237 return forkExec(argv0, argv, attr) 238 } 239 240 // StartProcess wraps ForkExec for package os. 241 func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) { 242 pid, err = forkExec(argv0, argv, attr) 243 return pid, 0, err 244 } 245 246 // Ordinary exec. 247 func Exec(argv0 string, argv []string, envv []string) (err error) { 248 argv0p, err := BytePtrFromString(argv0) 249 if err != nil { 250 return err 251 } 252 argvp, err := SlicePtrFromStrings(argv) 253 if err != nil { 254 return err 255 } 256 envvp, err := SlicePtrFromStrings(envv) 257 if err != nil { 258 return err 259 } 260 _, _, err1 := RawSyscall(SYS_EXECVE, 261 uintptr(unsafe.Pointer(argv0p)), 262 uintptr(unsafe.Pointer(&argvp[0])), 263 uintptr(unsafe.Pointer(&envvp[0]))) 264 return Errno(err1) 265 }