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