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