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