1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2008 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 bad; 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 errno = err; 80 return -1; 81 } 82 83 #else 84 85 #if _lib_spawn_mode 86 87 #include <process.h> 88 89 #ifndef P_NOWAIT 90 #define P_NOWAIT _P_NOWAIT 91 #endif 92 #ifndef P_DETACH 93 #define P_DETACH _P_DETACH 94 #endif 95 96 pid_t 97 spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid) 98 { 99 return spawnve(pgid ? P_DETACH : P_NOWAIT, path, argv, envv ? envv : environ); 100 } 101 102 #else 103 104 #if _lib_spawn && _hdr_spawn && _mem_pgroup_inheritance 105 106 #include <spawn.h> 107 108 /* 109 * open-edition/mvs/zos fork+exec+(setpgid) 110 */ 111 112 pid_t 113 spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid) 114 { 115 struct inheritance inherit; 116 117 inherit.flags = 0; 118 if (pgid) 119 { 120 inherit.flags |= SPAWN_SETGROUP; 121 inherit.pgroup = (pgid > 1) ? pgid : SPAWN_NEWPGROUP; 122 } 123 return spawn(path, 0, (int*)0, &inherit, (const char**)argv, (const char**)envv); 124 } 125 126 #else 127 128 #include <error.h> 129 #include <wait.h> 130 #include <sig.h> 131 #include <ast_vfork.h> 132 133 #ifndef ENOSYS 134 #define ENOSYS EINVAL 135 #endif 136 137 #if _lib_spawnve && _hdr_process 138 #include <process.h> 139 #if defined(P_NOWAIT) || defined(_P_NOWAIT) 140 #undef _lib_spawnve 141 #endif 142 #endif 143 144 #if !_lib_vfork 145 #undef _real_vfork 146 #endif 147 148 /* 149 * fork+exec+(setsid|setpgid) 150 */ 151 152 pid_t 153 spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid) 154 { 155 #if _lib_fork || _lib_vfork 156 int n; 157 int m; 158 pid_t pid; 159 pid_t rid; 160 #if _real_vfork 161 volatile int exec_errno; 162 volatile int* volatile exec_errno_ptr; 163 #else 164 int err[2]; 165 #endif 166 #endif 167 168 #if 0 169 if (access(path, X_OK)) 170 return -1; 171 #endif 172 if (!envv) 173 envv = environ; 174 #if _lib_spawnve 175 #if _lib_fork || _lib_vfork 176 if (!pgid) 177 #endif 178 return spawnve(path, argv, envv); 179 #endif 180 #if _lib_fork || _lib_vfork 181 n = errno; 182 #if _real_vfork 183 exec_errno = 0; 184 exec_errno_ptr = &exec_errno; 185 #else 186 if (pipe(err) < 0) 187 err[0] = -1; 188 else 189 { 190 fcntl(err[0], F_SETFD, FD_CLOEXEC); 191 fcntl(err[1], F_SETFD, FD_CLOEXEC); 192 } 193 #endif 194 sigcritical(1); 195 #if _lib_vfork 196 pid = vfork(); 197 #else 198 pid = fork(); 199 #endif 200 sigcritical(0); 201 if (pid == -1) 202 n = errno; 203 else if (!pid) 204 { 205 if (pgid < 0) 206 setsid(); 207 else if (pgid > 0) 208 { 209 if (pgid == 1) 210 pgid = 0; 211 if (setpgid(0, pgid) < 0 && pgid && errno == EPERM) 212 setpgid(0, 0); 213 } 214 execve(path, argv, envv); 215 #if _real_vfork 216 *exec_errno_ptr = errno; 217 #else 218 if (err[0] != -1) 219 { 220 n = errno; 221 write(err[1], &n, sizeof(n)); 222 } 223 #endif 224 _exit(errno == ENOENT ? EXIT_NOTFOUND : EXIT_NOEXEC); 225 } 226 rid = pid; 227 #if _real_vfork 228 if (pid != -1 && (m = *exec_errno_ptr)) 229 { 230 while (waitpid(pid, NiL, 0) == -1 && errno == EINTR); 231 rid = pid = -1; 232 n = m; 233 } 234 #else 235 if (err[0] != -1) 236 { 237 close(err[1]); 238 if (pid != -1 && read(err[0], &m, sizeof(m)) == sizeof(m) && m) 239 { 240 while (waitpid(pid, NiL, 0) == -1 && errno == EINTR); 241 rid = pid = -1; 242 n = m; 243 } 244 close(err[0]); 245 } 246 #endif 247 if (pid != -1 && pgid > 0) 248 { 249 /* 250 * parent and child are in a race here 251 */ 252 253 if (pgid == 1) 254 pgid = pid; 255 if (setpgid(pid, pgid) < 0 && pid != pgid && errno == EPERM) 256 setpgid(pid, pid); 257 } 258 errno = n; 259 return rid; 260 #else 261 errno = ENOSYS; 262 return -1; 263 #endif 264 } 265 266 #endif 267 268 #endif 269 270 #endif 271 272 #endif 273