15c51f124SMoriah Waterland /*
25c51f124SMoriah Waterland  * CDDL HEADER START
35c51f124SMoriah Waterland  *
45c51f124SMoriah Waterland  * The contents of this file are subject to the terms of the
55c51f124SMoriah Waterland  * Common Development and Distribution License (the "License").
65c51f124SMoriah Waterland  * You may not use this file except in compliance with the License.
75c51f124SMoriah Waterland  *
85c51f124SMoriah Waterland  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95c51f124SMoriah Waterland  * or http://www.opensolaris.org/os/licensing.
105c51f124SMoriah Waterland  * See the License for the specific language governing permissions
115c51f124SMoriah Waterland  * and limitations under the License.
125c51f124SMoriah Waterland  *
135c51f124SMoriah Waterland  * When distributing Covered Code, include this CDDL HEADER in each
145c51f124SMoriah Waterland  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155c51f124SMoriah Waterland  * If applicable, add the following below this CDDL HEADER, with the
165c51f124SMoriah Waterland  * fields enclosed by brackets "[]" replaced with your own identifying
175c51f124SMoriah Waterland  * information: Portions Copyright [yyyy] [name of copyright owner]
185c51f124SMoriah Waterland  *
195c51f124SMoriah Waterland  * CDDL HEADER END
205c51f124SMoriah Waterland  */
215c51f124SMoriah Waterland 
225c51f124SMoriah Waterland /*
235c51f124SMoriah Waterland  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
245c51f124SMoriah Waterland  * Use is subject to license terms.
255c51f124SMoriah Waterland  */
265c51f124SMoriah Waterland 
275c51f124SMoriah Waterland /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
285c51f124SMoriah Waterland /* All Rights Reserved */
295c51f124SMoriah Waterland 
305c51f124SMoriah Waterland 
315c51f124SMoriah Waterland #include <stdio.h>
325c51f124SMoriah Waterland #include <errno.h>
335c51f124SMoriah Waterland #include <string.h>
345c51f124SMoriah Waterland #include <stdlib.h>
355c51f124SMoriah Waterland #include <unistd.h>
365c51f124SMoriah Waterland #include <signal.h>
375c51f124SMoriah Waterland #include <wait.h>
385c51f124SMoriah Waterland #include <sys/types.h>
395c51f124SMoriah Waterland #include <sys/stat.h>
405c51f124SMoriah Waterland #include <fcntl.h>
415c51f124SMoriah Waterland #include <pwd.h>
425c51f124SMoriah Waterland #include <grp.h>
43*4656d474SGarrett D'Amore #include <note.h>
445c51f124SMoriah Waterland #include "pkglib.h"
455c51f124SMoriah Waterland #include "pkglibmsgs.h"
465c51f124SMoriah Waterland #include "pkglocale.h"
475c51f124SMoriah Waterland 
485c51f124SMoriah Waterland /* global environment inherited by this process */
495c51f124SMoriah Waterland extern char	**environ;
505c51f124SMoriah Waterland 
515c51f124SMoriah Waterland /* dstream.c */
525c51f124SMoriah Waterland extern int	ds_curpartcnt;
535c51f124SMoriah Waterland extern int	ds_close(int pkgendflg);
545c51f124SMoriah Waterland 
555c51f124SMoriah Waterland /*
565c51f124SMoriah Waterland  * global internal (private) variables
575c51f124SMoriah Waterland  */
585c51f124SMoriah Waterland 
595c51f124SMoriah Waterland /* received signal count - bumped with hooked signals are caught */
605c51f124SMoriah Waterland 
615c51f124SMoriah Waterland static int	sig_received = 0;
625c51f124SMoriah Waterland 
635c51f124SMoriah Waterland /*
645c51f124SMoriah Waterland  * Name:	sig_trap
655c51f124SMoriah Waterland  * Description:	hooked up to signal counts number of signals received
665c51f124SMoriah Waterland  * Arguments:	a_signo - [RO, *RO] - (int)
675c51f124SMoriah Waterland  *			Integer representing the signal received; see signal(3c)
685c51f124SMoriah Waterland  * Returns:	<void>
695c51f124SMoriah Waterland  */
705c51f124SMoriah Waterland 
715c51f124SMoriah Waterland static void
sig_trap(int a_signo)725c51f124SMoriah Waterland sig_trap(int a_signo)
735c51f124SMoriah Waterland {
74*4656d474SGarrett D'Amore 	_NOTE(ARGUNUSED(a_signo));
755c51f124SMoriah Waterland 	sig_received++;
765c51f124SMoriah Waterland }
775c51f124SMoriah Waterland 
785c51f124SMoriah Waterland /*
795c51f124SMoriah Waterland  * Name:	pkgexecv
805c51f124SMoriah Waterland  * Description:	Asynchronously execute a package command in a separate process
815c51f124SMoriah Waterland  *		and return results - the subprocess MUST arm it's own SIGINT
825c51f124SMoriah Waterland  *		and SIGHUP signals and must return a standard package command
835c51f124SMoriah Waterland  *		exit code (see returns below)
845c51f124SMoriah Waterland  *		Only another package command (such as pkginstall, pkgremove,
855c51f124SMoriah Waterland  *		etc.) may be called via this interface. No files are closed
865c51f124SMoriah Waterland  *		because open files are passed across to certain commands using
875c51f124SMoriah Waterland  *		either implicit agreements between the two (yuk!) or by using
885c51f124SMoriah Waterland  *		the '-p' option which passes a string of digits, some of which
895c51f124SMoriah Waterland  *		represent open file descriptors passed through this interface!
905c51f124SMoriah Waterland  * Arguments:	filein - [RO, *RO] - (char *)
915c51f124SMoriah Waterland  *			Pointer to string representing the name of the file to
925c51f124SMoriah Waterland  *			use for the package commands's stdin
935c51f124SMoriah Waterland  *			== (char *)NULL or == "" - the current stdin
945c51f124SMoriah Waterland  *			is used for the new package command process
955c51f124SMoriah Waterland  *		fileout - [RO, *RO] - (char *)
965c51f124SMoriah Waterland  *			Pointer to string representing the name of the file to
975c51f124SMoriah Waterland  *			use for the package commands's stdout and stderr
985c51f124SMoriah Waterland  *			== (char *)NULL or == "" - the current stdout/stderr
995c51f124SMoriah Waterland  *			is used for the new package command process
1005c51f124SMoriah Waterland  *		uname - [RO, *RO] - (char *)
1015c51f124SMoriah Waterland  *			Pointer to string representing the user name to execute
1025c51f124SMoriah Waterland  *			the package command as - the user name is looked up
1035c51f124SMoriah Waterland  *			using the ncgrpw:cpwnam() interface
1045c51f124SMoriah Waterland  *			== (char *)NULL or == "" - the user name of the current
1055c51f124SMoriah Waterland  *			process is used for the new package command process
1065c51f124SMoriah Waterland  *		gname - [RO, *RO] - (char *)
1075c51f124SMoriah Waterland  *			Pointer to string representing the group name to execute
1085c51f124SMoriah Waterland  *			the package command as - the group name is looked up
1095c51f124SMoriah Waterland  *			using the ncgrpw:cgrnam() interface
1105c51f124SMoriah Waterland  *			== (char *)NULL or == "" - the group name of the current
1115c51f124SMoriah Waterland  *			process is used for the new package command process
1125c51f124SMoriah Waterland  *		arg - [RO, *RO] - (char **)
1135c51f124SMoriah Waterland  *			Pointer to array of character pointers representing the
1145c51f124SMoriah Waterland  *			arguments to pass to the package command - the array is
1155c51f124SMoriah Waterland  *			terminated with a pointer to (char *)NULL
1165c51f124SMoriah Waterland  * Returns:	int
1175c51f124SMoriah Waterland  *			== 99 - exec() of package command failed
1185c51f124SMoriah Waterland  *			== -1 - fork failed or other fatal error during
1195c51f124SMoriah Waterland  *				execution of the package command
1205c51f124SMoriah Waterland  *			otherwise - exit code from package command:
1215c51f124SMoriah Waterland  *			0 - successful
1225c51f124SMoriah Waterland  *			1 - package operation failed (fatal error)
1235c51f124SMoriah Waterland  *			2 - non-fatal error (warning)
1245c51f124SMoriah Waterland  *			3 - operation interrupted (including SIGINT/SIGHUP)
1255c51f124SMoriah Waterland  *			4 - admin settings prevented operation
1265c51f124SMoriah Waterland  *			5 - administration required and -n was specified
1275c51f124SMoriah Waterland  *			IN addition:
1285c51f124SMoriah Waterland  *			10 is added to the return code if reboot after the
1295c51f124SMoriah Waterland  *				installation of all packages is required
1305c51f124SMoriah Waterland  *			20 is added to the return code if immediate reboot
1315c51f124SMoriah Waterland  *				after installation of this package is required
1325c51f124SMoriah Waterland  */
1335c51f124SMoriah Waterland 
1345c51f124SMoriah Waterland int
pkgexecv(char * filein,char * fileout,char * uname,char * gname,char * arg[])1355c51f124SMoriah Waterland pkgexecv(char *filein, char *fileout, char *uname, char *gname, char *arg[])
1365c51f124SMoriah Waterland {
1375c51f124SMoriah Waterland 	int			exit_no;
1385c51f124SMoriah Waterland 	int			n;
1395c51f124SMoriah Waterland 	int			status;
1405c51f124SMoriah Waterland 	pid_t			pid;
1415c51f124SMoriah Waterland 	pid_t			waitstat;
1425c51f124SMoriah Waterland 	struct group		*grp;
1435c51f124SMoriah Waterland 	struct passwd		*pwp;
1445c51f124SMoriah Waterland 	struct sigaction	nact;
1455c51f124SMoriah Waterland 	struct sigaction	oact;
1465c51f124SMoriah Waterland 	void			(*funcSighup)();
1475c51f124SMoriah Waterland 	void			(*funcSigint)();
1485c51f124SMoriah Waterland 
1495c51f124SMoriah Waterland 	/* flush standard i/o before creating new process */
1505c51f124SMoriah Waterland 
1515c51f124SMoriah Waterland 	(void) fflush(stdout);
1525c51f124SMoriah Waterland 	(void) fflush(stderr);
1535c51f124SMoriah Waterland 
1545c51f124SMoriah Waterland 	/*
1555c51f124SMoriah Waterland 	 * hold SIGINT/SIGHUP signals and reset signal received counter;
1565c51f124SMoriah Waterland 	 * after the vfork() the parent and child need to setup their respective
1575c51f124SMoriah Waterland 	 * interrupt handling and release the hold on the signals
1585c51f124SMoriah Waterland 	 */
1595c51f124SMoriah Waterland 
1605c51f124SMoriah Waterland 	(void) sighold(SIGINT);
1615c51f124SMoriah Waterland 	(void) sighold(SIGHUP);
1625c51f124SMoriah Waterland 
1635c51f124SMoriah Waterland 	sig_received = 0;
1645c51f124SMoriah Waterland 
1655c51f124SMoriah Waterland 	/*
1665c51f124SMoriah Waterland 	 * create new process to execute command in;
1675c51f124SMoriah Waterland 	 * vfork() is being used to avoid duplicating the parents
1685c51f124SMoriah Waterland 	 * memory space - this means that the child process may
1695c51f124SMoriah Waterland 	 * not modify any of the parents memory including the
1705c51f124SMoriah Waterland 	 * standard i/o descriptors - all the child can do is
1715c51f124SMoriah Waterland 	 * adjust interrupts and open files as a prelude to a
1725c51f124SMoriah Waterland 	 * call to exec().
1735c51f124SMoriah Waterland 	 */
1745c51f124SMoriah Waterland 
1755c51f124SMoriah Waterland 	pid = vfork();
1765c51f124SMoriah Waterland 
1775c51f124SMoriah Waterland 	if (pid < 0) {
1785c51f124SMoriah Waterland 		/*
1795c51f124SMoriah Waterland 		 * *************************************************************
1805c51f124SMoriah Waterland 		 * fork failed!
1815c51f124SMoriah Waterland 		 * *************************************************************
1825c51f124SMoriah Waterland 		 */
1835c51f124SMoriah Waterland 
1845c51f124SMoriah Waterland 		progerr(pkg_gt(ERR_FORK_FAILED), errno, strerror(errno));
1855c51f124SMoriah Waterland 
1865c51f124SMoriah Waterland 		/* release hold on signals */
1875c51f124SMoriah Waterland 
1885c51f124SMoriah Waterland 		(void) sigrelse(SIGHUP);
1895c51f124SMoriah Waterland 		(void) sigrelse(SIGINT);
1905c51f124SMoriah Waterland 
1915c51f124SMoriah Waterland 		return (-1);
1925c51f124SMoriah Waterland 	}
1935c51f124SMoriah Waterland 
1945c51f124SMoriah Waterland 	if (pid > 0) {
1955c51f124SMoriah Waterland 		/*
1965c51f124SMoriah Waterland 		 * *************************************************************
1975c51f124SMoriah Waterland 		 * This is the forking (parent) process
1985c51f124SMoriah Waterland 		 * *************************************************************
1995c51f124SMoriah Waterland 		 */
2005c51f124SMoriah Waterland 
2015c51f124SMoriah Waterland 		/* close datastream if any portion read */
2025c51f124SMoriah Waterland 
2035c51f124SMoriah Waterland 		if (ds_curpartcnt >= 0) {
2045c51f124SMoriah Waterland 			if (ds_close(0) != 0) {
2055c51f124SMoriah Waterland 				/* kill child process */
2065c51f124SMoriah Waterland 
2075c51f124SMoriah Waterland 				(void) sigsend(P_PID, pid, SIGKILL);
2085c51f124SMoriah Waterland 
2095c51f124SMoriah Waterland 				/* release hold on signals */
2105c51f124SMoriah Waterland 
2115c51f124SMoriah Waterland 				(void) sigrelse(SIGHUP);
2125c51f124SMoriah Waterland 				(void) sigrelse(SIGINT);
2135c51f124SMoriah Waterland 
2145c51f124SMoriah Waterland 				return (-1);
2155c51f124SMoriah Waterland 			}
2165c51f124SMoriah Waterland 		}
2175c51f124SMoriah Waterland 
2185c51f124SMoriah Waterland 		/*
2195c51f124SMoriah Waterland 		 * setup signal handlers for SIGINT and SIGHUP and release hold
2205c51f124SMoriah Waterland 		 */
2215c51f124SMoriah Waterland 
2225c51f124SMoriah Waterland 		/* hook SIGINT to sig_trap() */
2235c51f124SMoriah Waterland 
2245c51f124SMoriah Waterland 		nact.sa_handler = sig_trap;
2255c51f124SMoriah Waterland 		nact.sa_flags = SA_RESTART;
2265c51f124SMoriah Waterland 		(void) sigemptyset(&nact.sa_mask);
2275c51f124SMoriah Waterland 
2285c51f124SMoriah Waterland 		if (sigaction(SIGINT, &nact, &oact) < 0) {
2295c51f124SMoriah Waterland 			funcSigint = SIG_DFL;
2305c51f124SMoriah Waterland 		} else {
2315c51f124SMoriah Waterland 			funcSigint = oact.sa_handler;
2325c51f124SMoriah Waterland 		}
2335c51f124SMoriah Waterland 
2345c51f124SMoriah Waterland 		/* hook SIGHUP to sig_trap() */
2355c51f124SMoriah Waterland 
2365c51f124SMoriah Waterland 		nact.sa_handler = sig_trap;
2375c51f124SMoriah Waterland 		nact.sa_flags = SA_RESTART;
2385c51f124SMoriah Waterland 		(void) sigemptyset(&nact.sa_mask);
2395c51f124SMoriah Waterland 
2405c51f124SMoriah Waterland 		if (sigaction(SIGHUP, &nact, &oact) < 0) {
2415c51f124SMoriah Waterland 			funcSighup = SIG_DFL;
2425c51f124SMoriah Waterland 		} else {
2435c51f124SMoriah Waterland 			funcSighup = oact.sa_handler;
2445c51f124SMoriah Waterland 		}
2455c51f124SMoriah Waterland 
2465c51f124SMoriah Waterland 		/* release hold on signals */
2475c51f124SMoriah Waterland 
2485c51f124SMoriah Waterland 		(void) sigrelse(SIGHUP);
2495c51f124SMoriah Waterland 		(void) sigrelse(SIGINT);
2505c51f124SMoriah Waterland 
2515c51f124SMoriah Waterland 		/*
2525c51f124SMoriah Waterland 		 * wait for the process to exit, reap child exit status
2535c51f124SMoriah Waterland 		 */
2545c51f124SMoriah Waterland 
2555c51f124SMoriah Waterland 		for (;;) {
2565c51f124SMoriah Waterland 			status = 0;
257*4656d474SGarrett D'Amore 			waitstat = waitpid(pid, &status, 0);
2585c51f124SMoriah Waterland 			if (waitstat < 0) {
2595c51f124SMoriah Waterland 				/* waitpid returned error */
2605c51f124SMoriah Waterland 				if (errno == EAGAIN) {
2615c51f124SMoriah Waterland 					/* try again */
2625c51f124SMoriah Waterland 					continue;
2635c51f124SMoriah Waterland 				}
2645c51f124SMoriah Waterland 				if (errno == EINTR) {
2655c51f124SMoriah Waterland 					continue;
2665c51f124SMoriah Waterland 				}
2675c51f124SMoriah Waterland 				/* error from waitpid: bail */
2685c51f124SMoriah Waterland 				break;
2695c51f124SMoriah Waterland 			} else if (waitstat == pid) {
2705c51f124SMoriah Waterland 				/* child exit status available */
2715c51f124SMoriah Waterland 				break;
2725c51f124SMoriah Waterland 			}
2735c51f124SMoriah Waterland 		}
2745c51f124SMoriah Waterland 
2755c51f124SMoriah Waterland 		/*
2765c51f124SMoriah Waterland 		 * reset signal handlers
2775c51f124SMoriah Waterland 		 */
2785c51f124SMoriah Waterland 
2795c51f124SMoriah Waterland 		/* reset SIGINT */
2805c51f124SMoriah Waterland 
2815c51f124SMoriah Waterland 		nact.sa_handler = funcSigint;
2825c51f124SMoriah Waterland 		nact.sa_flags = SA_RESTART;
2835c51f124SMoriah Waterland 		(void) sigemptyset(&nact.sa_mask);
2845c51f124SMoriah Waterland 
2855c51f124SMoriah Waterland 		(void) sigaction(SIGINT, &nact, (struct sigaction *)NULL);
2865c51f124SMoriah Waterland 
2875c51f124SMoriah Waterland 		/* reset SIGHUP */
2885c51f124SMoriah Waterland 
2895c51f124SMoriah Waterland 		nact.sa_handler = funcSighup;
2905c51f124SMoriah Waterland 		nact.sa_flags = SA_RESTART;
2915c51f124SMoriah Waterland 		(void) sigemptyset(&nact.sa_mask);
2925c51f124SMoriah Waterland 
2935c51f124SMoriah Waterland 		(void) sigaction(SIGHUP, &nact, (struct sigaction *)NULL);
2945c51f124SMoriah Waterland 
2955c51f124SMoriah Waterland 		/* error if child process does not match */
2965c51f124SMoriah Waterland 
2975c51f124SMoriah Waterland 		if (waitstat != pid) {
298*4656d474SGarrett D'Amore 			progerr(pkg_gt(ERR_WAIT_FAILED), pid, status,
299*4656d474SGarrett D'Amore 			    errno, strerror(errno));
3005c51f124SMoriah Waterland 			return (-1);
3015c51f124SMoriah Waterland 		}
3025c51f124SMoriah Waterland 
3035c51f124SMoriah Waterland 		/*
3045c51f124SMoriah Waterland 		 * determine final exit code:
3055c51f124SMoriah Waterland 		 * - if signal received, then return interrupted (3)
3065c51f124SMoriah Waterland 		 * - if child exit status is available, return exit child status
3075c51f124SMoriah Waterland 		 * - otherwise return error (-1)
3085c51f124SMoriah Waterland 		 */
3095c51f124SMoriah Waterland 
3105c51f124SMoriah Waterland 		if (sig_received != 0) {
3115c51f124SMoriah Waterland 			exit_no = 3;	/* interrupted */
3125c51f124SMoriah Waterland 		} else if (WIFEXITED(status)) {
3135c51f124SMoriah Waterland 			exit_no = WEXITSTATUS(status);
3145c51f124SMoriah Waterland 		} else {
3155c51f124SMoriah Waterland 			exit_no = -1;	/* exec() or other process error */
3165c51f124SMoriah Waterland 		}
3175c51f124SMoriah Waterland 
3185c51f124SMoriah Waterland 		return (exit_no);
3195c51f124SMoriah Waterland 	}
3205c51f124SMoriah Waterland 
3215c51f124SMoriah Waterland 	/*
3225c51f124SMoriah Waterland 	 * *********************************************************************
3235c51f124SMoriah Waterland 	 * This is the forked (child) process
3245c51f124SMoriah Waterland 	 * *********************************************************************
3255c51f124SMoriah Waterland 	 */
3265c51f124SMoriah Waterland 
3275c51f124SMoriah Waterland 	/* reset all signals to default */
3285c51f124SMoriah Waterland 
3295c51f124SMoriah Waterland 	for (n = 0; n < NSIG; n++) {
3305c51f124SMoriah Waterland 		(void) sigset(n, SIG_DFL);
3315c51f124SMoriah Waterland 	}
3325c51f124SMoriah Waterland 
3335c51f124SMoriah Waterland 	/* release hold on signals held by parent before fork() */
3345c51f124SMoriah Waterland 
3355c51f124SMoriah Waterland 	(void) sigrelse(SIGHUP);
3365c51f124SMoriah Waterland 	(void) sigrelse(SIGINT);
3375c51f124SMoriah Waterland 
3385c51f124SMoriah Waterland 	/*
3395c51f124SMoriah Waterland 	 * The caller wants to have stdin connected to filein.
3405c51f124SMoriah Waterland 	 */
3415c51f124SMoriah Waterland 
3425c51f124SMoriah Waterland 	if (filein && *filein) {
3435c51f124SMoriah Waterland 		/*
3445c51f124SMoriah Waterland 		 * If input is supposed to be connected to /dev/tty
3455c51f124SMoriah Waterland 		 */
3465c51f124SMoriah Waterland 		if (strncmp(filein, "/dev/tty", 8) == 0) {
3475c51f124SMoriah Waterland 			/*
3485c51f124SMoriah Waterland 			 * If stdin is connected to a tty device.
3495c51f124SMoriah Waterland 			 */
3505c51f124SMoriah Waterland 			if (isatty(STDIN_FILENO)) {
3515c51f124SMoriah Waterland 				/*
3525c51f124SMoriah Waterland 				 * Reopen it to /dev/tty.
3535c51f124SMoriah Waterland 				 */
3545c51f124SMoriah Waterland 				n = open(filein, O_RDONLY);
3555c51f124SMoriah Waterland 				if (n >= 0) {
3565c51f124SMoriah Waterland 					(void) dup2(n, STDIN_FILENO);
3575c51f124SMoriah Waterland 				}
3585c51f124SMoriah Waterland 			}
3595c51f124SMoriah Waterland 		} else {
3605c51f124SMoriah Waterland 			/*
3615c51f124SMoriah Waterland 			 * If we did not want to be connected to /dev/tty, we
3625c51f124SMoriah Waterland 			 * connect input to the requested file no questions.
3635c51f124SMoriah Waterland 			 */
3645c51f124SMoriah Waterland 			n = open(filein, O_RDONLY);
3655c51f124SMoriah Waterland 			if (n >= 0) {
3665c51f124SMoriah Waterland 				(void) dup2(n, STDIN_FILENO);
3675c51f124SMoriah Waterland 			}
3685c51f124SMoriah Waterland 		}
3695c51f124SMoriah Waterland 	}
3705c51f124SMoriah Waterland 
3715c51f124SMoriah Waterland 	/*
3725c51f124SMoriah Waterland 	 * The caller wants to have stdout and stderr connected to fileout.
3735c51f124SMoriah Waterland 	 * If "fileout" is "/dev/tty" then reconnect stdout to "/dev/tty"
3745c51f124SMoriah Waterland 	 * only if /dev/tty is not already associated with "a tty".
3755c51f124SMoriah Waterland 	 */
3765c51f124SMoriah Waterland 
3775c51f124SMoriah Waterland 	if (fileout && *fileout) {
3785c51f124SMoriah Waterland 		/*
3795c51f124SMoriah Waterland 		 * If output is supposed to be connected to /dev/tty
3805c51f124SMoriah Waterland 		 */
3815c51f124SMoriah Waterland 		if (strncmp(fileout, "/dev/tty", 8) == 0) {
3825c51f124SMoriah Waterland 			/*
3835c51f124SMoriah Waterland 			 * If stdout is connected to a tty device.
3845c51f124SMoriah Waterland 			 */
3855c51f124SMoriah Waterland 			if (isatty(STDOUT_FILENO)) {
3865c51f124SMoriah Waterland 				/*
3875c51f124SMoriah Waterland 				 * Reopen it to /dev/tty if /dev/tty available.
3885c51f124SMoriah Waterland 				 */
3895c51f124SMoriah Waterland 				n = open(fileout, O_WRONLY);
3905c51f124SMoriah Waterland 				if (n >= 0) {
3915c51f124SMoriah Waterland 					/*
3925c51f124SMoriah Waterland 					 * /dev/tty is available - close the
3935c51f124SMoriah Waterland 					 * current standard output stream, and
3945c51f124SMoriah Waterland 					 * reopen it on /dev/tty
3955c51f124SMoriah Waterland 					 */
3965c51f124SMoriah Waterland 					(void) dup2(n, STDOUT_FILENO);
3975c51f124SMoriah Waterland 				}
3985c51f124SMoriah Waterland 			}
3995c51f124SMoriah Waterland 			/*
4005c51f124SMoriah Waterland 			 * not connected to tty device - probably redirect to
4015c51f124SMoriah Waterland 			 * file - preserve existing output device
4025c51f124SMoriah Waterland 			 */
4035c51f124SMoriah Waterland 		} else {
4045c51f124SMoriah Waterland 			/*
4055c51f124SMoriah Waterland 			 * If we did not want to be connected to /dev/tty, we
4065c51f124SMoriah Waterland 			 * connect output to the requested file no questions.
4075c51f124SMoriah Waterland 			 */
4085c51f124SMoriah Waterland 			/* LINTED O_CREAT without O_EXCL specified in call to */
4095c51f124SMoriah Waterland 			n = open(fileout, O_WRONLY|O_CREAT|O_APPEND, 0666);
4105c51f124SMoriah Waterland 			if (n >= 0) {
4115c51f124SMoriah Waterland 				(void) dup2(n, STDOUT_FILENO);
4125c51f124SMoriah Waterland 			}
4135c51f124SMoriah Waterland 		}
4145c51f124SMoriah Waterland 
4155c51f124SMoriah Waterland 		/*
4165c51f124SMoriah Waterland 		 * Dup stderr from stdout.
4175c51f124SMoriah Waterland 		 */
4185c51f124SMoriah Waterland 
4195c51f124SMoriah Waterland 		(void) dup2(STDOUT_FILENO, STDERR_FILENO);
4205c51f124SMoriah Waterland 	}
4215c51f124SMoriah Waterland 
4225c51f124SMoriah Waterland 	/*
4235c51f124SMoriah Waterland 	 * do NOT close all file descriptors except stdio
4245c51f124SMoriah Waterland 	 * file descriptors are passed in to some subcommands
4255c51f124SMoriah Waterland 	 * (see dstream:ds_getinfo() and dstream:ds_putinfo())
4265c51f124SMoriah Waterland 	 */
4275c51f124SMoriah Waterland 
4285c51f124SMoriah Waterland 	/* set group/user i.d. if requested */
4295c51f124SMoriah Waterland 
4305c51f124SMoriah Waterland 	if (gname && *gname && (grp = cgrnam(gname)) != NULL) {
4315c51f124SMoriah Waterland 		if (setgid(grp->gr_gid) == -1) {
4325c51f124SMoriah Waterland 			progerr(pkg_gt(ERR_SETGID), grp->gr_gid);
4335c51f124SMoriah Waterland 		}
4345c51f124SMoriah Waterland 	}
4355c51f124SMoriah Waterland 	if (uname && *uname && (pwp = cpwnam(uname)) != NULL) {
4365c51f124SMoriah Waterland 		if (setuid(pwp->pw_uid) == -1) {
4375c51f124SMoriah Waterland 			progerr(pkg_gt(ERR_SETUID), pwp->pw_uid);
4385c51f124SMoriah Waterland 		}
4395c51f124SMoriah Waterland 	}
4405c51f124SMoriah Waterland 
4415c51f124SMoriah Waterland 	/* execute target executable */
4425c51f124SMoriah Waterland 
4435c51f124SMoriah Waterland 	(void) execve(arg[0], arg, environ);
4445c51f124SMoriah Waterland 	progerr(pkg_gt(ERR_EX_FAIL), arg[0], errno);
4455c51f124SMoriah Waterland 	_exit(99);
4465c51f124SMoriah Waterland 	/*NOTREACHED*/
4475c51f124SMoriah Waterland }