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