xref: /onnv-gate/usr/src/lib/libpkg/common/pkgexecv.c (revision 9781:ccf49524d5dc)
1*9781SMoriah.Waterland@Sun.COM /*
2*9781SMoriah.Waterland@Sun.COM  * CDDL HEADER START
3*9781SMoriah.Waterland@Sun.COM  *
4*9781SMoriah.Waterland@Sun.COM  * The contents of this file are subject to the terms of the
5*9781SMoriah.Waterland@Sun.COM  * Common Development and Distribution License (the "License").
6*9781SMoriah.Waterland@Sun.COM  * You may not use this file except in compliance with the License.
7*9781SMoriah.Waterland@Sun.COM  *
8*9781SMoriah.Waterland@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*9781SMoriah.Waterland@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*9781SMoriah.Waterland@Sun.COM  * See the License for the specific language governing permissions
11*9781SMoriah.Waterland@Sun.COM  * and limitations under the License.
12*9781SMoriah.Waterland@Sun.COM  *
13*9781SMoriah.Waterland@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*9781SMoriah.Waterland@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*9781SMoriah.Waterland@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*9781SMoriah.Waterland@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*9781SMoriah.Waterland@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*9781SMoriah.Waterland@Sun.COM  *
19*9781SMoriah.Waterland@Sun.COM  * CDDL HEADER END
20*9781SMoriah.Waterland@Sun.COM  */
21*9781SMoriah.Waterland@Sun.COM 
22*9781SMoriah.Waterland@Sun.COM /*
23*9781SMoriah.Waterland@Sun.COM  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24*9781SMoriah.Waterland@Sun.COM  * Use is subject to license terms.
25*9781SMoriah.Waterland@Sun.COM  */
26*9781SMoriah.Waterland@Sun.COM 
27*9781SMoriah.Waterland@Sun.COM /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28*9781SMoriah.Waterland@Sun.COM /* All Rights Reserved */
29*9781SMoriah.Waterland@Sun.COM 
30*9781SMoriah.Waterland@Sun.COM 
31*9781SMoriah.Waterland@Sun.COM #include <stdio.h>
32*9781SMoriah.Waterland@Sun.COM #include <errno.h>
33*9781SMoriah.Waterland@Sun.COM #include <string.h>
34*9781SMoriah.Waterland@Sun.COM #include <stdlib.h>
35*9781SMoriah.Waterland@Sun.COM #include <unistd.h>
36*9781SMoriah.Waterland@Sun.COM #include <signal.h>
37*9781SMoriah.Waterland@Sun.COM #include <wait.h>
38*9781SMoriah.Waterland@Sun.COM #include <sys/types.h>
39*9781SMoriah.Waterland@Sun.COM #include <sys/stat.h>
40*9781SMoriah.Waterland@Sun.COM #include <fcntl.h>
41*9781SMoriah.Waterland@Sun.COM #include <pwd.h>
42*9781SMoriah.Waterland@Sun.COM #include <grp.h>
43*9781SMoriah.Waterland@Sun.COM #include "pkglib.h"
44*9781SMoriah.Waterland@Sun.COM #include "pkglibmsgs.h"
45*9781SMoriah.Waterland@Sun.COM #include "pkglocale.h"
46*9781SMoriah.Waterland@Sun.COM 
47*9781SMoriah.Waterland@Sun.COM /* global environment inherited by this process */
48*9781SMoriah.Waterland@Sun.COM extern char	**environ;
49*9781SMoriah.Waterland@Sun.COM 
50*9781SMoriah.Waterland@Sun.COM /* dstream.c */
51*9781SMoriah.Waterland@Sun.COM extern int	ds_curpartcnt;
52*9781SMoriah.Waterland@Sun.COM extern int	ds_close(int pkgendflg);
53*9781SMoriah.Waterland@Sun.COM 
54*9781SMoriah.Waterland@Sun.COM /*
55*9781SMoriah.Waterland@Sun.COM  * global internal (private) variables
56*9781SMoriah.Waterland@Sun.COM  */
57*9781SMoriah.Waterland@Sun.COM 
58*9781SMoriah.Waterland@Sun.COM /* received signal count - bumped with hooked signals are caught */
59*9781SMoriah.Waterland@Sun.COM 
60*9781SMoriah.Waterland@Sun.COM static int	sig_received = 0;
61*9781SMoriah.Waterland@Sun.COM 
62*9781SMoriah.Waterland@Sun.COM /*
63*9781SMoriah.Waterland@Sun.COM  * Name:	sig_trap
64*9781SMoriah.Waterland@Sun.COM  * Description:	hooked up to signal counts number of signals received
65*9781SMoriah.Waterland@Sun.COM  * Arguments:	a_signo - [RO, *RO] - (int)
66*9781SMoriah.Waterland@Sun.COM  *			Integer representing the signal received; see signal(3c)
67*9781SMoriah.Waterland@Sun.COM  * Returns:	<void>
68*9781SMoriah.Waterland@Sun.COM  */
69*9781SMoriah.Waterland@Sun.COM 
70*9781SMoriah.Waterland@Sun.COM static void
sig_trap(int a_signo)71*9781SMoriah.Waterland@Sun.COM sig_trap(int a_signo)
72*9781SMoriah.Waterland@Sun.COM {
73*9781SMoriah.Waterland@Sun.COM 	sig_received++;
74*9781SMoriah.Waterland@Sun.COM }
75*9781SMoriah.Waterland@Sun.COM 
76*9781SMoriah.Waterland@Sun.COM /*
77*9781SMoriah.Waterland@Sun.COM  * Name:	pkgexecv
78*9781SMoriah.Waterland@Sun.COM  * Description:	Asynchronously execute a package command in a separate process
79*9781SMoriah.Waterland@Sun.COM  *		and return results - the subprocess MUST arm it's own SIGINT
80*9781SMoriah.Waterland@Sun.COM  *		and SIGHUP signals and must return a standard package command
81*9781SMoriah.Waterland@Sun.COM  *		exit code (see returns below)
82*9781SMoriah.Waterland@Sun.COM  *		Only another package command (such as pkginstall, pkgremove,
83*9781SMoriah.Waterland@Sun.COM  *		etc.) may be called via this interface. No files are closed
84*9781SMoriah.Waterland@Sun.COM  *		because open files are passed across to certain commands using
85*9781SMoriah.Waterland@Sun.COM  *		either implicit agreements between the two (yuk!) or by using
86*9781SMoriah.Waterland@Sun.COM  *		the '-p' option which passes a string of digits, some of which
87*9781SMoriah.Waterland@Sun.COM  *		represent open file descriptors passed through this interface!
88*9781SMoriah.Waterland@Sun.COM  * Arguments:	filein - [RO, *RO] - (char *)
89*9781SMoriah.Waterland@Sun.COM  *			Pointer to string representing the name of the file to
90*9781SMoriah.Waterland@Sun.COM  *			use for the package commands's stdin
91*9781SMoriah.Waterland@Sun.COM  *			== (char *)NULL or == "" - the current stdin
92*9781SMoriah.Waterland@Sun.COM  *			is used for the new package command process
93*9781SMoriah.Waterland@Sun.COM  *		fileout - [RO, *RO] - (char *)
94*9781SMoriah.Waterland@Sun.COM  *			Pointer to string representing the name of the file to
95*9781SMoriah.Waterland@Sun.COM  *			use for the package commands's stdout and stderr
96*9781SMoriah.Waterland@Sun.COM  *			== (char *)NULL or == "" - the current stdout/stderr
97*9781SMoriah.Waterland@Sun.COM  *			is used for the new package command process
98*9781SMoriah.Waterland@Sun.COM  *		uname - [RO, *RO] - (char *)
99*9781SMoriah.Waterland@Sun.COM  *			Pointer to string representing the user name to execute
100*9781SMoriah.Waterland@Sun.COM  *			the package command as - the user name is looked up
101*9781SMoriah.Waterland@Sun.COM  *			using the ncgrpw:cpwnam() interface
102*9781SMoriah.Waterland@Sun.COM  *			== (char *)NULL or == "" - the user name of the current
103*9781SMoriah.Waterland@Sun.COM  *			process is used for the new package command process
104*9781SMoriah.Waterland@Sun.COM  *		gname - [RO, *RO] - (char *)
105*9781SMoriah.Waterland@Sun.COM  *			Pointer to string representing the group name to execute
106*9781SMoriah.Waterland@Sun.COM  *			the package command as - the group name is looked up
107*9781SMoriah.Waterland@Sun.COM  *			using the ncgrpw:cgrnam() interface
108*9781SMoriah.Waterland@Sun.COM  *			== (char *)NULL or == "" - the group name of the current
109*9781SMoriah.Waterland@Sun.COM  *			process is used for the new package command process
110*9781SMoriah.Waterland@Sun.COM  *		arg - [RO, *RO] - (char **)
111*9781SMoriah.Waterland@Sun.COM  *			Pointer to array of character pointers representing the
112*9781SMoriah.Waterland@Sun.COM  *			arguments to pass to the package command - the array is
113*9781SMoriah.Waterland@Sun.COM  *			terminated with a pointer to (char *)NULL
114*9781SMoriah.Waterland@Sun.COM  * Returns:	int
115*9781SMoriah.Waterland@Sun.COM  *			== 99 - exec() of package command failed
116*9781SMoriah.Waterland@Sun.COM  *			== -1 - fork failed or other fatal error during
117*9781SMoriah.Waterland@Sun.COM  *				execution of the package command
118*9781SMoriah.Waterland@Sun.COM  *			otherwise - exit code from package command:
119*9781SMoriah.Waterland@Sun.COM  *			0 - successful
120*9781SMoriah.Waterland@Sun.COM  *			1 - package operation failed (fatal error)
121*9781SMoriah.Waterland@Sun.COM  *			2 - non-fatal error (warning)
122*9781SMoriah.Waterland@Sun.COM  *			3 - operation interrupted (including SIGINT/SIGHUP)
123*9781SMoriah.Waterland@Sun.COM  *			4 - admin settings prevented operation
124*9781SMoriah.Waterland@Sun.COM  *			5 - administration required and -n was specified
125*9781SMoriah.Waterland@Sun.COM  *			IN addition:
126*9781SMoriah.Waterland@Sun.COM  *			10 is added to the return code if reboot after the
127*9781SMoriah.Waterland@Sun.COM  *				installation of all packages is required
128*9781SMoriah.Waterland@Sun.COM  *			20 is added to the return code if immediate reboot
129*9781SMoriah.Waterland@Sun.COM  *				after installation of this package is required
130*9781SMoriah.Waterland@Sun.COM  */
131*9781SMoriah.Waterland@Sun.COM 
132*9781SMoriah.Waterland@Sun.COM int
pkgexecv(char * filein,char * fileout,char * uname,char * gname,char * arg[])133*9781SMoriah.Waterland@Sun.COM pkgexecv(char *filein, char *fileout, char *uname, char *gname, char *arg[])
134*9781SMoriah.Waterland@Sun.COM {
135*9781SMoriah.Waterland@Sun.COM 	int			exit_no;
136*9781SMoriah.Waterland@Sun.COM 	int			n;
137*9781SMoriah.Waterland@Sun.COM 	int			status;
138*9781SMoriah.Waterland@Sun.COM 	pid_t			pid;
139*9781SMoriah.Waterland@Sun.COM 	pid_t			waitstat;
140*9781SMoriah.Waterland@Sun.COM 	struct group		*grp;
141*9781SMoriah.Waterland@Sun.COM 	struct passwd		*pwp;
142*9781SMoriah.Waterland@Sun.COM 	struct sigaction	nact;
143*9781SMoriah.Waterland@Sun.COM 	struct sigaction	oact;
144*9781SMoriah.Waterland@Sun.COM 	void			(*funcSighup)();
145*9781SMoriah.Waterland@Sun.COM 	void			(*funcSigint)();
146*9781SMoriah.Waterland@Sun.COM 
147*9781SMoriah.Waterland@Sun.COM 	/* flush standard i/o before creating new process */
148*9781SMoriah.Waterland@Sun.COM 
149*9781SMoriah.Waterland@Sun.COM 	(void) fflush(stdout);
150*9781SMoriah.Waterland@Sun.COM 	(void) fflush(stderr);
151*9781SMoriah.Waterland@Sun.COM 
152*9781SMoriah.Waterland@Sun.COM 	/*
153*9781SMoriah.Waterland@Sun.COM 	 * hold SIGINT/SIGHUP signals and reset signal received counter;
154*9781SMoriah.Waterland@Sun.COM 	 * after the vfork() the parent and child need to setup their respective
155*9781SMoriah.Waterland@Sun.COM 	 * interrupt handling and release the hold on the signals
156*9781SMoriah.Waterland@Sun.COM 	 */
157*9781SMoriah.Waterland@Sun.COM 
158*9781SMoriah.Waterland@Sun.COM 	(void) sighold(SIGINT);
159*9781SMoriah.Waterland@Sun.COM 	(void) sighold(SIGHUP);
160*9781SMoriah.Waterland@Sun.COM 
161*9781SMoriah.Waterland@Sun.COM 	sig_received = 0;
162*9781SMoriah.Waterland@Sun.COM 
163*9781SMoriah.Waterland@Sun.COM 	/*
164*9781SMoriah.Waterland@Sun.COM 	 * create new process to execute command in;
165*9781SMoriah.Waterland@Sun.COM 	 * vfork() is being used to avoid duplicating the parents
166*9781SMoriah.Waterland@Sun.COM 	 * memory space - this means that the child process may
167*9781SMoriah.Waterland@Sun.COM 	 * not modify any of the parents memory including the
168*9781SMoriah.Waterland@Sun.COM 	 * standard i/o descriptors - all the child can do is
169*9781SMoriah.Waterland@Sun.COM 	 * adjust interrupts and open files as a prelude to a
170*9781SMoriah.Waterland@Sun.COM 	 * call to exec().
171*9781SMoriah.Waterland@Sun.COM 	 */
172*9781SMoriah.Waterland@Sun.COM 
173*9781SMoriah.Waterland@Sun.COM 	pid = vfork();
174*9781SMoriah.Waterland@Sun.COM 
175*9781SMoriah.Waterland@Sun.COM 	if (pid < 0) {
176*9781SMoriah.Waterland@Sun.COM 		/*
177*9781SMoriah.Waterland@Sun.COM 		 * *************************************************************
178*9781SMoriah.Waterland@Sun.COM 		 * fork failed!
179*9781SMoriah.Waterland@Sun.COM 		 * *************************************************************
180*9781SMoriah.Waterland@Sun.COM 		 */
181*9781SMoriah.Waterland@Sun.COM 
182*9781SMoriah.Waterland@Sun.COM 		progerr(pkg_gt(ERR_FORK_FAILED), errno, strerror(errno));
183*9781SMoriah.Waterland@Sun.COM 
184*9781SMoriah.Waterland@Sun.COM 		/* release hold on signals */
185*9781SMoriah.Waterland@Sun.COM 
186*9781SMoriah.Waterland@Sun.COM 		(void) sigrelse(SIGHUP);
187*9781SMoriah.Waterland@Sun.COM 		(void) sigrelse(SIGINT);
188*9781SMoriah.Waterland@Sun.COM 
189*9781SMoriah.Waterland@Sun.COM 		return (-1);
190*9781SMoriah.Waterland@Sun.COM 	}
191*9781SMoriah.Waterland@Sun.COM 
192*9781SMoriah.Waterland@Sun.COM 	if (pid > 0) {
193*9781SMoriah.Waterland@Sun.COM 		/*
194*9781SMoriah.Waterland@Sun.COM 		 * *************************************************************
195*9781SMoriah.Waterland@Sun.COM 		 * This is the forking (parent) process
196*9781SMoriah.Waterland@Sun.COM 		 * *************************************************************
197*9781SMoriah.Waterland@Sun.COM 		 */
198*9781SMoriah.Waterland@Sun.COM 
199*9781SMoriah.Waterland@Sun.COM 		/* close datastream if any portion read */
200*9781SMoriah.Waterland@Sun.COM 
201*9781SMoriah.Waterland@Sun.COM 		if (ds_curpartcnt >= 0) {
202*9781SMoriah.Waterland@Sun.COM 			if (ds_close(0) != 0) {
203*9781SMoriah.Waterland@Sun.COM 				/* kill child process */
204*9781SMoriah.Waterland@Sun.COM 
205*9781SMoriah.Waterland@Sun.COM 				(void) sigsend(P_PID, pid, SIGKILL);
206*9781SMoriah.Waterland@Sun.COM 
207*9781SMoriah.Waterland@Sun.COM 				/* release hold on signals */
208*9781SMoriah.Waterland@Sun.COM 
209*9781SMoriah.Waterland@Sun.COM 				(void) sigrelse(SIGHUP);
210*9781SMoriah.Waterland@Sun.COM 				(void) sigrelse(SIGINT);
211*9781SMoriah.Waterland@Sun.COM 
212*9781SMoriah.Waterland@Sun.COM 				return (-1);
213*9781SMoriah.Waterland@Sun.COM 			}
214*9781SMoriah.Waterland@Sun.COM 		}
215*9781SMoriah.Waterland@Sun.COM 
216*9781SMoriah.Waterland@Sun.COM 		/*
217*9781SMoriah.Waterland@Sun.COM 		 * setup signal handlers for SIGINT and SIGHUP and release hold
218*9781SMoriah.Waterland@Sun.COM 		 */
219*9781SMoriah.Waterland@Sun.COM 
220*9781SMoriah.Waterland@Sun.COM 		/* hook SIGINT to sig_trap() */
221*9781SMoriah.Waterland@Sun.COM 
222*9781SMoriah.Waterland@Sun.COM 		nact.sa_handler = sig_trap;
223*9781SMoriah.Waterland@Sun.COM 		nact.sa_flags = SA_RESTART;
224*9781SMoriah.Waterland@Sun.COM 		(void) sigemptyset(&nact.sa_mask);
225*9781SMoriah.Waterland@Sun.COM 
226*9781SMoriah.Waterland@Sun.COM 		if (sigaction(SIGINT, &nact, &oact) < 0) {
227*9781SMoriah.Waterland@Sun.COM 			funcSigint = SIG_DFL;
228*9781SMoriah.Waterland@Sun.COM 		} else {
229*9781SMoriah.Waterland@Sun.COM 			funcSigint = oact.sa_handler;
230*9781SMoriah.Waterland@Sun.COM 		}
231*9781SMoriah.Waterland@Sun.COM 
232*9781SMoriah.Waterland@Sun.COM 		/* hook SIGHUP to sig_trap() */
233*9781SMoriah.Waterland@Sun.COM 
234*9781SMoriah.Waterland@Sun.COM 		nact.sa_handler = sig_trap;
235*9781SMoriah.Waterland@Sun.COM 		nact.sa_flags = SA_RESTART;
236*9781SMoriah.Waterland@Sun.COM 		(void) sigemptyset(&nact.sa_mask);
237*9781SMoriah.Waterland@Sun.COM 
238*9781SMoriah.Waterland@Sun.COM 		if (sigaction(SIGHUP, &nact, &oact) < 0) {
239*9781SMoriah.Waterland@Sun.COM 			funcSighup = SIG_DFL;
240*9781SMoriah.Waterland@Sun.COM 		} else {
241*9781SMoriah.Waterland@Sun.COM 			funcSighup = oact.sa_handler;
242*9781SMoriah.Waterland@Sun.COM 		}
243*9781SMoriah.Waterland@Sun.COM 
244*9781SMoriah.Waterland@Sun.COM 		/* release hold on signals */
245*9781SMoriah.Waterland@Sun.COM 
246*9781SMoriah.Waterland@Sun.COM 		(void) sigrelse(SIGHUP);
247*9781SMoriah.Waterland@Sun.COM 		(void) sigrelse(SIGINT);
248*9781SMoriah.Waterland@Sun.COM 
249*9781SMoriah.Waterland@Sun.COM 		/*
250*9781SMoriah.Waterland@Sun.COM 		 * wait for the process to exit, reap child exit status
251*9781SMoriah.Waterland@Sun.COM 		 */
252*9781SMoriah.Waterland@Sun.COM 
253*9781SMoriah.Waterland@Sun.COM 		for (;;) {
254*9781SMoriah.Waterland@Sun.COM 			status = 0;
255*9781SMoriah.Waterland@Sun.COM 			waitstat = waitpid(pid, (int *)&status, 0);
256*9781SMoriah.Waterland@Sun.COM 			if (waitstat < 0) {
257*9781SMoriah.Waterland@Sun.COM 				/* waitpid returned error */
258*9781SMoriah.Waterland@Sun.COM 				if (errno == EAGAIN) {
259*9781SMoriah.Waterland@Sun.COM 					/* try again */
260*9781SMoriah.Waterland@Sun.COM 					continue;
261*9781SMoriah.Waterland@Sun.COM 				}
262*9781SMoriah.Waterland@Sun.COM 				if (errno == EINTR) {
263*9781SMoriah.Waterland@Sun.COM 					continue;
264*9781SMoriah.Waterland@Sun.COM 				}
265*9781SMoriah.Waterland@Sun.COM 				/* error from waitpid: bail */
266*9781SMoriah.Waterland@Sun.COM 				break;
267*9781SMoriah.Waterland@Sun.COM 			} else if (waitstat == pid) {
268*9781SMoriah.Waterland@Sun.COM 				/* child exit status available */
269*9781SMoriah.Waterland@Sun.COM 				break;
270*9781SMoriah.Waterland@Sun.COM 			}
271*9781SMoriah.Waterland@Sun.COM 		}
272*9781SMoriah.Waterland@Sun.COM 
273*9781SMoriah.Waterland@Sun.COM 		/*
274*9781SMoriah.Waterland@Sun.COM 		 * reset signal handlers
275*9781SMoriah.Waterland@Sun.COM 		 */
276*9781SMoriah.Waterland@Sun.COM 
277*9781SMoriah.Waterland@Sun.COM 		/* reset SIGINT */
278*9781SMoriah.Waterland@Sun.COM 
279*9781SMoriah.Waterland@Sun.COM 		nact.sa_handler = funcSigint;
280*9781SMoriah.Waterland@Sun.COM 		nact.sa_flags = SA_RESTART;
281*9781SMoriah.Waterland@Sun.COM 		(void) sigemptyset(&nact.sa_mask);
282*9781SMoriah.Waterland@Sun.COM 
283*9781SMoriah.Waterland@Sun.COM 		(void) sigaction(SIGINT, &nact, (struct sigaction *)NULL);
284*9781SMoriah.Waterland@Sun.COM 
285*9781SMoriah.Waterland@Sun.COM 		/* reset SIGHUP */
286*9781SMoriah.Waterland@Sun.COM 
287*9781SMoriah.Waterland@Sun.COM 		nact.sa_handler = funcSighup;
288*9781SMoriah.Waterland@Sun.COM 		nact.sa_flags = SA_RESTART;
289*9781SMoriah.Waterland@Sun.COM 		(void) sigemptyset(&nact.sa_mask);
290*9781SMoriah.Waterland@Sun.COM 
291*9781SMoriah.Waterland@Sun.COM 		(void) sigaction(SIGHUP, &nact, (struct sigaction *)NULL);
292*9781SMoriah.Waterland@Sun.COM 
293*9781SMoriah.Waterland@Sun.COM 		/* error if child process does not match */
294*9781SMoriah.Waterland@Sun.COM 
295*9781SMoriah.Waterland@Sun.COM 		if (waitstat != pid) {
296*9781SMoriah.Waterland@Sun.COM 			progerr(pkg_gt(ERR_WAIT_FAILED), pid, waitstat, status,
297*9781SMoriah.Waterland@Sun.COM 				errno, strerror(errno));
298*9781SMoriah.Waterland@Sun.COM 			return (-1);
299*9781SMoriah.Waterland@Sun.COM 		}
300*9781SMoriah.Waterland@Sun.COM 
301*9781SMoriah.Waterland@Sun.COM 		/*
302*9781SMoriah.Waterland@Sun.COM 		 * determine final exit code:
303*9781SMoriah.Waterland@Sun.COM 		 * - if signal received, then return interrupted (3)
304*9781SMoriah.Waterland@Sun.COM 		 * - if child exit status is available, return exit child status
305*9781SMoriah.Waterland@Sun.COM 		 * - otherwise return error (-1)
306*9781SMoriah.Waterland@Sun.COM 		 */
307*9781SMoriah.Waterland@Sun.COM 
308*9781SMoriah.Waterland@Sun.COM 		if (sig_received != 0) {
309*9781SMoriah.Waterland@Sun.COM 			exit_no = 3;	/* interrupted */
310*9781SMoriah.Waterland@Sun.COM 		} else if (WIFEXITED(status)) {
311*9781SMoriah.Waterland@Sun.COM 			exit_no = WEXITSTATUS(status);
312*9781SMoriah.Waterland@Sun.COM 		} else {
313*9781SMoriah.Waterland@Sun.COM 			exit_no = -1;	/* exec() or other process error */
314*9781SMoriah.Waterland@Sun.COM 		}
315*9781SMoriah.Waterland@Sun.COM 
316*9781SMoriah.Waterland@Sun.COM 		return (exit_no);
317*9781SMoriah.Waterland@Sun.COM 	}
318*9781SMoriah.Waterland@Sun.COM 
319*9781SMoriah.Waterland@Sun.COM 	/*
320*9781SMoriah.Waterland@Sun.COM 	 * *********************************************************************
321*9781SMoriah.Waterland@Sun.COM 	 * This is the forked (child) process
322*9781SMoriah.Waterland@Sun.COM 	 * *********************************************************************
323*9781SMoriah.Waterland@Sun.COM 	 */
324*9781SMoriah.Waterland@Sun.COM 
325*9781SMoriah.Waterland@Sun.COM 	/* reset all signals to default */
326*9781SMoriah.Waterland@Sun.COM 
327*9781SMoriah.Waterland@Sun.COM 	for (n = 0; n < NSIG; n++) {
328*9781SMoriah.Waterland@Sun.COM 		(void) sigset(n, SIG_DFL);
329*9781SMoriah.Waterland@Sun.COM 	}
330*9781SMoriah.Waterland@Sun.COM 
331*9781SMoriah.Waterland@Sun.COM 	/* release hold on signals held by parent before fork() */
332*9781SMoriah.Waterland@Sun.COM 
333*9781SMoriah.Waterland@Sun.COM 	(void) sigrelse(SIGHUP);
334*9781SMoriah.Waterland@Sun.COM 	(void) sigrelse(SIGINT);
335*9781SMoriah.Waterland@Sun.COM 
336*9781SMoriah.Waterland@Sun.COM 	/*
337*9781SMoriah.Waterland@Sun.COM 	 * The caller wants to have stdin connected to filein.
338*9781SMoriah.Waterland@Sun.COM 	 */
339*9781SMoriah.Waterland@Sun.COM 
340*9781SMoriah.Waterland@Sun.COM 	if (filein && *filein) {
341*9781SMoriah.Waterland@Sun.COM 		/*
342*9781SMoriah.Waterland@Sun.COM 		 * If input is supposed to be connected to /dev/tty
343*9781SMoriah.Waterland@Sun.COM 		 */
344*9781SMoriah.Waterland@Sun.COM 		if (strncmp(filein, "/dev/tty", 8) == 0) {
345*9781SMoriah.Waterland@Sun.COM 			/*
346*9781SMoriah.Waterland@Sun.COM 			 * If stdin is connected to a tty device.
347*9781SMoriah.Waterland@Sun.COM 			 */
348*9781SMoriah.Waterland@Sun.COM 			if (isatty(STDIN_FILENO)) {
349*9781SMoriah.Waterland@Sun.COM 				/*
350*9781SMoriah.Waterland@Sun.COM 				 * Reopen it to /dev/tty.
351*9781SMoriah.Waterland@Sun.COM 				 */
352*9781SMoriah.Waterland@Sun.COM 				n = open(filein, O_RDONLY);
353*9781SMoriah.Waterland@Sun.COM 				if (n >= 0) {
354*9781SMoriah.Waterland@Sun.COM 					(void) dup2(n, STDIN_FILENO);
355*9781SMoriah.Waterland@Sun.COM 				}
356*9781SMoriah.Waterland@Sun.COM 			}
357*9781SMoriah.Waterland@Sun.COM 		} else {
358*9781SMoriah.Waterland@Sun.COM 			/*
359*9781SMoriah.Waterland@Sun.COM 			 * If we did not want to be connected to /dev/tty, we
360*9781SMoriah.Waterland@Sun.COM 			 * connect input to the requested file no questions.
361*9781SMoriah.Waterland@Sun.COM 			 */
362*9781SMoriah.Waterland@Sun.COM 			n = open(filein, O_RDONLY);
363*9781SMoriah.Waterland@Sun.COM 			if (n >= 0) {
364*9781SMoriah.Waterland@Sun.COM 				(void) dup2(n, STDIN_FILENO);
365*9781SMoriah.Waterland@Sun.COM 			}
366*9781SMoriah.Waterland@Sun.COM 		}
367*9781SMoriah.Waterland@Sun.COM 	}
368*9781SMoriah.Waterland@Sun.COM 
369*9781SMoriah.Waterland@Sun.COM 	/*
370*9781SMoriah.Waterland@Sun.COM 	 * The caller wants to have stdout and stderr connected to fileout.
371*9781SMoriah.Waterland@Sun.COM 	 * If "fileout" is "/dev/tty" then reconnect stdout to "/dev/tty"
372*9781SMoriah.Waterland@Sun.COM 	 * only if /dev/tty is not already associated with "a tty".
373*9781SMoriah.Waterland@Sun.COM 	 */
374*9781SMoriah.Waterland@Sun.COM 
375*9781SMoriah.Waterland@Sun.COM 	if (fileout && *fileout) {
376*9781SMoriah.Waterland@Sun.COM 		/*
377*9781SMoriah.Waterland@Sun.COM 		 * If output is supposed to be connected to /dev/tty
378*9781SMoriah.Waterland@Sun.COM 		 */
379*9781SMoriah.Waterland@Sun.COM 		if (strncmp(fileout, "/dev/tty", 8) == 0) {
380*9781SMoriah.Waterland@Sun.COM 			/*
381*9781SMoriah.Waterland@Sun.COM 			 * If stdout is connected to a tty device.
382*9781SMoriah.Waterland@Sun.COM 			 */
383*9781SMoriah.Waterland@Sun.COM 			if (isatty(STDOUT_FILENO)) {
384*9781SMoriah.Waterland@Sun.COM 				/*
385*9781SMoriah.Waterland@Sun.COM 				 * Reopen it to /dev/tty if /dev/tty available.
386*9781SMoriah.Waterland@Sun.COM 				 */
387*9781SMoriah.Waterland@Sun.COM 				n = open(fileout, O_WRONLY);
388*9781SMoriah.Waterland@Sun.COM 				if (n >= 0) {
389*9781SMoriah.Waterland@Sun.COM 					/*
390*9781SMoriah.Waterland@Sun.COM 					 * /dev/tty is available - close the
391*9781SMoriah.Waterland@Sun.COM 					 * current standard output stream, and
392*9781SMoriah.Waterland@Sun.COM 					 * reopen it on /dev/tty
393*9781SMoriah.Waterland@Sun.COM 					 */
394*9781SMoriah.Waterland@Sun.COM 					(void) dup2(n, STDOUT_FILENO);
395*9781SMoriah.Waterland@Sun.COM 				}
396*9781SMoriah.Waterland@Sun.COM 			}
397*9781SMoriah.Waterland@Sun.COM 			/*
398*9781SMoriah.Waterland@Sun.COM 			 * not connected to tty device - probably redirect to
399*9781SMoriah.Waterland@Sun.COM 			 * file - preserve existing output device
400*9781SMoriah.Waterland@Sun.COM 			 */
401*9781SMoriah.Waterland@Sun.COM 		} else {
402*9781SMoriah.Waterland@Sun.COM 			/*
403*9781SMoriah.Waterland@Sun.COM 			 * If we did not want to be connected to /dev/tty, we
404*9781SMoriah.Waterland@Sun.COM 			 * connect output to the requested file no questions.
405*9781SMoriah.Waterland@Sun.COM 			 */
406*9781SMoriah.Waterland@Sun.COM 			/* LINTED O_CREAT without O_EXCL specified in call to */
407*9781SMoriah.Waterland@Sun.COM 			n = open(fileout, O_WRONLY|O_CREAT|O_APPEND, 0666);
408*9781SMoriah.Waterland@Sun.COM 			if (n >= 0) {
409*9781SMoriah.Waterland@Sun.COM 				(void) dup2(n, STDOUT_FILENO);
410*9781SMoriah.Waterland@Sun.COM 			}
411*9781SMoriah.Waterland@Sun.COM 		}
412*9781SMoriah.Waterland@Sun.COM 
413*9781SMoriah.Waterland@Sun.COM 		/*
414*9781SMoriah.Waterland@Sun.COM 		 * Dup stderr from stdout.
415*9781SMoriah.Waterland@Sun.COM 		 */
416*9781SMoriah.Waterland@Sun.COM 
417*9781SMoriah.Waterland@Sun.COM 		(void) dup2(STDOUT_FILENO, STDERR_FILENO);
418*9781SMoriah.Waterland@Sun.COM 	}
419*9781SMoriah.Waterland@Sun.COM 
420*9781SMoriah.Waterland@Sun.COM 	/*
421*9781SMoriah.Waterland@Sun.COM 	 * do NOT close all file descriptors except stdio
422*9781SMoriah.Waterland@Sun.COM 	 * file descriptors are passed in to some subcommands
423*9781SMoriah.Waterland@Sun.COM 	 * (see dstream:ds_getinfo() and dstream:ds_putinfo())
424*9781SMoriah.Waterland@Sun.COM 	 */
425*9781SMoriah.Waterland@Sun.COM 
426*9781SMoriah.Waterland@Sun.COM 	/* set group/user i.d. if requested */
427*9781SMoriah.Waterland@Sun.COM 
428*9781SMoriah.Waterland@Sun.COM 	if (gname && *gname && (grp = cgrnam(gname)) != NULL) {
429*9781SMoriah.Waterland@Sun.COM 		if (setgid(grp->gr_gid) == -1) {
430*9781SMoriah.Waterland@Sun.COM 			progerr(pkg_gt(ERR_SETGID), grp->gr_gid);
431*9781SMoriah.Waterland@Sun.COM 		}
432*9781SMoriah.Waterland@Sun.COM 	}
433*9781SMoriah.Waterland@Sun.COM 	if (uname && *uname && (pwp = cpwnam(uname)) != NULL) {
434*9781SMoriah.Waterland@Sun.COM 		if (setuid(pwp->pw_uid) == -1) {
435*9781SMoriah.Waterland@Sun.COM 			progerr(pkg_gt(ERR_SETUID), pwp->pw_uid);
436*9781SMoriah.Waterland@Sun.COM 		}
437*9781SMoriah.Waterland@Sun.COM 	}
438*9781SMoriah.Waterland@Sun.COM 
439*9781SMoriah.Waterland@Sun.COM 	/* execute target executable */
440*9781SMoriah.Waterland@Sun.COM 
441*9781SMoriah.Waterland@Sun.COM 	(void) execve(arg[0], arg, environ);
442*9781SMoriah.Waterland@Sun.COM 	progerr(pkg_gt(ERR_EX_FAIL), arg[0], errno);
443*9781SMoriah.Waterland@Sun.COM 	_exit(99);
444*9781SMoriah.Waterland@Sun.COM 	/*NOTREACHED*/
445*9781SMoriah.Waterland@Sun.COM }
446