1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2012 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Eclipse Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 8 * * 9 * A copy of the License is available at * 10 * http://www.eclipse.org/org/documents/epl-v10.html * 11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * Glenn Fowler <gsf@research.att.com> * 18 * David Korn <dgk@research.att.com> * 19 * Phong Vo <kpv@research.att.com> * 20 * * 21 ***********************************************************************/ 22 #pragma prototyped 23 24 /* 25 * spawnveg -- spawnve with process group or session control 26 * 27 * pgid <0 setsid() [session group leader] 28 * 0 nothing [retain session and process group] 29 * 1 setpgid(0,0) [process group leader] 30 * >1 setpgid(0,pgid) [join process group] 31 */ 32 33 #include <ast.h> 34 35 #if _lib_spawnveg 36 37 NoN(spawnveg) 38 39 #else 40 41 #if _lib_posix_spawn > 1 /* reports underlying exec() errors */ 42 43 #include <spawn.h> 44 #include <error.h> 45 #include <wait.h> 46 47 pid_t 48 spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid) 49 { 50 int err; 51 pid_t pid; 52 posix_spawnattr_t attr; 53 54 if (err = posix_spawnattr_init(&attr)) 55 goto nope; 56 if (pgid) 57 { 58 if (pgid <= 1) 59 pgid = 0; 60 if (err = posix_spawnattr_setpgroup(&attr, pgid)) 61 goto bad; 62 if (err = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETPGROUP)) 63 goto bad; 64 } 65 if (err = posix_spawn(&pid, path, NiL, &attr, argv, envv ? envv : environ)) 66 goto bad; 67 posix_spawnattr_destroy(&attr); 68 #if _lib_posix_spawn < 2 69 if (waitpid(pid, &err, WNOHANG|WNOWAIT) == pid && EXIT_STATUS(err) == 127) 70 { 71 while (waitpid(pid, NiL, 0) == -1 && errno == EINTR); 72 if (!access(path, X_OK)) 73 errno = ENOEXEC; 74 pid = -1; 75 } 76 #endif 77 return pid; 78 bad: 79 posix_spawnattr_destroy(&attr); 80 nope: 81 errno = err; 82 return -1; 83 } 84 85 #else 86 87 #if _lib_spawn_mode 88 89 #include <process.h> 90 91 #ifndef P_NOWAIT 92 #define P_NOWAIT _P_NOWAIT 93 #endif 94 #ifndef P_DETACH 95 #define P_DETACH _P_DETACH 96 #endif 97 98 pid_t 99 spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid) 100 { 101 return spawnve(pgid ? P_DETACH : P_NOWAIT, path, argv, envv ? envv : environ); 102 } 103 104 #else 105 106 #if _lib_spawn && _hdr_spawn && _mem_pgroup_inheritance 107 108 #include <spawn.h> 109 110 /* 111 * open-edition/mvs/zos fork+exec+(setpgid) 112 */ 113 114 pid_t 115 spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid) 116 { 117 struct inheritance inherit; 118 119 inherit.flags = 0; 120 if (pgid) 121 { 122 inherit.flags |= SPAWN_SETGROUP; 123 inherit.pgroup = (pgid > 1) ? pgid : SPAWN_NEWPGROUP; 124 } 125 return spawn(path, 0, (int*)0, &inherit, (const char**)argv, (const char**)envv); 126 } 127 128 #else 129 130 #include <error.h> 131 #include <wait.h> 132 #include <sig.h> 133 #include <ast_tty.h> 134 #include <ast_vfork.h> 135 136 #ifndef ENOSYS 137 #define ENOSYS EINVAL 138 #endif 139 140 #if _lib_spawnve && _hdr_process 141 #include <process.h> 142 #if defined(P_NOWAIT) || defined(_P_NOWAIT) 143 #undef _lib_spawnve 144 #endif 145 #endif 146 147 #if !_lib_vfork 148 #undef _real_vfork 149 #endif 150 151 /* 152 * fork+exec+(setsid|setpgid) 153 */ 154 155 pid_t 156 spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid) 157 { 158 #if _lib_fork || _lib_vfork 159 int n; 160 int m; 161 pid_t pid; 162 pid_t rid; 163 #if _real_vfork 164 volatile int exec_errno; 165 volatile int* volatile exec_errno_ptr; 166 #else 167 int err[2]; 168 #endif 169 #endif 170 171 #if 0 172 if (access(path, X_OK)) 173 return -1; 174 #endif 175 if (!envv) 176 envv = environ; 177 #if _lib_spawnve 178 #if _lib_fork || _lib_vfork 179 if (!pgid) 180 #endif 181 return spawnve(path, argv, envv); 182 #endif 183 #if _lib_fork || _lib_vfork 184 n = errno; 185 #if _real_vfork 186 exec_errno = 0; 187 exec_errno_ptr = &exec_errno; 188 #else 189 if (pipe(err) < 0) 190 err[0] = -1; 191 else 192 { 193 fcntl(err[0], F_SETFD, FD_CLOEXEC); 194 fcntl(err[1], F_SETFD, FD_CLOEXEC); 195 } 196 #endif 197 sigcritical(SIG_REG_EXEC|SIG_REG_PROC); 198 #if _lib_vfork 199 pid = vfork(); 200 #else 201 pid = fork(); 202 #endif 203 if (pid == -1) 204 n = errno; 205 else if (!pid) 206 { 207 sigcritical(0); 208 if (pgid == -1) 209 setsid(); 210 else if (pgid) 211 { 212 m = 0; 213 if (pgid == 1 || pgid == -2 && (m = 1)) 214 pgid = getpid(); 215 if (setpgid(0, pgid) < 0 && errno == EPERM) 216 setpgid(pgid, 0); 217 #if _lib_tcgetpgrp 218 if (m) 219 tcsetpgrp(2, pgid); 220 #else 221 #ifdef TIOCSPGRP 222 if (m) 223 ioctl(2, TIOCSPGRP, &pgid); 224 #endif 225 #endif 226 } 227 execve(path, argv, envv); 228 #if _real_vfork 229 *exec_errno_ptr = errno; 230 #else 231 if (err[0] != -1) 232 { 233 m = errno; 234 write(err[1], &m, sizeof(m)); 235 } 236 #endif 237 _exit(errno == ENOENT ? EXIT_NOTFOUND : EXIT_NOEXEC); 238 } 239 rid = pid; 240 #if _real_vfork 241 if (pid != -1 && (m = *exec_errno_ptr)) 242 { 243 while (waitpid(pid, NiL, 0) == -1 && errno == EINTR); 244 rid = pid = -1; 245 n = m; 246 } 247 #else 248 if (err[0] != -1) 249 { 250 close(err[1]); 251 if (pid != -1) 252 { 253 m = 0; 254 while (read(err[0], &m, sizeof(m)) == -1) 255 if (errno != EINTR) 256 { 257 m = errno; 258 break; 259 } 260 if (m) 261 { 262 while (waitpid(pid, &n, 0) && errno == EINTR); 263 rid = pid = -1; 264 n = m; 265 } 266 } 267 close(err[0]); 268 } 269 #endif 270 sigcritical(0); 271 if (pid != -1 && pgid > 0) 272 { 273 /* 274 * parent and child are in a race here 275 */ 276 277 if (pgid == 1) 278 pgid = pid; 279 if (setpgid(pid, pgid) < 0 && pid != pgid && errno == EPERM) 280 setpgid(pid, pid); 281 } 282 errno = n; 283 return rid; 284 #else 285 errno = ENOSYS; 286 return -1; 287 #endif 288 } 289 290 #endif 291 292 #endif 293 294 #endif 295 296 #endif 297