xref: /illumos-gate/usr/src/lib/libpkg/common/runcmd.c (revision 3970c098)
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 2009 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 
325c51f124SMoriah Waterland #include <stdio.h>
335c51f124SMoriah Waterland #include <errno.h>
345c51f124SMoriah Waterland #include <string.h>
355c51f124SMoriah Waterland #include <strings.h>
365c51f124SMoriah Waterland #include <signal.h>
375c51f124SMoriah Waterland #include <fcntl.h>
385c51f124SMoriah Waterland #include <stdlib.h>
395c51f124SMoriah Waterland #include <unistd.h>
405c51f124SMoriah Waterland #include <wait.h>
415c51f124SMoriah Waterland #include <sys/types.h>
425c51f124SMoriah Waterland #include "pkglib.h"
435c51f124SMoriah Waterland #include "pkglocale.h"
445c51f124SMoriah Waterland #include "pkglibmsgs.h"
455c51f124SMoriah Waterland 
465c51f124SMoriah Waterland #ifndef _STDARG_H
475c51f124SMoriah Waterland #include "stdarg.h"
485c51f124SMoriah Waterland #endif
495c51f124SMoriah Waterland 
505c51f124SMoriah Waterland /*
515c51f124SMoriah Waterland  * Private definitions
525c51f124SMoriah Waterland  */
535c51f124SMoriah Waterland 
545c51f124SMoriah Waterland /* Maximum number of arguments to pkg_ExecCmdList */
555c51f124SMoriah Waterland 
565c51f124SMoriah Waterland #define	MAX_EXEC_CMD_ARGS	100
575c51f124SMoriah Waterland 
585c51f124SMoriah Waterland /* Size of buffer increments when reading from pipe */
595c51f124SMoriah Waterland 
605c51f124SMoriah Waterland #define	PIPE_BUFFER_INCREMENT	256
615c51f124SMoriah Waterland 
625c51f124SMoriah Waterland static char	errfile[L_tmpnam+1];
635c51f124SMoriah Waterland 
645c51f124SMoriah Waterland /*
655c51f124SMoriah Waterland  * Public Methods
665c51f124SMoriah Waterland  */
675c51f124SMoriah Waterland 
685c51f124SMoriah Waterland 
695c51f124SMoriah Waterland void
rpterr(void)705c51f124SMoriah Waterland rpterr(void)
715c51f124SMoriah Waterland {
725c51f124SMoriah Waterland 	FILE	*fp;
735c51f124SMoriah Waterland 	int	c;
745c51f124SMoriah Waterland 
755c51f124SMoriah Waterland 	if (errfile[0]) {
765c51f124SMoriah Waterland 		if (fp = fopen(errfile, "r")) {
775c51f124SMoriah Waterland 			while ((c = getc(fp)) != EOF)
784656d474SGarrett D'Amore 				(void) putc(c, stderr);
795c51f124SMoriah Waterland 			(void) fclose(fp);
805c51f124SMoriah Waterland 		}
815c51f124SMoriah Waterland 		(void) unlink(errfile);
825c51f124SMoriah Waterland 		errfile[0] = '\0';
835c51f124SMoriah Waterland 	}
845c51f124SMoriah Waterland }
855c51f124SMoriah Waterland 
865c51f124SMoriah Waterland void
ecleanup(void)875c51f124SMoriah Waterland ecleanup(void)
885c51f124SMoriah Waterland {
895c51f124SMoriah Waterland 	if (errfile[0]) {
905c51f124SMoriah Waterland 		(void) unlink(errfile);
91*3970c098SToomas Soome 		errfile[0] = '\0';
925c51f124SMoriah Waterland 	}
935c51f124SMoriah Waterland }
945c51f124SMoriah Waterland 
955c51f124SMoriah Waterland int
esystem(char * cmd,int ifd,int ofd)965c51f124SMoriah Waterland esystem(char *cmd, int ifd, int ofd)
975c51f124SMoriah Waterland {
985c51f124SMoriah Waterland 	char	*perrfile;
995c51f124SMoriah Waterland 	int	status = 0;
1005c51f124SMoriah Waterland 	pid_t	pid;
1015c51f124SMoriah Waterland 
1025c51f124SMoriah Waterland 	perrfile = tmpnam(NULL);
1035c51f124SMoriah Waterland 	if (perrfile == NULL) {
1045c51f124SMoriah Waterland 		progerr(
1055c51f124SMoriah Waterland 		    pkg_gt("unable to create temp error file, errno=%d"),
1065c51f124SMoriah Waterland 		    errno);
1075c51f124SMoriah Waterland 		return (-1);
1085c51f124SMoriah Waterland 	}
1095c51f124SMoriah Waterland 	(void) strlcpy(errfile, perrfile, sizeof (errfile));
1105c51f124SMoriah Waterland 
1115c51f124SMoriah Waterland 	/* flush standard i/o before creating new process */
1125c51f124SMoriah Waterland 
1135c51f124SMoriah Waterland 	(void) fflush(stderr);
1145c51f124SMoriah Waterland 	(void) fflush(stdout);
1155c51f124SMoriah Waterland 
1165c51f124SMoriah Waterland 	/*
1175c51f124SMoriah Waterland 	 * create new process to execute command in;
1185c51f124SMoriah Waterland 	 * vfork() is being used to avoid duplicating the parents
1195c51f124SMoriah Waterland 	 * memory space - this means that the child process may
1205c51f124SMoriah Waterland 	 * not modify any of the parents memory including the
1215c51f124SMoriah Waterland 	 * standard i/o descriptors - all the child can do is
1225c51f124SMoriah Waterland 	 * adjust interrupts and open files as a prelude to a
1235c51f124SMoriah Waterland 	 * call to exec().
1245c51f124SMoriah Waterland 	 */
1255c51f124SMoriah Waterland 
1265c51f124SMoriah Waterland 	pid = vfork();
1275c51f124SMoriah Waterland 	if (pid == 0) {
1285c51f124SMoriah Waterland 		/*
1295c51f124SMoriah Waterland 		 * this is the child process
1305c51f124SMoriah Waterland 		 */
1315c51f124SMoriah Waterland 		int	i;
1325c51f124SMoriah Waterland 
1335c51f124SMoriah Waterland 		/* reset any signals to default */
1345c51f124SMoriah Waterland 
1355c51f124SMoriah Waterland 		for (i = 0; i < NSIG; i++) {
1365c51f124SMoriah Waterland 			(void) sigset(i, SIG_DFL);
1375c51f124SMoriah Waterland 		}
1385c51f124SMoriah Waterland 
1395c51f124SMoriah Waterland 		if (ifd > 0) {
1405c51f124SMoriah Waterland 			(void) dup2(ifd, STDIN_FILENO);
1415c51f124SMoriah Waterland 		}
1425c51f124SMoriah Waterland 
1435c51f124SMoriah Waterland 		if (ofd >= 0 && ofd != STDOUT_FILENO) {
1445c51f124SMoriah Waterland 			(void) dup2(ofd, STDOUT_FILENO);
1455c51f124SMoriah Waterland 		}
1465c51f124SMoriah Waterland 
1475c51f124SMoriah Waterland 		i = open(errfile, O_WRONLY|O_CREAT|O_TRUNC, 0666);
1485c51f124SMoriah Waterland 		if (i >= 0) {
1494656d474SGarrett D'Amore 			(void) dup2(i, STDERR_FILENO);
1505c51f124SMoriah Waterland 		}
1515c51f124SMoriah Waterland 
1525c51f124SMoriah Waterland 		/* Close all open files except standard i/o */
1535c51f124SMoriah Waterland 
1545c51f124SMoriah Waterland 		closefrom(3);
1555c51f124SMoriah Waterland 
1565c51f124SMoriah Waterland 		/* execute target executable */
1575c51f124SMoriah Waterland 
1584656d474SGarrett D'Amore 		(void) execl("/sbin/sh", "/sbin/sh", "-c", cmd, NULL);
1595c51f124SMoriah Waterland 		progerr(pkg_gt("exec of <%s> failed, errno=%d"), cmd, errno);
1605c51f124SMoriah Waterland 		_exit(99);
1615c51f124SMoriah Waterland 	} else if (pid < 0) {
1625c51f124SMoriah Waterland 		/* fork failed! */
1635c51f124SMoriah Waterland 
1645c51f124SMoriah Waterland 		logerr(pkg_gt("bad vfork(), errno=%d"), errno);
1655c51f124SMoriah Waterland 		return (-1);
1665c51f124SMoriah Waterland 	}
1675c51f124SMoriah Waterland 
1685c51f124SMoriah Waterland 	/*
1695c51f124SMoriah Waterland 	 * this is the parent process
1705c51f124SMoriah Waterland 	 */
1715c51f124SMoriah Waterland 
1724656d474SGarrett D'Amore 	(void) sighold(SIGINT);
1735c51f124SMoriah Waterland 	pid = waitpid(pid, &status, 0);
1744656d474SGarrett D'Amore 	(void) sigrelse(SIGINT);
1755c51f124SMoriah Waterland 
1765c51f124SMoriah Waterland 	if (pid < 0) {
1775c51f124SMoriah Waterland 		return (-1); /* probably interrupted */
1785c51f124SMoriah Waterland 	}
1795c51f124SMoriah Waterland 
1805c51f124SMoriah Waterland 	switch (status & 0177) {
1815c51f124SMoriah Waterland 		case 0:
1825c51f124SMoriah Waterland 		case 0177:
1835c51f124SMoriah Waterland 			status = status >> 8;
1845c51f124SMoriah Waterland 			/*FALLTHROUGH*/
1855c51f124SMoriah Waterland 
1865c51f124SMoriah Waterland 		default:
1875c51f124SMoriah Waterland 			/* terminated by a signal */
1885c51f124SMoriah Waterland 			status = status & 0177;
1895c51f124SMoriah Waterland 	}
1905c51f124SMoriah Waterland 
1915c51f124SMoriah Waterland 	if (status == 0) {
1925c51f124SMoriah Waterland 		ecleanup();
1935c51f124SMoriah Waterland 	}
1945c51f124SMoriah Waterland 
1955c51f124SMoriah Waterland 	return (status);
1965c51f124SMoriah Waterland }
1975c51f124SMoriah Waterland 
1985c51f124SMoriah Waterland FILE *
epopen(char * cmd,char * mode)1995c51f124SMoriah Waterland epopen(char *cmd, char *mode)
2005c51f124SMoriah Waterland {
2015c51f124SMoriah Waterland 	char	*buffer, *perrfile;
2025c51f124SMoriah Waterland 	FILE	*pp;
2035c51f124SMoriah Waterland 	size_t	len;
2045c51f124SMoriah Waterland 	size_t	alen;
2055c51f124SMoriah Waterland 
2065c51f124SMoriah Waterland 	if (errfile[0]) {
2075c51f124SMoriah Waterland 		/* cleanup previous errfile */
2084656d474SGarrett D'Amore 		(void) unlink(errfile);
2095c51f124SMoriah Waterland 	}
2105c51f124SMoriah Waterland 
2115c51f124SMoriah Waterland 	perrfile = tmpnam(NULL);
2125c51f124SMoriah Waterland 	if (perrfile == NULL) {
2135c51f124SMoriah Waterland 		progerr(
2145c51f124SMoriah Waterland 		    pkg_gt("unable to create temp error file, errno=%d"),
2155c51f124SMoriah Waterland 		    errno);
2165c51f124SMoriah Waterland 		return ((FILE *)0);
2175c51f124SMoriah Waterland 	}
2185c51f124SMoriah Waterland 
2195c51f124SMoriah Waterland 	if (strlcpy(errfile, perrfile, sizeof (errfile)) > sizeof (errfile)) {
2205c51f124SMoriah Waterland 		progerr(pkg_gt("file name max length %d; name is too long: %s"),
221*3970c098SToomas Soome 		    sizeof (errfile), perrfile);
222*3970c098SToomas Soome 		return (NULL);
2235c51f124SMoriah Waterland 	}
2245c51f124SMoriah Waterland 
2255c51f124SMoriah Waterland 	len = strlen(cmd)+6+strlen(errfile);
2265c51f124SMoriah Waterland 	buffer = (char *)calloc(len, sizeof (char));
2275c51f124SMoriah Waterland 	if (buffer == NULL) {
2285c51f124SMoriah Waterland 		progerr(pkg_gt("no memory in epopen(), errno=%d"), errno);
229*3970c098SToomas Soome 		return (NULL);
2305c51f124SMoriah Waterland 	}
2315c51f124SMoriah Waterland 
2325c51f124SMoriah Waterland 	if (strchr(cmd, '|')) {
2335c51f124SMoriah Waterland 		alen = snprintf(buffer, len, "(%s) 2>%s", cmd, errfile);
2345c51f124SMoriah Waterland 	} else {
2355c51f124SMoriah Waterland 		alen = snprintf(buffer, len, "%s 2>%s", cmd, errfile);
2365c51f124SMoriah Waterland 	}
2375c51f124SMoriah Waterland 
2385c51f124SMoriah Waterland 	if (alen > len) {
2395c51f124SMoriah Waterland 		progerr(pkg_gt("command max length %d; cmd is too long: %s"),
240*3970c098SToomas Soome 		    len, cmd);
241*3970c098SToomas Soome 		return (NULL);
2425c51f124SMoriah Waterland 	}
2435c51f124SMoriah Waterland 
2445c51f124SMoriah Waterland 	pp = popen(buffer, mode);
2455c51f124SMoriah Waterland 
2465c51f124SMoriah Waterland 	free(buffer);
2475c51f124SMoriah Waterland 	return (pp);
2485c51f124SMoriah Waterland }
2495c51f124SMoriah Waterland 
2505c51f124SMoriah Waterland int
epclose(FILE * pp)2515c51f124SMoriah Waterland epclose(FILE *pp)
2525c51f124SMoriah Waterland {
2535c51f124SMoriah Waterland 	int n;
2545c51f124SMoriah Waterland 
2555c51f124SMoriah Waterland 	n = pclose(pp);
2565c51f124SMoriah Waterland 	if (n == 0)
2575c51f124SMoriah Waterland 		ecleanup();
2585c51f124SMoriah Waterland 	return (n);
2595c51f124SMoriah Waterland }
2605c51f124SMoriah Waterland 
2615c51f124SMoriah Waterland /*
2625c51f124SMoriah Waterland  * Name:	e_ExecCmdArray
2635c51f124SMoriah Waterland  * Synopsis:	Execute Unix command and return results
2645c51f124SMoriah Waterland  * Description:	Execute a Unix command and return results and status
2655c51f124SMoriah Waterland  * Arguments:
2665c51f124SMoriah Waterland  *		r_status - [RO, *RW] - (int *)
2675c51f124SMoriah Waterland  *			Return (exit) status from Unix command:
2685c51f124SMoriah Waterland  *			== -1 : child terminated with a signal
2695c51f124SMoriah Waterland  *			!= -1 : lower 8-bit value child passed to exit()
2705c51f124SMoriah Waterland  *		r_results - [RO, *RW] - (char **)
2715c51f124SMoriah Waterland  *			Any output generated by the Unix command to stdout
2725c51f124SMoriah Waterland  *			and to stderr
2735c51f124SMoriah Waterland  *			== (char *)NULL if no output generated
2745c51f124SMoriah Waterland  *		a_inputFile - [RO, *RO] - (char *)
2755c51f124SMoriah Waterland  *			Pointer to character string representing file to be
2765c51f124SMoriah Waterland  *			used as "standard input" for the command.
2775c51f124SMoriah Waterland  *			== (char *)NULL to use "/dev/null" as standard input
2785c51f124SMoriah Waterland  *		a_cmd - [RO, *RO] - (char *)
2795c51f124SMoriah Waterland  *			Pointer to character string representing the full path
2805c51f124SMoriah Waterland  *			of the Unix command to execute
2815c51f124SMoriah Waterland  *		char **a_args - [RO, *RO] - (char **)
2825c51f124SMoriah Waterland  *			List of character strings representing the arguments
2835c51f124SMoriah Waterland  *			to be passed to the Unix command. The list must be
2845c51f124SMoriah Waterland  *			terminated with an element that is (char *)NULL
2855c51f124SMoriah Waterland  * Returns:	int
2865c51f124SMoriah Waterland  *			== 0 - Command executed
2875c51f124SMoriah Waterland  *				Look at r_status for results of Unix command
2885c51f124SMoriah Waterland  *			!= 0 - problems executing command
2895c51f124SMoriah Waterland  *				r_status and r_results have no meaning;
2905c51f124SMoriah Waterland  *				r_status will be -1
2915c51f124SMoriah Waterland  *				r_results will be NULL
292*3970c098SToomas Soome  * NOTE:	Any results returned is placed in new storage for the
2935c51f124SMoriah Waterland  *		calling method. The caller must use 'free' to dispose
2945c51f124SMoriah Waterland  *		of the storage once the results are no longer needed.
2955c51f124SMoriah Waterland  * NOTE:	If 0 is returned, 'r_status' must be queried to
2965c51f124SMoriah Waterland  *		determine the results of the Unix command.
2975c51f124SMoriah Waterland  * NOTE:	The system "errno" value from immediately after waitpid() call
2985c51f124SMoriah Waterland  *		is preserved for the calling method to use to determine
2995c51f124SMoriah Waterland  *		the system reason why the operation failed.
3005c51f124SMoriah Waterland  */
3015c51f124SMoriah Waterland 
3025c51f124SMoriah Waterland int
e_ExecCmdArray(int * r_status,char ** r_results,char * a_inputFile,char * a_cmd,char ** a_args)3035c51f124SMoriah Waterland e_ExecCmdArray(int *r_status, char **r_results,
304*3970c098SToomas Soome     char *a_inputFile, char *a_cmd, char **a_args)
3055c51f124SMoriah Waterland {
3065c51f124SMoriah Waterland 	char		*buffer;
3075c51f124SMoriah Waterland 	int		bufferIndex;
3085c51f124SMoriah Waterland 	int		bufferSize;
3095c51f124SMoriah Waterland 	int		ipipe[2] = {0, 0};
3105c51f124SMoriah Waterland 	pid_t		pid;
3115c51f124SMoriah Waterland 	pid_t		resultPid;
3125c51f124SMoriah Waterland 	int		status;
3135c51f124SMoriah Waterland 	int		lerrno;
3145c51f124SMoriah Waterland 	int		stdinfile = -1;
3155c51f124SMoriah Waterland 
3165c51f124SMoriah Waterland 	/* reset return results buffer pointer */
3175c51f124SMoriah Waterland 
3185c51f124SMoriah Waterland 	if (r_results != (char **)NULL) {
3195c51f124SMoriah Waterland 		*r_results = (char *)NULL;
3205c51f124SMoriah Waterland 	}
3215c51f124SMoriah Waterland 
3225c51f124SMoriah Waterland 	*r_status = -1;
3235c51f124SMoriah Waterland 
3245c51f124SMoriah Waterland 	/*
3255c51f124SMoriah Waterland 	 * See if command exists
3265c51f124SMoriah Waterland 	 */
3275c51f124SMoriah Waterland 
3285c51f124SMoriah Waterland 	if (access(a_cmd, F_OK|X_OK) != 0) {
3295c51f124SMoriah Waterland 		return (-1);
3305c51f124SMoriah Waterland 	}
3315c51f124SMoriah Waterland 
3325c51f124SMoriah Waterland 	/*
3335c51f124SMoriah Waterland 	 * See if input file exists
3345c51f124SMoriah Waterland 	 */
3355c51f124SMoriah Waterland 
3365c51f124SMoriah Waterland 	if (a_inputFile != (char *)NULL) {
3375c51f124SMoriah Waterland 		stdinfile = open(a_inputFile, O_RDONLY);
3385c51f124SMoriah Waterland 	} else {
3395c51f124SMoriah Waterland 		stdinfile = open("/dev/null", O_RDONLY); /* stdin = /dev/null */
3405c51f124SMoriah Waterland 	}
3415c51f124SMoriah Waterland 
3425c51f124SMoriah Waterland 	if (stdinfile < 0) {
3435c51f124SMoriah Waterland 		return (-1);
3445c51f124SMoriah Waterland 	}
3455c51f124SMoriah Waterland 
3465c51f124SMoriah Waterland 	/*
3475c51f124SMoriah Waterland 	 * Create a pipe to be used to capture the command output
3485c51f124SMoriah Waterland 	 */
3495c51f124SMoriah Waterland 
3505c51f124SMoriah Waterland 	if (pipe(ipipe) != 0) {
3515c51f124SMoriah Waterland 		(void) close(stdinfile);
3525c51f124SMoriah Waterland 		return (-1);
3535c51f124SMoriah Waterland 	}
3545c51f124SMoriah Waterland 
3555c51f124SMoriah Waterland 
3565c51f124SMoriah Waterland 	bufferSize = PIPE_BUFFER_INCREMENT;
3575c51f124SMoriah Waterland 	bufferIndex = 0;
3585c51f124SMoriah Waterland 	buffer = calloc(1, bufferSize);
3595c51f124SMoriah Waterland 	if (buffer == (char *)NULL) {
3605c51f124SMoriah Waterland 		(void) close(stdinfile);
3615c51f124SMoriah Waterland 		return (-1);
3625c51f124SMoriah Waterland 	}
3635c51f124SMoriah Waterland 
3645c51f124SMoriah Waterland 	/* flush standard i/o before creating new process */
3655c51f124SMoriah Waterland 
3665c51f124SMoriah Waterland 	(void) fflush(stderr);
3675c51f124SMoriah Waterland 	(void) fflush(stdout);
3685c51f124SMoriah Waterland 
3695c51f124SMoriah Waterland 	/*
3705c51f124SMoriah Waterland 	 * create new process to execute command in;
3715c51f124SMoriah Waterland 	 * vfork() is being used to avoid duplicating the parents
3725c51f124SMoriah Waterland 	 * memory space - this means that the child process may
3735c51f124SMoriah Waterland 	 * not modify any of the parents memory including the
3745c51f124SMoriah Waterland 	 * standard i/o descriptors - all the child can do is
3755c51f124SMoriah Waterland 	 * adjust interrupts and open files as a prelude to a
3765c51f124SMoriah Waterland 	 * call to exec().
3775c51f124SMoriah Waterland 	 */
3785c51f124SMoriah Waterland 
3795c51f124SMoriah Waterland 	pid = vfork();
3805c51f124SMoriah Waterland 
3815c51f124SMoriah Waterland 	if (pid == 0) {
3825c51f124SMoriah Waterland 		/*
3835c51f124SMoriah Waterland 		 * This is the forked (child) process ======================
3845c51f124SMoriah Waterland 		 */
3855c51f124SMoriah Waterland 
3865c51f124SMoriah Waterland 		int	i;
3875c51f124SMoriah Waterland 
3885c51f124SMoriah Waterland 		/* reset any signals to default */
3895c51f124SMoriah Waterland 
3905c51f124SMoriah Waterland 		for (i = 0; i < NSIG; i++) {
3915c51f124SMoriah Waterland 			(void) sigset(i, SIG_DFL);
3925c51f124SMoriah Waterland 		}
3935c51f124SMoriah Waterland 
3945c51f124SMoriah Waterland 		/* assign stdin, stdout, stderr as appropriate */
3955c51f124SMoriah Waterland 
3965c51f124SMoriah Waterland 		(void) dup2(stdinfile, STDIN_FILENO);
3975c51f124SMoriah Waterland 		(void) close(ipipe[0]);		/* close out pipe reader side */
3985c51f124SMoriah Waterland 		(void) dup2(ipipe[1], STDOUT_FILENO);
3995c51f124SMoriah Waterland 		(void) dup2(ipipe[1], STDERR_FILENO);
4005c51f124SMoriah Waterland 
4015c51f124SMoriah Waterland 		/* Close all open files except standard i/o */
4025c51f124SMoriah Waterland 
4035c51f124SMoriah Waterland 		closefrom(3);
4045c51f124SMoriah Waterland 
4055c51f124SMoriah Waterland 		/* execute target executable */
4065c51f124SMoriah Waterland 
4075c51f124SMoriah Waterland 		(void) execvp(a_cmd, a_args);
4085c51f124SMoriah Waterland 		perror(a_cmd);	/* Emit error msg - ends up in callers buffer */
4095c51f124SMoriah Waterland 		_exit(0x00FE);
4105c51f124SMoriah Waterland 	}
4115c51f124SMoriah Waterland 
4125c51f124SMoriah Waterland 	/*
4135c51f124SMoriah Waterland 	 * This is the forking (parent) process ====================
4145c51f124SMoriah Waterland 	 */
4155c51f124SMoriah Waterland 
4165c51f124SMoriah Waterland 	(void) close(stdinfile);
4175c51f124SMoriah Waterland 	(void) close(ipipe[1]);		/* Close write side of pipe */
4185c51f124SMoriah Waterland 
4195c51f124SMoriah Waterland 	/*
4205c51f124SMoriah Waterland 	 * Spin reading data from the child into the buffer - when the read eofs
4215c51f124SMoriah Waterland 	 * the child has exited
4225c51f124SMoriah Waterland 	 */
4235c51f124SMoriah Waterland 
4245c51f124SMoriah Waterland 	for (;;) {
4255c51f124SMoriah Waterland 		ssize_t	bytesRead;
4265c51f124SMoriah Waterland 
4275c51f124SMoriah Waterland 		/* read as much child data as there is available buffer space */
4285c51f124SMoriah Waterland 
4295c51f124SMoriah Waterland 		bytesRead = read(ipipe[0], buffer + bufferIndex,
430*3970c098SToomas Soome 		    bufferSize - bufferIndex);
4315c51f124SMoriah Waterland 
4325c51f124SMoriah Waterland 		/* break out of read loop if end-of-file encountered */
4335c51f124SMoriah Waterland 
4345c51f124SMoriah Waterland 		if (bytesRead == 0) {
4355c51f124SMoriah Waterland 			break;
4365c51f124SMoriah Waterland 		}
4375c51f124SMoriah Waterland 
4385c51f124SMoriah Waterland 		/* if error, continue if recoverable, else break out of loop */
4395c51f124SMoriah Waterland 
4405c51f124SMoriah Waterland 		if (bytesRead == -1) {
4415c51f124SMoriah Waterland 			/* try again: EAGAIN - insufficient resources */
4425c51f124SMoriah Waterland 
4435c51f124SMoriah Waterland 			if (errno == EAGAIN) {
4445c51f124SMoriah Waterland 				continue;
4455c51f124SMoriah Waterland 			}
4465c51f124SMoriah Waterland 
4475c51f124SMoriah Waterland 			/* try again: EINTR - interrupted system call */
4485c51f124SMoriah Waterland 
4495c51f124SMoriah Waterland 			if (errno == EINTR) {
4505c51f124SMoriah Waterland 				continue;
4515c51f124SMoriah Waterland 			}
4525c51f124SMoriah Waterland 
4535c51f124SMoriah Waterland 			/* break out of loop - error not recoverable */
4545c51f124SMoriah Waterland 			break;
4555c51f124SMoriah Waterland 		}
4565c51f124SMoriah Waterland 
4575c51f124SMoriah Waterland 		/* at least 1 byte read: expand buffer if at end */
4585c51f124SMoriah Waterland 
4595c51f124SMoriah Waterland 		bufferIndex += bytesRead;
4605c51f124SMoriah Waterland 		if (bufferIndex >= bufferSize) {
4615c51f124SMoriah Waterland 			buffer = realloc(buffer,
462*3970c098SToomas Soome 			    bufferSize += PIPE_BUFFER_INCREMENT);
4635c51f124SMoriah Waterland 			(void) memset(buffer + bufferIndex, 0,
464*3970c098SToomas Soome 			    bufferSize - bufferIndex);
4655c51f124SMoriah Waterland 		}
4665c51f124SMoriah Waterland 	}
4675c51f124SMoriah Waterland 
4685c51f124SMoriah Waterland 	(void) close(ipipe[0]);		/* Close read side of pipe */
4695c51f124SMoriah Waterland 
4705c51f124SMoriah Waterland 	/* Get subprocess exit status */
4715c51f124SMoriah Waterland 
4725c51f124SMoriah Waterland 	for (;;) {
4735c51f124SMoriah Waterland 		resultPid = waitpid(pid, &status, 0L);
4745c51f124SMoriah Waterland 		lerrno = (resultPid == -1 ? errno : 0);
4755c51f124SMoriah Waterland 
4765c51f124SMoriah Waterland 		/* break loop if child process status reaped */
4775c51f124SMoriah Waterland 
4785c51f124SMoriah Waterland 		if (resultPid != -1) {
4795c51f124SMoriah Waterland 			break;
4805c51f124SMoriah Waterland 		}
4815c51f124SMoriah Waterland 
4825c51f124SMoriah Waterland 		/* break loop if not interrupted out of waitpid */
4835c51f124SMoriah Waterland 
4845c51f124SMoriah Waterland 		if (errno != EINTR) {
4855c51f124SMoriah Waterland 			break;
4865c51f124SMoriah Waterland 		}
4875c51f124SMoriah Waterland 	}
4885c51f124SMoriah Waterland 
4895c51f124SMoriah Waterland 	/*
4905c51f124SMoriah Waterland 	 * If the child process terminated due to a call to exit(), then
4915c51f124SMoriah Waterland 	 * set results equal to the 8-bit exit status of the child process;
4925c51f124SMoriah Waterland 	 * otherwise, set the exit status to "-1" indicating that the child
4935c51f124SMoriah Waterland 	 * exited via a signal.
4945c51f124SMoriah Waterland 	 */
4955c51f124SMoriah Waterland 
4965c51f124SMoriah Waterland 	*r_status = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
4975c51f124SMoriah Waterland 
4985c51f124SMoriah Waterland 	/* return appropriate output */
4995c51f124SMoriah Waterland 
5005c51f124SMoriah Waterland 	if (!*buffer) {
5015c51f124SMoriah Waterland 		/* No contents in output buffer - discard */
5025c51f124SMoriah Waterland 		free(buffer);
5035c51f124SMoriah Waterland 	} else if (r_results == (char **)NULL) {
5045c51f124SMoriah Waterland 		/* Not requested to return results - discard */
5055c51f124SMoriah Waterland 		free(buffer);
5065c51f124SMoriah Waterland 	} else {
5075c51f124SMoriah Waterland 		/* have output and request to return: pass to calling method */
5085c51f124SMoriah Waterland 		*r_results = buffer;
5095c51f124SMoriah Waterland 	}
5105c51f124SMoriah Waterland 
5115c51f124SMoriah Waterland 	errno = lerrno;
5125c51f124SMoriah Waterland 	return (resultPid == -1 ? -1 : 0);
5135c51f124SMoriah Waterland }
5145c51f124SMoriah Waterland 
5155c51f124SMoriah Waterland /*
5165c51f124SMoriah Waterland  * Name:	e_ExecCmdList
5175c51f124SMoriah Waterland  * Synopsis:	Execute Unix command and return results
5185c51f124SMoriah Waterland  * Description:	Execute a Unix command and return results and status
5195c51f124SMoriah Waterland  * Arguments:
5205c51f124SMoriah Waterland  *		r_status - [RO, *RW] - (int *)
5215c51f124SMoriah Waterland  *			Return (exit) status from Unix command
5225c51f124SMoriah Waterland  *		r_results - [RO, *RW] - (char **)
5235c51f124SMoriah Waterland  *			Any output generated by the Unix command to stdout
5245c51f124SMoriah Waterland  *			and to stderr
5255c51f124SMoriah Waterland  *			== (char *)NULL if no output generated
5265c51f124SMoriah Waterland  *		a_inputFile - [RO, *RO] - (char *)
5275c51f124SMoriah Waterland  *			Pointer to character string representing file to be
5285c51f124SMoriah Waterland  *			used as "standard input" for the command.
5295c51f124SMoriah Waterland  *			== (char *)NULL to use "/dev/null" as standard input
5305c51f124SMoriah Waterland  *		a_cmd - [RO, *RO] - (char *)
5315c51f124SMoriah Waterland  *			Pointer to character string representing the full path
5325c51f124SMoriah Waterland  *			of the Unix command to execute
5335c51f124SMoriah Waterland  *		... - [RO] (?)
5345c51f124SMoriah Waterland  *			Zero or more arguments to the Unix command
5355c51f124SMoriah Waterland  *			The argument list must be ended with (void *)NULL
5365c51f124SMoriah Waterland  * Returns:	int
5375c51f124SMoriah Waterland  *			== 0 - Command executed
5385c51f124SMoriah Waterland  *				Look at r_status for results of Unix command
5395c51f124SMoriah Waterland  *			!= 0 - problems executing command
5405c51f124SMoriah Waterland  *				r_status and r_results have no meaning
541*3970c098SToomas Soome  * NOTE:	Any results returned is placed in new storage for the
5425c51f124SMoriah Waterland  *		calling method. The caller must use 'free' to dispose
5435c51f124SMoriah Waterland  *		of the storage once the results are no longer needed.
5445c51f124SMoriah Waterland  * NOTE:	If LU_SUCCESS is returned, 'r_status' must be queried to
5455c51f124SMoriah Waterland  *		determine the results of the Unix command.
5465c51f124SMoriah Waterland  */
5475c51f124SMoriah Waterland 
5485c51f124SMoriah Waterland int
e_ExecCmdList(int * r_status,char ** r_results,char * a_inputFile,char * a_cmd,...)5495c51f124SMoriah Waterland e_ExecCmdList(int *r_status, char **r_results,
550*3970c098SToomas Soome     char *a_inputFile, char *a_cmd, ...)
5515c51f124SMoriah Waterland {
5525c51f124SMoriah Waterland 	va_list		ap;		/* references variable argument list */
5535c51f124SMoriah Waterland 	char		*array[MAX_EXEC_CMD_ARGS+1];
5545c51f124SMoriah Waterland 	int		argno = 0;
5555c51f124SMoriah Waterland 
5565c51f124SMoriah Waterland 	/*
5575c51f124SMoriah Waterland 	 * Create argument array for exec system call
5585c51f124SMoriah Waterland 	 */
5595c51f124SMoriah Waterland 
5605c51f124SMoriah Waterland 	bzero(array, sizeof (array));
5615c51f124SMoriah Waterland 
5625c51f124SMoriah Waterland 	va_start(ap, a_cmd);	/* Begin variable argument processing */
5635c51f124SMoriah Waterland 
5645c51f124SMoriah Waterland 	for (argno = 0; argno < MAX_EXEC_CMD_ARGS; argno++) {
5655c51f124SMoriah Waterland 		array[argno] = va_arg(ap, char *);
5665c51f124SMoriah Waterland 		if (array[argno] == (char *)NULL) {
5675c51f124SMoriah Waterland 			break;
5685c51f124SMoriah Waterland 		}
5695c51f124SMoriah Waterland 	}
5705c51f124SMoriah Waterland 
5715c51f124SMoriah Waterland 	va_end(ap);
572*3970c098SToomas Soome 	return (e_ExecCmdArray(r_status, r_results, a_inputFile, a_cmd, array));
5735c51f124SMoriah Waterland }
574