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