Blame src/lib/libast/comp/spawnveg.c

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