xref: /titanic_50/usr/src/lib/libast/common/comp/spawnveg.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*3e14f97fSRoger A. Faulkner *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6da2e3ebdSchin *                  Common Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
19da2e3ebdSchin *                   Phong Vo <kpv@research.att.com>                    *
20da2e3ebdSchin *                                                                      *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #pragma prototyped
23da2e3ebdSchin 
24da2e3ebdSchin /*
25da2e3ebdSchin  * spawnveg -- spawnve with process group or session control
26da2e3ebdSchin  *
27da2e3ebdSchin  *	pgid	<0	setsid()	[session group leader]
28da2e3ebdSchin  *		 0	nothing		[retain session and process group]
29da2e3ebdSchin  *		 1	setpgid(0,0)	[process group leader]
30da2e3ebdSchin  *		>1	setpgid(0,pgid)	[join process group]
31da2e3ebdSchin  */
32da2e3ebdSchin 
33da2e3ebdSchin #include <ast.h>
34da2e3ebdSchin 
35da2e3ebdSchin #if _lib_spawnveg
36da2e3ebdSchin 
37da2e3ebdSchin NoN(spawnveg)
38da2e3ebdSchin 
39da2e3ebdSchin #else
40da2e3ebdSchin 
41da2e3ebdSchin #if _lib_posix_spawn > 1	/* reports underlying exec() errors */
42da2e3ebdSchin 
43da2e3ebdSchin #include <spawn.h>
44da2e3ebdSchin #include <error.h>
45da2e3ebdSchin #include <wait.h>
46da2e3ebdSchin 
47da2e3ebdSchin pid_t
48da2e3ebdSchin spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid)
49da2e3ebdSchin {
50da2e3ebdSchin 	int			err;
51da2e3ebdSchin 	pid_t			pid;
52da2e3ebdSchin 	posix_spawnattr_t	attr;
53da2e3ebdSchin 
54da2e3ebdSchin 	if (err = posix_spawnattr_init(&attr))
5534f9b3eeSRoland Mainz 		goto nope;
56da2e3ebdSchin 	if (pgid)
57da2e3ebdSchin 	{
58da2e3ebdSchin 		if (pgid <= 1)
59da2e3ebdSchin 			pgid = 0;
60da2e3ebdSchin 		if (err = posix_spawnattr_setpgroup(&attr, pgid))
61da2e3ebdSchin 			goto bad;
62da2e3ebdSchin 		if (err = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETPGROUP))
63da2e3ebdSchin 			goto bad;
64da2e3ebdSchin 	}
65da2e3ebdSchin 	if (err = posix_spawn(&pid, path, NiL, &attr, argv, envv ? envv : environ))
66da2e3ebdSchin 		goto bad;
67da2e3ebdSchin 	posix_spawnattr_destroy(&attr);
68da2e3ebdSchin #if _lib_posix_spawn < 2
69da2e3ebdSchin 	if (waitpid(pid, &err, WNOHANG|WNOWAIT) == pid && EXIT_STATUS(err) == 127)
70da2e3ebdSchin 	{
71da2e3ebdSchin 		while (waitpid(pid, NiL, 0) == -1 && errno == EINTR);
72da2e3ebdSchin 		if (!access(path, X_OK))
73da2e3ebdSchin 			errno = ENOEXEC;
74da2e3ebdSchin 		pid = -1;
75da2e3ebdSchin 	}
76da2e3ebdSchin #endif
77da2e3ebdSchin 	return pid;
78da2e3ebdSchin  bad:
7934f9b3eeSRoland Mainz 	posix_spawnattr_destroy(&attr);
8034f9b3eeSRoland Mainz  nope:
81da2e3ebdSchin 	errno = err;
82da2e3ebdSchin 	return -1;
83da2e3ebdSchin }
84da2e3ebdSchin 
85da2e3ebdSchin #else
86da2e3ebdSchin 
87da2e3ebdSchin #if _lib_spawn_mode
88da2e3ebdSchin 
89da2e3ebdSchin #include <process.h>
90da2e3ebdSchin 
91da2e3ebdSchin #ifndef P_NOWAIT
92da2e3ebdSchin #define P_NOWAIT	_P_NOWAIT
93da2e3ebdSchin #endif
94da2e3ebdSchin #ifndef P_DETACH
95da2e3ebdSchin #define P_DETACH	_P_DETACH
96da2e3ebdSchin #endif
97da2e3ebdSchin 
98da2e3ebdSchin pid_t
99da2e3ebdSchin spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid)
100da2e3ebdSchin {
101da2e3ebdSchin 	return spawnve(pgid ? P_DETACH : P_NOWAIT, path, argv, envv ? envv : environ);
102da2e3ebdSchin }
103da2e3ebdSchin 
104da2e3ebdSchin #else
105da2e3ebdSchin 
106da2e3ebdSchin #if _lib_spawn && _hdr_spawn && _mem_pgroup_inheritance
107da2e3ebdSchin 
108da2e3ebdSchin #include <spawn.h>
109da2e3ebdSchin 
110da2e3ebdSchin /*
111da2e3ebdSchin  * open-edition/mvs/zos fork+exec+(setpgid)
112da2e3ebdSchin  */
113da2e3ebdSchin 
114da2e3ebdSchin pid_t
115da2e3ebdSchin spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid)
116da2e3ebdSchin {
117da2e3ebdSchin 	struct inheritance	inherit;
118da2e3ebdSchin 
119da2e3ebdSchin 	inherit.flags = 0;
120da2e3ebdSchin 	if (pgid)
121da2e3ebdSchin 	{
122da2e3ebdSchin 		inherit.flags |= SPAWN_SETGROUP;
123da2e3ebdSchin 		inherit.pgroup = (pgid > 1) ? pgid : SPAWN_NEWPGROUP;
124da2e3ebdSchin 	}
125da2e3ebdSchin 	return spawn(path, 0, (int*)0, &inherit, (const char**)argv, (const char**)envv);
126da2e3ebdSchin }
127da2e3ebdSchin 
128da2e3ebdSchin #else
129da2e3ebdSchin 
130da2e3ebdSchin #include <error.h>
131da2e3ebdSchin #include <wait.h>
132da2e3ebdSchin #include <sig.h>
133da2e3ebdSchin #include <ast_vfork.h>
134da2e3ebdSchin 
135da2e3ebdSchin #ifndef ENOSYS
136da2e3ebdSchin #define ENOSYS	EINVAL
137da2e3ebdSchin #endif
138da2e3ebdSchin 
139da2e3ebdSchin #if _lib_spawnve && _hdr_process
140da2e3ebdSchin #include <process.h>
141da2e3ebdSchin #if defined(P_NOWAIT) || defined(_P_NOWAIT)
142da2e3ebdSchin #undef	_lib_spawnve
143da2e3ebdSchin #endif
144da2e3ebdSchin #endif
145da2e3ebdSchin 
146da2e3ebdSchin #if !_lib_vfork
147da2e3ebdSchin #undef	_real_vfork
148da2e3ebdSchin #endif
149da2e3ebdSchin 
150da2e3ebdSchin /*
151da2e3ebdSchin  * fork+exec+(setsid|setpgid)
152da2e3ebdSchin  */
153da2e3ebdSchin 
154da2e3ebdSchin pid_t
155da2e3ebdSchin spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid)
156da2e3ebdSchin {
157da2e3ebdSchin #if _lib_fork || _lib_vfork
158da2e3ebdSchin 	int			n;
159da2e3ebdSchin 	int			m;
160da2e3ebdSchin 	pid_t			pid;
161da2e3ebdSchin 	pid_t			rid;
162da2e3ebdSchin #if _real_vfork
163da2e3ebdSchin 	volatile int		exec_errno;
164da2e3ebdSchin 	volatile int* volatile	exec_errno_ptr;
165da2e3ebdSchin #else
166da2e3ebdSchin 	int			err[2];
167da2e3ebdSchin #endif
168da2e3ebdSchin #endif
169da2e3ebdSchin 
170da2e3ebdSchin #if 0
171da2e3ebdSchin 	if (access(path, X_OK))
172da2e3ebdSchin 		return -1;
173da2e3ebdSchin #endif
174da2e3ebdSchin 	if (!envv)
175da2e3ebdSchin 		envv = environ;
176da2e3ebdSchin #if _lib_spawnve
177da2e3ebdSchin #if _lib_fork || _lib_vfork
178da2e3ebdSchin 	if (!pgid)
179da2e3ebdSchin #endif
180da2e3ebdSchin 		return spawnve(path, argv, envv);
181da2e3ebdSchin #endif
182da2e3ebdSchin #if _lib_fork || _lib_vfork
183da2e3ebdSchin 	n = errno;
184da2e3ebdSchin #if _real_vfork
185da2e3ebdSchin 	exec_errno = 0;
186da2e3ebdSchin 	exec_errno_ptr = &exec_errno;
187da2e3ebdSchin #else
188da2e3ebdSchin 	if (pipe(err) < 0)
189da2e3ebdSchin 		err[0] = -1;
190da2e3ebdSchin 	else
191da2e3ebdSchin 	{
192da2e3ebdSchin 		fcntl(err[0], F_SETFD, FD_CLOEXEC);
193da2e3ebdSchin 		fcntl(err[1], F_SETFD, FD_CLOEXEC);
194da2e3ebdSchin 	}
195da2e3ebdSchin #endif
196da2e3ebdSchin 	sigcritical(1);
197da2e3ebdSchin #if _lib_vfork
198da2e3ebdSchin 	pid = vfork();
199da2e3ebdSchin #else
200da2e3ebdSchin 	pid = fork();
201da2e3ebdSchin #endif
202da2e3ebdSchin 	sigcritical(0);
2037c2fbfb3SApril Chin 	if (pid == -1)
2047c2fbfb3SApril Chin 		n = errno;
2057c2fbfb3SApril Chin 	else if (!pid)
206da2e3ebdSchin 	{
207da2e3ebdSchin 		if (pgid < 0)
208da2e3ebdSchin 			setsid();
209da2e3ebdSchin 		else if (pgid > 0)
210da2e3ebdSchin 		{
211da2e3ebdSchin 			if (pgid == 1)
212da2e3ebdSchin 				pgid = 0;
213da2e3ebdSchin 			if (setpgid(0, pgid) < 0 && pgid && errno == EPERM)
214da2e3ebdSchin 				setpgid(0, 0);
215da2e3ebdSchin 		}
216da2e3ebdSchin 		execve(path, argv, envv);
217da2e3ebdSchin #if _real_vfork
218da2e3ebdSchin 		*exec_errno_ptr = errno;
219da2e3ebdSchin #else
220da2e3ebdSchin 		if (err[0] != -1)
221da2e3ebdSchin 		{
222da2e3ebdSchin 			n = errno;
223da2e3ebdSchin 			write(err[1], &n, sizeof(n));
224da2e3ebdSchin 		}
225da2e3ebdSchin #endif
226da2e3ebdSchin 		_exit(errno == ENOENT ? EXIT_NOTFOUND : EXIT_NOEXEC);
227da2e3ebdSchin 	}
228da2e3ebdSchin 	rid = pid;
229da2e3ebdSchin #if _real_vfork
230da2e3ebdSchin 	if (pid != -1 && (m = *exec_errno_ptr))
231da2e3ebdSchin 	{
232da2e3ebdSchin 		while (waitpid(pid, NiL, 0) == -1 && errno == EINTR);
233da2e3ebdSchin 		rid = pid = -1;
234da2e3ebdSchin 		n = m;
235da2e3ebdSchin 	}
236da2e3ebdSchin #else
2377c2fbfb3SApril Chin 	if (err[0] != -1)
238da2e3ebdSchin 	{
239da2e3ebdSchin 		close(err[1]);
2407c2fbfb3SApril Chin 		if (pid != -1 && read(err[0], &m, sizeof(m)) == sizeof(m) && m)
241da2e3ebdSchin 		{
242da2e3ebdSchin 			while (waitpid(pid, NiL, 0) == -1 && errno == EINTR);
243da2e3ebdSchin 			rid = pid = -1;
244da2e3ebdSchin 			n = m;
245da2e3ebdSchin 		}
246da2e3ebdSchin 		close(err[0]);
247da2e3ebdSchin 	}
248da2e3ebdSchin #endif
249da2e3ebdSchin 	if (pid != -1 && pgid > 0)
250da2e3ebdSchin 	{
251da2e3ebdSchin 		/*
252da2e3ebdSchin 		 * parent and child are in a race here
253da2e3ebdSchin 		 */
254da2e3ebdSchin 
255da2e3ebdSchin 		if (pgid == 1)
256da2e3ebdSchin 			pgid = pid;
257da2e3ebdSchin 		if (setpgid(pid, pgid) < 0 && pid != pgid && errno == EPERM)
258da2e3ebdSchin 			setpgid(pid, pid);
259da2e3ebdSchin 	}
260da2e3ebdSchin 	errno = n;
261da2e3ebdSchin 	return rid;
262da2e3ebdSchin #else
263da2e3ebdSchin 	errno = ENOSYS;
264da2e3ebdSchin 	return -1;
265da2e3ebdSchin #endif
266da2e3ebdSchin }
267da2e3ebdSchin 
268da2e3ebdSchin #endif
269da2e3ebdSchin 
270da2e3ebdSchin #endif
271da2e3ebdSchin 
272da2e3ebdSchin #endif
273da2e3ebdSchin 
274da2e3ebdSchin #endif
275