/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1985-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * * * * Information and Software Systems Research * * AT&T Research * * Florham Park NJ * * * * Glenn Fowler * * David Korn * * Phong Vo * * * ***********************************************************************/ #pragma prototyped /* * spawnveg -- spawnve with process group or session control * * pgid <0 setsid() [session group leader] * 0 nothing [retain session and process group] * 1 setpgid(0,0) [process group leader] * >1 setpgid(0,pgid) [join process group] */ #include #if _lib_spawnveg NoN(spawnveg) #else #if _lib_posix_spawn > 1 /* reports underlying exec() errors */ #include #include #include pid_t spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid) { int err; pid_t pid; posix_spawnattr_t attr; if (err = posix_spawnattr_init(&attr)) goto nope; if (pgid) { if (pgid <= 1) pgid = 0; if (err = posix_spawnattr_setpgroup(&attr, pgid)) goto bad; if (err = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETPGROUP)) goto bad; } if (err = posix_spawn(&pid, path, NiL, &attr, argv, envv ? envv : environ)) goto bad; posix_spawnattr_destroy(&attr); #if _lib_posix_spawn < 2 if (waitpid(pid, &err, WNOHANG|WNOWAIT) == pid && EXIT_STATUS(err) == 127) { while (waitpid(pid, NiL, 0) == -1 && errno == EINTR); if (!access(path, X_OK)) errno = ENOEXEC; pid = -1; } #endif return pid; bad: posix_spawnattr_destroy(&attr); nope: errno = err; return -1; } #else #if _lib_spawn_mode #include #ifndef P_NOWAIT #define P_NOWAIT _P_NOWAIT #endif #ifndef P_DETACH #define P_DETACH _P_DETACH #endif pid_t spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid) { return spawnve(pgid ? P_DETACH : P_NOWAIT, path, argv, envv ? envv : environ); } #else #if _lib_spawn && _hdr_spawn && _mem_pgroup_inheritance #include /* * open-edition/mvs/zos fork+exec+(setpgid) */ pid_t spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid) { struct inheritance inherit; inherit.flags = 0; if (pgid) { inherit.flags |= SPAWN_SETGROUP; inherit.pgroup = (pgid > 1) ? pgid : SPAWN_NEWPGROUP; } return spawn(path, 0, (int*)0, &inherit, (const char**)argv, (const char**)envv); } #else #include #include #include #include #ifndef ENOSYS #define ENOSYS EINVAL #endif #if _lib_spawnve && _hdr_process #include #if defined(P_NOWAIT) || defined(_P_NOWAIT) #undef _lib_spawnve #endif #endif #if !_lib_vfork #undef _real_vfork #endif /* * fork+exec+(setsid|setpgid) */ pid_t spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid) { #if _lib_fork || _lib_vfork int n; int m; pid_t pid; pid_t rid; #if _real_vfork volatile int exec_errno; volatile int* volatile exec_errno_ptr; #else int err[2]; #endif #endif #if 0 if (access(path, X_OK)) return -1; #endif if (!envv) envv = environ; #if _lib_spawnve #if _lib_fork || _lib_vfork if (!pgid) #endif return spawnve(path, argv, envv); #endif #if _lib_fork || _lib_vfork n = errno; #if _real_vfork exec_errno = 0; exec_errno_ptr = &exec_errno; #else if (pipe(err) < 0) err[0] = -1; else { fcntl(err[0], F_SETFD, FD_CLOEXEC); fcntl(err[1], F_SETFD, FD_CLOEXEC); } #endif sigcritical(1); #if _lib_vfork pid = vfork(); #else pid = fork(); #endif sigcritical(0); if (pid == -1) n = errno; else if (!pid) { if (pgid < 0) setsid(); else if (pgid > 0) { if (pgid == 1) pgid = 0; if (setpgid(0, pgid) < 0 && pgid && errno == EPERM) setpgid(0, 0); } execve(path, argv, envv); #if _real_vfork *exec_errno_ptr = errno; #else if (err[0] != -1) { n = errno; write(err[1], &n, sizeof(n)); } #endif _exit(errno == ENOENT ? EXIT_NOTFOUND : EXIT_NOEXEC); } rid = pid; #if _real_vfork if (pid != -1 && (m = *exec_errno_ptr)) { while (waitpid(pid, NiL, 0) == -1 && errno == EINTR); rid = pid = -1; n = m; } #else if (err[0] != -1) { close(err[1]); if (pid != -1 && read(err[0], &m, sizeof(m)) == sizeof(m) && m) { while (waitpid(pid, NiL, 0) == -1 && errno == EINTR); rid = pid = -1; n = m; } close(err[0]); } #endif if (pid != -1 && pgid > 0) { /* * parent and child are in a race here */ if (pgid == 1) pgid = pid; if (setpgid(pid, pgid) < 0 && pid != pgid && errno == EPERM) setpgid(pid, pid); } errno = n; return rid; #else errno = ENOSYS; return -1; #endif } #endif #endif #endif #endif