1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2010 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 8 * * 9 * A copy of the License is available at * 10 * http://www.opensource.org/licenses/cpl1.0.txt * 11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 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_vfork.h> 134 135 #ifndef ENOSYS 136 #define ENOSYS EINVAL 137 #endif 138 139 #if _lib_spawnve && _hdr_process 140 #include <process.h> 141 #if defined(P_NOWAIT) || defined(_P_NOWAIT) 142 #undef _lib_spawnve 143 #endif 144 #endif 145 146 #if !_lib_vfork 147 #undef _real_vfork 148 #endif 149 150 /* 151 * fork+exec+(setsid|setpgid) 152 */ 153 154 pid_t 155 spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid) 156 { 157 #if _lib_fork || _lib_vfork 158 int n; 159 int m; 160 pid_t pid; 161 pid_t rid; 162 #if _real_vfork 163 volatile int exec_errno; 164 volatile int* volatile exec_errno_ptr; 165 #else 166 int err[2]; 167 #endif 168 #endif 169 170 #if 0 171 if (access(path, X_OK)) 172 return -1; 173 #endif 174 if (!envv) 175 envv = environ; 176 #if _lib_spawnve 177 #if _lib_fork || _lib_vfork 178 if (!pgid) 179 #endif 180 return spawnve(path, argv, envv); 181 #endif 182 #if _lib_fork || _lib_vfork 183 n = errno; 184 #if _real_vfork 185 exec_errno = 0; 186 exec_errno_ptr = &exec_errno; 187 #else 188 if (pipe(err) < 0) 189 err[0] = -1; 190 else 191 { 192 fcntl(err[0], F_SETFD, FD_CLOEXEC); 193 fcntl(err[1], F_SETFD, FD_CLOEXEC); 194 } 195 #endif 196 sigcritical(1); 197 #if _lib_vfork 198 pid = vfork(); 199 #else 200 pid = fork(); 201 #endif 202 sigcritical(0); 203 if (pid == -1) 204 n = errno; 205 else if (!pid) 206 { 207 if (pgid < 0) 208 setsid(); 209 else if (pgid > 0) 210 { 211 if (pgid == 1) 212 pgid = 0; 213 if (setpgid(0, pgid) < 0 && pgid && errno == EPERM) 214 setpgid(0, 0); 215 } 216 execve(path, argv, envv); 217 #if _real_vfork 218 *exec_errno_ptr = errno; 219 #else 220 if (err[0] != -1) 221 { 222 n = errno; 223 write(err[1], &n, sizeof(n)); 224 } 225 #endif 226 _exit(errno == ENOENT ? EXIT_NOTFOUND : EXIT_NOEXEC); 227 } 228 rid = pid; 229 #if _real_vfork 230 if (pid != -1 && (m = *exec_errno_ptr)) 231 { 232 while (waitpid(pid, NiL, 0) == -1 && errno == EINTR); 233 rid = pid = -1; 234 n = m; 235 } 236 #else 237 if (err[0] != -1) 238 { 239 close(err[1]); 240 if (pid != -1 && read(err[0], &m, sizeof(m)) == sizeof(m) && m) 241 { 242 while (waitpid(pid, NiL, 0) == -1 && errno == EINTR); 243 rid = pid = -1; 244 n = m; 245 } 246 close(err[0]); 247 } 248 #endif 249 if (pid != -1 && pgid > 0) 250 { 251 /* 252 * parent and child are in a race here 253 */ 254 255 if (pgid == 1) 256 pgid = pid; 257 if (setpgid(pid, pgid) < 0 && pid != pgid && errno == EPERM) 258 setpgid(pid, pid); 259 } 260 errno = n; 261 return rid; 262 #else 263 errno = ENOSYS; 264 return -1; 265 #endif 266 } 267 268 #endif 269 270 #endif 271 272 #endif 273 274 #endif 275