1/*********************************************************************** 2* * 3* This software is part of the ast package * 4* Copyright (c) 1985-2011 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 37NoN(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 47pid_t 48spawnveg(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 98pid_t 99spawnveg(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 114pid_t 115spawnveg(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 154pid_t 155spawnveg(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