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