xref: /titanic_50/usr/src/lib/libast/common/comp/spawnveg.c (revision dd52495f0d9ba8ff6d84921ec0500be837896554)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2008 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 
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 bad;
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 	errno = err;
80 	return -1;
81 }
82 
83 #else
84 
85 #if _lib_spawn_mode
86 
87 #include <process.h>
88 
89 #ifndef P_NOWAIT
90 #define P_NOWAIT	_P_NOWAIT
91 #endif
92 #ifndef P_DETACH
93 #define P_DETACH	_P_DETACH
94 #endif
95 
96 pid_t
97 spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid)
98 {
99 	return spawnve(pgid ? P_DETACH : P_NOWAIT, path, argv, envv ? envv : environ);
100 }
101 
102 #else
103 
104 #if _lib_spawn && _hdr_spawn && _mem_pgroup_inheritance
105 
106 #include <spawn.h>
107 
108 /*
109  * open-edition/mvs/zos fork+exec+(setpgid)
110  */
111 
112 pid_t
113 spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid)
114 {
115 	struct inheritance	inherit;
116 
117 	inherit.flags = 0;
118 	if (pgid)
119 	{
120 		inherit.flags |= SPAWN_SETGROUP;
121 		inherit.pgroup = (pgid > 1) ? pgid : SPAWN_NEWPGROUP;
122 	}
123 	return spawn(path, 0, (int*)0, &inherit, (const char**)argv, (const char**)envv);
124 }
125 
126 #else
127 
128 #include <error.h>
129 #include <wait.h>
130 #include <sig.h>
131 #include <ast_vfork.h>
132 
133 #ifndef ENOSYS
134 #define ENOSYS	EINVAL
135 #endif
136 
137 #if _lib_spawnve && _hdr_process
138 #include <process.h>
139 #if defined(P_NOWAIT) || defined(_P_NOWAIT)
140 #undef	_lib_spawnve
141 #endif
142 #endif
143 
144 #if !_lib_vfork
145 #undef	_real_vfork
146 #endif
147 
148 /*
149  * fork+exec+(setsid|setpgid)
150  */
151 
152 pid_t
153 spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid)
154 {
155 #if _lib_fork || _lib_vfork
156 	int			n;
157 	int			m;
158 	pid_t			pid;
159 	pid_t			rid;
160 #if _real_vfork
161 	volatile int		exec_errno;
162 	volatile int* volatile	exec_errno_ptr;
163 #else
164 	int			err[2];
165 #endif
166 #endif
167 
168 #if 0
169 	if (access(path, X_OK))
170 		return -1;
171 #endif
172 	if (!envv)
173 		envv = environ;
174 #if _lib_spawnve
175 #if _lib_fork || _lib_vfork
176 	if (!pgid)
177 #endif
178 		return spawnve(path, argv, envv);
179 #endif
180 #if _lib_fork || _lib_vfork
181 	n = errno;
182 #if _real_vfork
183 	exec_errno = 0;
184 	exec_errno_ptr = &exec_errno;
185 #else
186 	if (pipe(err) < 0)
187 		err[0] = -1;
188 	else
189 	{
190 		fcntl(err[0], F_SETFD, FD_CLOEXEC);
191 		fcntl(err[1], F_SETFD, FD_CLOEXEC);
192 	}
193 #endif
194 	sigcritical(1);
195 #if _lib_vfork
196 	pid = vfork();
197 #else
198 	pid = fork();
199 #endif
200 	sigcritical(0);
201 	if (pid == -1)
202 		n = errno;
203 	else if (!pid)
204 	{
205 		if (pgid < 0)
206 			setsid();
207 		else if (pgid > 0)
208 		{
209 			if (pgid == 1)
210 				pgid = 0;
211 			if (setpgid(0, pgid) < 0 && pgid && errno == EPERM)
212 				setpgid(0, 0);
213 		}
214 		execve(path, argv, envv);
215 #if _real_vfork
216 		*exec_errno_ptr = errno;
217 #else
218 		if (err[0] != -1)
219 		{
220 			n = errno;
221 			write(err[1], &n, sizeof(n));
222 		}
223 #endif
224 		_exit(errno == ENOENT ? EXIT_NOTFOUND : EXIT_NOEXEC);
225 	}
226 	rid = pid;
227 #if _real_vfork
228 	if (pid != -1 && (m = *exec_errno_ptr))
229 	{
230 		while (waitpid(pid, NiL, 0) == -1 && errno == EINTR);
231 		rid = pid = -1;
232 		n = m;
233 	}
234 #else
235 	if (err[0] != -1)
236 	{
237 		close(err[1]);
238 		if (pid != -1 && read(err[0], &m, sizeof(m)) == sizeof(m) && m)
239 		{
240 			while (waitpid(pid, NiL, 0) == -1 && errno == EINTR);
241 			rid = pid = -1;
242 			n = m;
243 		}
244 		close(err[0]);
245 	}
246 #endif
247 	if (pid != -1 && pgid > 0)
248 	{
249 		/*
250 		 * parent and child are in a race here
251 		 */
252 
253 		if (pgid == 1)
254 			pgid = pid;
255 		if (setpgid(pid, pgid) < 0 && pid != pgid && errno == EPERM)
256 			setpgid(pid, pid);
257 	}
258 	errno = n;
259 	return rid;
260 #else
261 	errno = ENOSYS;
262 	return -1;
263 #endif
264 }
265 
266 #endif
267 
268 #endif
269 
270 #endif
271 
272 #endif
273