1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1985-2012 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                 Eclipse Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*          http://www.eclipse.org/org/documents/epl-v10.html           *
11*         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
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_tty.h>
134#include <ast_vfork.h>
135
136#ifndef ENOSYS
137#define ENOSYS	EINVAL
138#endif
139
140#if _lib_spawnve && _hdr_process
141#include <process.h>
142#if defined(P_NOWAIT) || defined(_P_NOWAIT)
143#undef	_lib_spawnve
144#endif
145#endif
146
147#if !_lib_vfork
148#undef	_real_vfork
149#endif
150
151/*
152 * fork+exec+(setsid|setpgid)
153 */
154
155pid_t
156spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid)
157{
158#if _lib_fork || _lib_vfork
159	int			n;
160	int			m;
161	pid_t			pid;
162	pid_t			rid;
163#if _real_vfork
164	volatile int		exec_errno;
165	volatile int* volatile	exec_errno_ptr;
166#else
167	int			err[2];
168#endif
169#endif
170
171#if 0
172	if (access(path, X_OK))
173		return -1;
174#endif
175	if (!envv)
176		envv = environ;
177#if _lib_spawnve
178#if _lib_fork || _lib_vfork
179	if (!pgid)
180#endif
181		return spawnve(path, argv, envv);
182#endif
183#if _lib_fork || _lib_vfork
184	n = errno;
185#if _real_vfork
186	exec_errno = 0;
187	exec_errno_ptr = &exec_errno;
188#else
189	if (pipe(err) < 0)
190		err[0] = -1;
191	else
192	{
193		fcntl(err[0], F_SETFD, FD_CLOEXEC);
194		fcntl(err[1], F_SETFD, FD_CLOEXEC);
195	}
196#endif
197	sigcritical(SIG_REG_EXEC|SIG_REG_PROC);
198#if _lib_vfork
199	pid = vfork();
200#else
201	pid = fork();
202#endif
203	if (pid == -1)
204		n = errno;
205	else if (!pid)
206	{
207		sigcritical(0);
208		if (pgid == -1)
209			setsid();
210		else if (pgid)
211		{
212			m = 0;
213			if (pgid == 1 || pgid == -2 && (m = 1))
214				pgid = getpid();
215			if (setpgid(0, pgid) < 0 && errno == EPERM)
216				setpgid(pgid, 0);
217#if _lib_tcgetpgrp
218			if (m)
219				tcsetpgrp(2, pgid);
220#else
221#ifdef TIOCSPGRP
222			if (m)
223				ioctl(2, TIOCSPGRP, &pgid);
224#endif
225#endif
226		}
227		execve(path, argv, envv);
228#if _real_vfork
229		*exec_errno_ptr = errno;
230#else
231		if (err[0] != -1)
232		{
233			m = errno;
234			write(err[1], &m, sizeof(m));
235		}
236#endif
237		_exit(errno == ENOENT ? EXIT_NOTFOUND : EXIT_NOEXEC);
238	}
239	rid = pid;
240#if _real_vfork
241	if (pid != -1 && (m = *exec_errno_ptr))
242	{
243		while (waitpid(pid, NiL, 0) == -1 && errno == EINTR);
244		rid = pid = -1;
245		n = m;
246	}
247#else
248	if (err[0] != -1)
249	{
250		close(err[1]);
251		if (pid != -1)
252		{
253			m = 0;
254			while (read(err[0], &m, sizeof(m)) == -1)
255				if (errno != EINTR)
256				{
257					m = errno;
258					break;
259				}
260			if (m)
261			{
262				while (waitpid(pid, &n, 0) && errno == EINTR);
263				rid = pid = -1;
264				n = m;
265			}
266		}
267		close(err[0]);
268	}
269#endif
270	sigcritical(0);
271	if (pid != -1 && pgid > 0)
272	{
273		/*
274		 * parent and child are in a race here
275		 */
276
277		if (pgid == 1)
278			pgid = pid;
279		if (setpgid(pid, pgid) < 0 && pid != pgid && errno == EPERM)
280			setpgid(pid, pid);
281	}
282	errno = n;
283	return rid;
284#else
285	errno = ENOSYS;
286	return -1;
287#endif
288}
289
290#endif
291
292#endif
293
294#endif
295
296#endif
297