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 
37 NoN(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 
47 pid_t
48 spawnveg(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 
98 pid_t
99 spawnveg(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 
114 pid_t
115 spawnveg(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 
155 pid_t
156 spawnveg(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