xref: /titanic_53/usr/src/lib/libpkg/common/runcmd.c (revision 5c51f1241dbbdf2656d0e10011981411ed0c9673)
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 2009 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 
32*5c51f124SMoriah Waterland #include <stdio.h>
33*5c51f124SMoriah Waterland #include <errno.h>
34*5c51f124SMoriah Waterland #include <string.h>
35*5c51f124SMoriah Waterland #include <strings.h>
36*5c51f124SMoriah Waterland #include <signal.h>
37*5c51f124SMoriah Waterland #include <fcntl.h>
38*5c51f124SMoriah Waterland #include <stdlib.h>
39*5c51f124SMoriah Waterland #include <unistd.h>
40*5c51f124SMoriah Waterland #include <wait.h>
41*5c51f124SMoriah Waterland #include <sys/types.h>
42*5c51f124SMoriah Waterland #include "pkglib.h"
43*5c51f124SMoriah Waterland #include "pkglocale.h"
44*5c51f124SMoriah Waterland #include "pkglibmsgs.h"
45*5c51f124SMoriah Waterland 
46*5c51f124SMoriah Waterland #ifndef _STDARG_H
47*5c51f124SMoriah Waterland #include "stdarg.h"
48*5c51f124SMoriah Waterland #endif
49*5c51f124SMoriah Waterland 
50*5c51f124SMoriah Waterland /*
51*5c51f124SMoriah Waterland  * Private definitions
52*5c51f124SMoriah Waterland  */
53*5c51f124SMoriah Waterland 
54*5c51f124SMoriah Waterland /* Maximum number of arguments to pkg_ExecCmdList */
55*5c51f124SMoriah Waterland 
56*5c51f124SMoriah Waterland #define	MAX_EXEC_CMD_ARGS	100
57*5c51f124SMoriah Waterland 
58*5c51f124SMoriah Waterland /* Size of buffer increments when reading from pipe */
59*5c51f124SMoriah Waterland 
60*5c51f124SMoriah Waterland #define	PIPE_BUFFER_INCREMENT	256
61*5c51f124SMoriah Waterland 
62*5c51f124SMoriah Waterland static char	errfile[L_tmpnam+1];
63*5c51f124SMoriah Waterland 
64*5c51f124SMoriah Waterland /*
65*5c51f124SMoriah Waterland  * This is the "argument array" definition that is returned by e_new_args and is
66*5c51f124SMoriah Waterland  * used by e_add_args, e_free_args, etc.
67*5c51f124SMoriah Waterland  */
68*5c51f124SMoriah Waterland 
69*5c51f124SMoriah Waterland struct _argArray_t {
70*5c51f124SMoriah Waterland 	long	_aaNumArgs;	/* number of arguments set */
71*5c51f124SMoriah Waterland 	long	_aaMaxArgs;	/* number of arguments allocated */
72*5c51f124SMoriah Waterland 	char	**_aaArgs;	/* actual arguments */
73*5c51f124SMoriah Waterland };
74*5c51f124SMoriah Waterland 
75*5c51f124SMoriah Waterland typedef struct _argArray_t argArray_t;
76*5c51f124SMoriah Waterland 
77*5c51f124SMoriah Waterland /*
78*5c51f124SMoriah Waterland  * Private Methods
79*5c51f124SMoriah Waterland  */
80*5c51f124SMoriah Waterland static void		e_free_args(argArray_t *a_args);
81*5c51f124SMoriah Waterland static argArray_t	*e_new_args(int initialCount);
82*5c51f124SMoriah Waterland /*PRINTFLIKE2*/
83*5c51f124SMoriah Waterland static boolean_t	e_add_arg(argArray_t *a_args, char *a_format, ...);
84*5c51f124SMoriah Waterland static int		e_get_argc(argArray_t *a_args);
85*5c51f124SMoriah Waterland static char		**e_get_argv(argArray_t *a_args);
86*5c51f124SMoriah Waterland 
87*5c51f124SMoriah Waterland 
88*5c51f124SMoriah Waterland /*
89*5c51f124SMoriah Waterland  * Public Methods
90*5c51f124SMoriah Waterland  */
91*5c51f124SMoriah Waterland 
92*5c51f124SMoriah Waterland 
93*5c51f124SMoriah Waterland void
94*5c51f124SMoriah Waterland rpterr(void)
95*5c51f124SMoriah Waterland {
96*5c51f124SMoriah Waterland 	FILE	*fp;
97*5c51f124SMoriah Waterland 	int	c;
98*5c51f124SMoriah Waterland 
99*5c51f124SMoriah Waterland 	if (errfile[0]) {
100*5c51f124SMoriah Waterland 		if (fp = fopen(errfile, "r")) {
101*5c51f124SMoriah Waterland 			while ((c = getc(fp)) != EOF)
102*5c51f124SMoriah Waterland 				putc(c, stderr);
103*5c51f124SMoriah Waterland 			(void) fclose(fp);
104*5c51f124SMoriah Waterland 		}
105*5c51f124SMoriah Waterland 		(void) unlink(errfile);
106*5c51f124SMoriah Waterland 		errfile[0] = '\0';
107*5c51f124SMoriah Waterland 	}
108*5c51f124SMoriah Waterland }
109*5c51f124SMoriah Waterland 
110*5c51f124SMoriah Waterland void
111*5c51f124SMoriah Waterland ecleanup(void)
112*5c51f124SMoriah Waterland {
113*5c51f124SMoriah Waterland 	if (errfile[0]) {
114*5c51f124SMoriah Waterland 		(void) unlink(errfile);
115*5c51f124SMoriah Waterland 		errfile[0] = NULL;
116*5c51f124SMoriah Waterland 	}
117*5c51f124SMoriah Waterland }
118*5c51f124SMoriah Waterland 
119*5c51f124SMoriah Waterland int
120*5c51f124SMoriah Waterland esystem(char *cmd, int ifd, int ofd)
121*5c51f124SMoriah Waterland {
122*5c51f124SMoriah Waterland 	char	*perrfile;
123*5c51f124SMoriah Waterland 	int	status = 0;
124*5c51f124SMoriah Waterland 	pid_t	pid;
125*5c51f124SMoriah Waterland 
126*5c51f124SMoriah Waterland 	perrfile = tmpnam(NULL);
127*5c51f124SMoriah Waterland 	if (perrfile == NULL) {
128*5c51f124SMoriah Waterland 		progerr(
129*5c51f124SMoriah Waterland 		    pkg_gt("unable to create temp error file, errno=%d"),
130*5c51f124SMoriah Waterland 		    errno);
131*5c51f124SMoriah Waterland 		return (-1);
132*5c51f124SMoriah Waterland 	}
133*5c51f124SMoriah Waterland 	(void) strlcpy(errfile, perrfile, sizeof (errfile));
134*5c51f124SMoriah Waterland 
135*5c51f124SMoriah Waterland 	/* flush standard i/o before creating new process */
136*5c51f124SMoriah Waterland 
137*5c51f124SMoriah Waterland 	(void) fflush(stderr);
138*5c51f124SMoriah Waterland 	(void) fflush(stdout);
139*5c51f124SMoriah Waterland 
140*5c51f124SMoriah Waterland 	/*
141*5c51f124SMoriah Waterland 	 * create new process to execute command in;
142*5c51f124SMoriah Waterland 	 * vfork() is being used to avoid duplicating the parents
143*5c51f124SMoriah Waterland 	 * memory space - this means that the child process may
144*5c51f124SMoriah Waterland 	 * not modify any of the parents memory including the
145*5c51f124SMoriah Waterland 	 * standard i/o descriptors - all the child can do is
146*5c51f124SMoriah Waterland 	 * adjust interrupts and open files as a prelude to a
147*5c51f124SMoriah Waterland 	 * call to exec().
148*5c51f124SMoriah Waterland 	 */
149*5c51f124SMoriah Waterland 
150*5c51f124SMoriah Waterland 	pid = vfork();
151*5c51f124SMoriah Waterland 	if (pid == 0) {
152*5c51f124SMoriah Waterland 		/*
153*5c51f124SMoriah Waterland 		 * this is the child process
154*5c51f124SMoriah Waterland 		 */
155*5c51f124SMoriah Waterland 		int	i;
156*5c51f124SMoriah Waterland 
157*5c51f124SMoriah Waterland 		/* reset any signals to default */
158*5c51f124SMoriah Waterland 
159*5c51f124SMoriah Waterland 		for (i = 0; i < NSIG; i++) {
160*5c51f124SMoriah Waterland 			(void) sigset(i, SIG_DFL);
161*5c51f124SMoriah Waterland 		}
162*5c51f124SMoriah Waterland 
163*5c51f124SMoriah Waterland 		if (ifd > 0) {
164*5c51f124SMoriah Waterland 			(void) dup2(ifd, STDIN_FILENO);
165*5c51f124SMoriah Waterland 		}
166*5c51f124SMoriah Waterland 
167*5c51f124SMoriah Waterland 		if (ofd >= 0 && ofd != STDOUT_FILENO) {
168*5c51f124SMoriah Waterland 			(void) dup2(ofd, STDOUT_FILENO);
169*5c51f124SMoriah Waterland 		}
170*5c51f124SMoriah Waterland 
171*5c51f124SMoriah Waterland 		i = open(errfile, O_WRONLY|O_CREAT|O_TRUNC, 0666);
172*5c51f124SMoriah Waterland 		if (i >= 0) {
173*5c51f124SMoriah Waterland 			dup2(i, STDERR_FILENO);
174*5c51f124SMoriah Waterland 		}
175*5c51f124SMoriah Waterland 
176*5c51f124SMoriah Waterland 		/* Close all open files except standard i/o */
177*5c51f124SMoriah Waterland 
178*5c51f124SMoriah Waterland 		closefrom(3);
179*5c51f124SMoriah Waterland 
180*5c51f124SMoriah Waterland 		/* execute target executable */
181*5c51f124SMoriah Waterland 
182*5c51f124SMoriah Waterland 		execl("/sbin/sh", "/sbin/sh", "-c", cmd, NULL);
183*5c51f124SMoriah Waterland 		progerr(pkg_gt("exec of <%s> failed, errno=%d"), cmd, errno);
184*5c51f124SMoriah Waterland 		_exit(99);
185*5c51f124SMoriah Waterland 	} else if (pid < 0) {
186*5c51f124SMoriah Waterland 		/* fork failed! */
187*5c51f124SMoriah Waterland 
188*5c51f124SMoriah Waterland 		logerr(pkg_gt("bad vfork(), errno=%d"), errno);
189*5c51f124SMoriah Waterland 		return (-1);
190*5c51f124SMoriah Waterland 	}
191*5c51f124SMoriah Waterland 
192*5c51f124SMoriah Waterland 	/*
193*5c51f124SMoriah Waterland 	 * this is the parent process
194*5c51f124SMoriah Waterland 	 */
195*5c51f124SMoriah Waterland 
196*5c51f124SMoriah Waterland 	sighold(SIGINT);
197*5c51f124SMoriah Waterland 	pid = waitpid(pid, &status, 0);
198*5c51f124SMoriah Waterland 	sigrelse(SIGINT);
199*5c51f124SMoriah Waterland 
200*5c51f124SMoriah Waterland 	if (pid < 0) {
201*5c51f124SMoriah Waterland 		return (-1); /* probably interrupted */
202*5c51f124SMoriah Waterland 	}
203*5c51f124SMoriah Waterland 
204*5c51f124SMoriah Waterland 	switch (status & 0177) {
205*5c51f124SMoriah Waterland 		case 0:
206*5c51f124SMoriah Waterland 		case 0177:
207*5c51f124SMoriah Waterland 			status = status >> 8;
208*5c51f124SMoriah Waterland 			/*FALLTHROUGH*/
209*5c51f124SMoriah Waterland 
210*5c51f124SMoriah Waterland 		default:
211*5c51f124SMoriah Waterland 			/* terminated by a signal */
212*5c51f124SMoriah Waterland 			status = status & 0177;
213*5c51f124SMoriah Waterland 	}
214*5c51f124SMoriah Waterland 
215*5c51f124SMoriah Waterland 	if (status == 0) {
216*5c51f124SMoriah Waterland 		ecleanup();
217*5c51f124SMoriah Waterland 	}
218*5c51f124SMoriah Waterland 
219*5c51f124SMoriah Waterland 	return (status);
220*5c51f124SMoriah Waterland }
221*5c51f124SMoriah Waterland 
222*5c51f124SMoriah Waterland FILE *
223*5c51f124SMoriah Waterland epopen(char *cmd, char *mode)
224*5c51f124SMoriah Waterland {
225*5c51f124SMoriah Waterland 	char	*buffer, *perrfile;
226*5c51f124SMoriah Waterland 	FILE	*pp;
227*5c51f124SMoriah Waterland 	size_t	len;
228*5c51f124SMoriah Waterland 	size_t	alen;
229*5c51f124SMoriah Waterland 
230*5c51f124SMoriah Waterland 	if (errfile[0]) {
231*5c51f124SMoriah Waterland 		/* cleanup previous errfile */
232*5c51f124SMoriah Waterland 		unlink(errfile);
233*5c51f124SMoriah Waterland 	}
234*5c51f124SMoriah Waterland 
235*5c51f124SMoriah Waterland 	perrfile = tmpnam(NULL);
236*5c51f124SMoriah Waterland 	if (perrfile == NULL) {
237*5c51f124SMoriah Waterland 		progerr(
238*5c51f124SMoriah Waterland 		    pkg_gt("unable to create temp error file, errno=%d"),
239*5c51f124SMoriah Waterland 		    errno);
240*5c51f124SMoriah Waterland 		return ((FILE *)0);
241*5c51f124SMoriah Waterland 	}
242*5c51f124SMoriah Waterland 
243*5c51f124SMoriah Waterland 	if (strlcpy(errfile, perrfile, sizeof (errfile)) > sizeof (errfile)) {
244*5c51f124SMoriah Waterland 		progerr(pkg_gt("file name max length %d; name is too long: %s"),
245*5c51f124SMoriah Waterland 						sizeof (errfile), perrfile);
246*5c51f124SMoriah Waterland 		return ((FILE *)0);
247*5c51f124SMoriah Waterland 	}
248*5c51f124SMoriah Waterland 
249*5c51f124SMoriah Waterland 	len = strlen(cmd)+6+strlen(errfile);
250*5c51f124SMoriah Waterland 	buffer = (char *)calloc(len, sizeof (char));
251*5c51f124SMoriah Waterland 	if (buffer == NULL) {
252*5c51f124SMoriah Waterland 		progerr(pkg_gt("no memory in epopen(), errno=%d"), errno);
253*5c51f124SMoriah Waterland 		return ((FILE *)0);
254*5c51f124SMoriah Waterland 	}
255*5c51f124SMoriah Waterland 
256*5c51f124SMoriah Waterland 	if (strchr(cmd, '|')) {
257*5c51f124SMoriah Waterland 		alen = snprintf(buffer, len, "(%s) 2>%s", cmd, errfile);
258*5c51f124SMoriah Waterland 	} else {
259*5c51f124SMoriah Waterland 		alen = snprintf(buffer, len, "%s 2>%s", cmd, errfile);
260*5c51f124SMoriah Waterland 	}
261*5c51f124SMoriah Waterland 
262*5c51f124SMoriah Waterland 	if (alen > len) {
263*5c51f124SMoriah Waterland 		progerr(pkg_gt("command max length %d; cmd is too long: %s"),
264*5c51f124SMoriah Waterland 								len, cmd);
265*5c51f124SMoriah Waterland 		return ((FILE *)0);
266*5c51f124SMoriah Waterland 	}
267*5c51f124SMoriah Waterland 
268*5c51f124SMoriah Waterland 	pp = popen(buffer, mode);
269*5c51f124SMoriah Waterland 
270*5c51f124SMoriah Waterland 	free(buffer);
271*5c51f124SMoriah Waterland 	return (pp);
272*5c51f124SMoriah Waterland }
273*5c51f124SMoriah Waterland 
274*5c51f124SMoriah Waterland int
275*5c51f124SMoriah Waterland epclose(FILE *pp)
276*5c51f124SMoriah Waterland {
277*5c51f124SMoriah Waterland 	int n;
278*5c51f124SMoriah Waterland 
279*5c51f124SMoriah Waterland 	n = pclose(pp);
280*5c51f124SMoriah Waterland 	if (n == 0)
281*5c51f124SMoriah Waterland 		ecleanup();
282*5c51f124SMoriah Waterland 	return (n);
283*5c51f124SMoriah Waterland }
284*5c51f124SMoriah Waterland 
285*5c51f124SMoriah Waterland /*
286*5c51f124SMoriah Waterland  * Name:	e_ExecCmdArray
287*5c51f124SMoriah Waterland  * Synopsis:	Execute Unix command and return results
288*5c51f124SMoriah Waterland  * Description:	Execute a Unix command and return results and status
289*5c51f124SMoriah Waterland  * Arguments:
290*5c51f124SMoriah Waterland  *		r_status - [RO, *RW] - (int *)
291*5c51f124SMoriah Waterland  *			Return (exit) status from Unix command:
292*5c51f124SMoriah Waterland  *			== -1 : child terminated with a signal
293*5c51f124SMoriah Waterland  *			!= -1 : lower 8-bit value child passed to exit()
294*5c51f124SMoriah Waterland  *		r_results - [RO, *RW] - (char **)
295*5c51f124SMoriah Waterland  *			Any output generated by the Unix command to stdout
296*5c51f124SMoriah Waterland  *			and to stderr
297*5c51f124SMoriah Waterland  *			== (char *)NULL if no output generated
298*5c51f124SMoriah Waterland  *		a_inputFile - [RO, *RO] - (char *)
299*5c51f124SMoriah Waterland  *			Pointer to character string representing file to be
300*5c51f124SMoriah Waterland  *			used as "standard input" for the command.
301*5c51f124SMoriah Waterland  *			== (char *)NULL to use "/dev/null" as standard input
302*5c51f124SMoriah Waterland  *		a_cmd - [RO, *RO] - (char *)
303*5c51f124SMoriah Waterland  *			Pointer to character string representing the full path
304*5c51f124SMoriah Waterland  *			of the Unix command to execute
305*5c51f124SMoriah Waterland  *		char **a_args - [RO, *RO] - (char **)
306*5c51f124SMoriah Waterland  *			List of character strings representing the arguments
307*5c51f124SMoriah Waterland  *			to be passed to the Unix command. The list must be
308*5c51f124SMoriah Waterland  *			terminated with an element that is (char *)NULL
309*5c51f124SMoriah Waterland  * Returns:	int
310*5c51f124SMoriah Waterland  *			== 0 - Command executed
311*5c51f124SMoriah Waterland  *				Look at r_status for results of Unix command
312*5c51f124SMoriah Waterland  *			!= 0 - problems executing command
313*5c51f124SMoriah Waterland  *				r_status and r_results have no meaning;
314*5c51f124SMoriah Waterland  *				r_status will be -1
315*5c51f124SMoriah Waterland  *				r_results will be NULL
316*5c51f124SMoriah Waterland  * NOTE:    	Any results returned is placed in new storage for the
317*5c51f124SMoriah Waterland  *		calling method. The caller must use 'free' to dispose
318*5c51f124SMoriah Waterland  *		of the storage once the results are no longer needed.
319*5c51f124SMoriah Waterland  * NOTE:	If 0 is returned, 'r_status' must be queried to
320*5c51f124SMoriah Waterland  *		determine the results of the Unix command.
321*5c51f124SMoriah Waterland  * NOTE:	The system "errno" value from immediately after waitpid() call
322*5c51f124SMoriah Waterland  *		is preserved for the calling method to use to determine
323*5c51f124SMoriah Waterland  *		the system reason why the operation failed.
324*5c51f124SMoriah Waterland  */
325*5c51f124SMoriah Waterland 
326*5c51f124SMoriah Waterland int
327*5c51f124SMoriah Waterland e_ExecCmdArray(int *r_status, char **r_results,
328*5c51f124SMoriah Waterland 	char *a_inputFile, char *a_cmd, char **a_args)
329*5c51f124SMoriah Waterland {
330*5c51f124SMoriah Waterland 	char		*buffer;
331*5c51f124SMoriah Waterland 	int		bufferIndex;
332*5c51f124SMoriah Waterland 	int		bufferSize;
333*5c51f124SMoriah Waterland 	int		ipipe[2] = {0, 0};
334*5c51f124SMoriah Waterland 	pid_t		pid;
335*5c51f124SMoriah Waterland 	pid_t		resultPid;
336*5c51f124SMoriah Waterland 	int		status;
337*5c51f124SMoriah Waterland 	int		lerrno;
338*5c51f124SMoriah Waterland 	int		stdinfile = -1;
339*5c51f124SMoriah Waterland 
340*5c51f124SMoriah Waterland 	/* reset return results buffer pointer */
341*5c51f124SMoriah Waterland 
342*5c51f124SMoriah Waterland 	if (r_results != (char **)NULL) {
343*5c51f124SMoriah Waterland 		*r_results = (char *)NULL;
344*5c51f124SMoriah Waterland 	}
345*5c51f124SMoriah Waterland 
346*5c51f124SMoriah Waterland 	*r_status = -1;
347*5c51f124SMoriah Waterland 
348*5c51f124SMoriah Waterland 	/*
349*5c51f124SMoriah Waterland 	 * See if command exists
350*5c51f124SMoriah Waterland 	 */
351*5c51f124SMoriah Waterland 
352*5c51f124SMoriah Waterland 	if (access(a_cmd, F_OK|X_OK) != 0) {
353*5c51f124SMoriah Waterland 		return (-1);
354*5c51f124SMoriah Waterland 	}
355*5c51f124SMoriah Waterland 
356*5c51f124SMoriah Waterland 	/*
357*5c51f124SMoriah Waterland 	 * See if input file exists
358*5c51f124SMoriah Waterland 	 */
359*5c51f124SMoriah Waterland 
360*5c51f124SMoriah Waterland 	if (a_inputFile != (char *)NULL) {
361*5c51f124SMoriah Waterland 		stdinfile = open(a_inputFile, O_RDONLY);
362*5c51f124SMoriah Waterland 	} else {
363*5c51f124SMoriah Waterland 		stdinfile = open("/dev/null", O_RDONLY); /* stdin = /dev/null */
364*5c51f124SMoriah Waterland 	}
365*5c51f124SMoriah Waterland 
366*5c51f124SMoriah Waterland 	if (stdinfile < 0) {
367*5c51f124SMoriah Waterland 		return (-1);
368*5c51f124SMoriah Waterland 	}
369*5c51f124SMoriah Waterland 
370*5c51f124SMoriah Waterland 	/*
371*5c51f124SMoriah Waterland 	 * Create a pipe to be used to capture the command output
372*5c51f124SMoriah Waterland 	 */
373*5c51f124SMoriah Waterland 
374*5c51f124SMoriah Waterland 	if (pipe(ipipe) != 0) {
375*5c51f124SMoriah Waterland 		(void) close(stdinfile);
376*5c51f124SMoriah Waterland 		return (-1);
377*5c51f124SMoriah Waterland 	}
378*5c51f124SMoriah Waterland 
379*5c51f124SMoriah Waterland 
380*5c51f124SMoriah Waterland 	bufferSize = PIPE_BUFFER_INCREMENT;
381*5c51f124SMoriah Waterland 	bufferIndex = 0;
382*5c51f124SMoriah Waterland 	buffer = calloc(1, bufferSize);
383*5c51f124SMoriah Waterland 	if (buffer == (char *)NULL) {
384*5c51f124SMoriah Waterland 		(void) close(stdinfile);
385*5c51f124SMoriah Waterland 		return (-1);
386*5c51f124SMoriah Waterland 	}
387*5c51f124SMoriah Waterland 
388*5c51f124SMoriah Waterland 	/* flush standard i/o before creating new process */
389*5c51f124SMoriah Waterland 
390*5c51f124SMoriah Waterland 	(void) fflush(stderr);
391*5c51f124SMoriah Waterland 	(void) fflush(stdout);
392*5c51f124SMoriah Waterland 
393*5c51f124SMoriah Waterland 	/*
394*5c51f124SMoriah Waterland 	 * create new process to execute command in;
395*5c51f124SMoriah Waterland 	 * vfork() is being used to avoid duplicating the parents
396*5c51f124SMoriah Waterland 	 * memory space - this means that the child process may
397*5c51f124SMoriah Waterland 	 * not modify any of the parents memory including the
398*5c51f124SMoriah Waterland 	 * standard i/o descriptors - all the child can do is
399*5c51f124SMoriah Waterland 	 * adjust interrupts and open files as a prelude to a
400*5c51f124SMoriah Waterland 	 * call to exec().
401*5c51f124SMoriah Waterland 	 */
402*5c51f124SMoriah Waterland 
403*5c51f124SMoriah Waterland 	pid = vfork();
404*5c51f124SMoriah Waterland 
405*5c51f124SMoriah Waterland 	if (pid == 0) {
406*5c51f124SMoriah Waterland 		/*
407*5c51f124SMoriah Waterland 		 * This is the forked (child) process ======================
408*5c51f124SMoriah Waterland 		 */
409*5c51f124SMoriah Waterland 
410*5c51f124SMoriah Waterland 		int	i;
411*5c51f124SMoriah Waterland 
412*5c51f124SMoriah Waterland 		/* reset any signals to default */
413*5c51f124SMoriah Waterland 
414*5c51f124SMoriah Waterland 		for (i = 0; i < NSIG; i++) {
415*5c51f124SMoriah Waterland 			(void) sigset(i, SIG_DFL);
416*5c51f124SMoriah Waterland 		}
417*5c51f124SMoriah Waterland 
418*5c51f124SMoriah Waterland 		/* assign stdin, stdout, stderr as appropriate */
419*5c51f124SMoriah Waterland 
420*5c51f124SMoriah Waterland 		(void) dup2(stdinfile, STDIN_FILENO);
421*5c51f124SMoriah Waterland 		(void) close(ipipe[0]);		/* close out pipe reader side */
422*5c51f124SMoriah Waterland 		(void) dup2(ipipe[1], STDOUT_FILENO);
423*5c51f124SMoriah Waterland 		(void) dup2(ipipe[1], STDERR_FILENO);
424*5c51f124SMoriah Waterland 
425*5c51f124SMoriah Waterland 		/* Close all open files except standard i/o */
426*5c51f124SMoriah Waterland 
427*5c51f124SMoriah Waterland 		closefrom(3);
428*5c51f124SMoriah Waterland 
429*5c51f124SMoriah Waterland 		/* execute target executable */
430*5c51f124SMoriah Waterland 
431*5c51f124SMoriah Waterland 		(void) execvp(a_cmd, a_args);
432*5c51f124SMoriah Waterland 		perror(a_cmd);	/* Emit error msg - ends up in callers buffer */
433*5c51f124SMoriah Waterland 		_exit(0x00FE);
434*5c51f124SMoriah Waterland 	}
435*5c51f124SMoriah Waterland 
436*5c51f124SMoriah Waterland 	/*
437*5c51f124SMoriah Waterland 	 * This is the forking (parent) process ====================
438*5c51f124SMoriah Waterland 	 */
439*5c51f124SMoriah Waterland 
440*5c51f124SMoriah Waterland 	(void) close(stdinfile);
441*5c51f124SMoriah Waterland 	(void) close(ipipe[1]);		/* Close write side of pipe */
442*5c51f124SMoriah Waterland 
443*5c51f124SMoriah Waterland 	/*
444*5c51f124SMoriah Waterland 	 * Spin reading data from the child into the buffer - when the read eofs
445*5c51f124SMoriah Waterland 	 * the child has exited
446*5c51f124SMoriah Waterland 	 */
447*5c51f124SMoriah Waterland 
448*5c51f124SMoriah Waterland 	for (;;) {
449*5c51f124SMoriah Waterland 		ssize_t	bytesRead;
450*5c51f124SMoriah Waterland 
451*5c51f124SMoriah Waterland 		/* read as much child data as there is available buffer space */
452*5c51f124SMoriah Waterland 
453*5c51f124SMoriah Waterland 		bytesRead = read(ipipe[0], buffer + bufferIndex,
454*5c51f124SMoriah Waterland 						bufferSize - bufferIndex);
455*5c51f124SMoriah Waterland 
456*5c51f124SMoriah Waterland 		/* break out of read loop if end-of-file encountered */
457*5c51f124SMoriah Waterland 
458*5c51f124SMoriah Waterland 		if (bytesRead == 0) {
459*5c51f124SMoriah Waterland 			break;
460*5c51f124SMoriah Waterland 		}
461*5c51f124SMoriah Waterland 
462*5c51f124SMoriah Waterland 		/* if error, continue if recoverable, else break out of loop */
463*5c51f124SMoriah Waterland 
464*5c51f124SMoriah Waterland 		if (bytesRead == -1) {
465*5c51f124SMoriah Waterland 			/* try again: EAGAIN - insufficient resources */
466*5c51f124SMoriah Waterland 
467*5c51f124SMoriah Waterland 			if (errno == EAGAIN) {
468*5c51f124SMoriah Waterland 				continue;
469*5c51f124SMoriah Waterland 			}
470*5c51f124SMoriah Waterland 
471*5c51f124SMoriah Waterland 			/* try again: EINTR - interrupted system call */
472*5c51f124SMoriah Waterland 
473*5c51f124SMoriah Waterland 			if (errno == EINTR) {
474*5c51f124SMoriah Waterland 				continue;
475*5c51f124SMoriah Waterland 			}
476*5c51f124SMoriah Waterland 
477*5c51f124SMoriah Waterland 			/* break out of loop - error not recoverable */
478*5c51f124SMoriah Waterland 			break;
479*5c51f124SMoriah Waterland 		}
480*5c51f124SMoriah Waterland 
481*5c51f124SMoriah Waterland 		/* at least 1 byte read: expand buffer if at end */
482*5c51f124SMoriah Waterland 
483*5c51f124SMoriah Waterland 		bufferIndex += bytesRead;
484*5c51f124SMoriah Waterland 		if (bufferIndex >= bufferSize) {
485*5c51f124SMoriah Waterland 			buffer = realloc(buffer,
486*5c51f124SMoriah Waterland 					bufferSize += PIPE_BUFFER_INCREMENT);
487*5c51f124SMoriah Waterland 			(void) memset(buffer + bufferIndex, 0,
488*5c51f124SMoriah Waterland 				bufferSize - bufferIndex);
489*5c51f124SMoriah Waterland 		}
490*5c51f124SMoriah Waterland 	}
491*5c51f124SMoriah Waterland 
492*5c51f124SMoriah Waterland 	(void) close(ipipe[0]);		/* Close read side of pipe */
493*5c51f124SMoriah Waterland 
494*5c51f124SMoriah Waterland 	/* Get subprocess exit status */
495*5c51f124SMoriah Waterland 
496*5c51f124SMoriah Waterland 	for (;;) {
497*5c51f124SMoriah Waterland 		resultPid = waitpid(pid, &status, 0L);
498*5c51f124SMoriah Waterland 		lerrno = (resultPid == -1 ? errno : 0);
499*5c51f124SMoriah Waterland 
500*5c51f124SMoriah Waterland 		/* break loop if child process status reaped */
501*5c51f124SMoriah Waterland 
502*5c51f124SMoriah Waterland 		if (resultPid != -1) {
503*5c51f124SMoriah Waterland 			break;
504*5c51f124SMoriah Waterland 		}
505*5c51f124SMoriah Waterland 
506*5c51f124SMoriah Waterland 		/* break loop if not interrupted out of waitpid */
507*5c51f124SMoriah Waterland 
508*5c51f124SMoriah Waterland 		if (errno != EINTR) {
509*5c51f124SMoriah Waterland 			break;
510*5c51f124SMoriah Waterland 		}
511*5c51f124SMoriah Waterland 	}
512*5c51f124SMoriah Waterland 
513*5c51f124SMoriah Waterland 	/*
514*5c51f124SMoriah Waterland 	 * If the child process terminated due to a call to exit(), then
515*5c51f124SMoriah Waterland 	 * set results equal to the 8-bit exit status of the child process;
516*5c51f124SMoriah Waterland 	 * otherwise, set the exit status to "-1" indicating that the child
517*5c51f124SMoriah Waterland 	 * exited via a signal.
518*5c51f124SMoriah Waterland 	 */
519*5c51f124SMoriah Waterland 
520*5c51f124SMoriah Waterland 	*r_status = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
521*5c51f124SMoriah Waterland 
522*5c51f124SMoriah Waterland 	/* return appropriate output */
523*5c51f124SMoriah Waterland 
524*5c51f124SMoriah Waterland 	if (!*buffer) {
525*5c51f124SMoriah Waterland 		/* No contents in output buffer - discard */
526*5c51f124SMoriah Waterland 		free(buffer);
527*5c51f124SMoriah Waterland 	} else if (r_results == (char **)NULL) {
528*5c51f124SMoriah Waterland 		/* Not requested to return results - discard */
529*5c51f124SMoriah Waterland 		free(buffer);
530*5c51f124SMoriah Waterland 	} else {
531*5c51f124SMoriah Waterland 		/* have output and request to return: pass to calling method */
532*5c51f124SMoriah Waterland 		*r_results = buffer;
533*5c51f124SMoriah Waterland 	}
534*5c51f124SMoriah Waterland 
535*5c51f124SMoriah Waterland 	errno = lerrno;
536*5c51f124SMoriah Waterland 	return (resultPid == -1 ? -1 : 0);
537*5c51f124SMoriah Waterland }
538*5c51f124SMoriah Waterland 
539*5c51f124SMoriah Waterland /*
540*5c51f124SMoriah Waterland  * Name:	e_ExecCmdList
541*5c51f124SMoriah Waterland  * Synopsis:	Execute Unix command and return results
542*5c51f124SMoriah Waterland  * Description:	Execute a Unix command and return results and status
543*5c51f124SMoriah Waterland  * Arguments:
544*5c51f124SMoriah Waterland  *		r_status - [RO, *RW] - (int *)
545*5c51f124SMoriah Waterland  *			Return (exit) status from Unix command
546*5c51f124SMoriah Waterland  *		r_results - [RO, *RW] - (char **)
547*5c51f124SMoriah Waterland  *			Any output generated by the Unix command to stdout
548*5c51f124SMoriah Waterland  *			and to stderr
549*5c51f124SMoriah Waterland  *			== (char *)NULL if no output generated
550*5c51f124SMoriah Waterland  *		a_inputFile - [RO, *RO] - (char *)
551*5c51f124SMoriah Waterland  *			Pointer to character string representing file to be
552*5c51f124SMoriah Waterland  *			used as "standard input" for the command.
553*5c51f124SMoriah Waterland  *			== (char *)NULL to use "/dev/null" as standard input
554*5c51f124SMoriah Waterland  *		a_cmd - [RO, *RO] - (char *)
555*5c51f124SMoriah Waterland  *			Pointer to character string representing the full path
556*5c51f124SMoriah Waterland  *			of the Unix command to execute
557*5c51f124SMoriah Waterland  *		... - [RO] (?)
558*5c51f124SMoriah Waterland  *			Zero or more arguments to the Unix command
559*5c51f124SMoriah Waterland  *			The argument list must be ended with (void *)NULL
560*5c51f124SMoriah Waterland  * Returns:	int
561*5c51f124SMoriah Waterland  *			== 0 - Command executed
562*5c51f124SMoriah Waterland  *				Look at r_status for results of Unix command
563*5c51f124SMoriah Waterland  *			!= 0 - problems executing command
564*5c51f124SMoriah Waterland  *				r_status and r_results have no meaning
565*5c51f124SMoriah Waterland  * NOTE:    	Any results returned is placed in new storage for the
566*5c51f124SMoriah Waterland  *		calling method. The caller must use 'free' to dispose
567*5c51f124SMoriah Waterland  *		of the storage once the results are no longer needed.
568*5c51f124SMoriah Waterland  * NOTE:	If LU_SUCCESS is returned, 'r_status' must be queried to
569*5c51f124SMoriah Waterland  *		determine the results of the Unix command.
570*5c51f124SMoriah Waterland  */
571*5c51f124SMoriah Waterland 
572*5c51f124SMoriah Waterland int
573*5c51f124SMoriah Waterland e_ExecCmdList(int *r_status, char **r_results,
574*5c51f124SMoriah Waterland 	char *a_inputFile, char *a_cmd, ...)
575*5c51f124SMoriah Waterland {
576*5c51f124SMoriah Waterland 	va_list		ap;		/* references variable argument list */
577*5c51f124SMoriah Waterland 	char		*array[MAX_EXEC_CMD_ARGS+1];
578*5c51f124SMoriah Waterland 	int		argno = 0;
579*5c51f124SMoriah Waterland 
580*5c51f124SMoriah Waterland 	/*
581*5c51f124SMoriah Waterland 	 * Create argument array for exec system call
582*5c51f124SMoriah Waterland 	 */
583*5c51f124SMoriah Waterland 
584*5c51f124SMoriah Waterland 	bzero(array, sizeof (array));
585*5c51f124SMoriah Waterland 
586*5c51f124SMoriah Waterland 	va_start(ap, a_cmd);	/* Begin variable argument processing */
587*5c51f124SMoriah Waterland 
588*5c51f124SMoriah Waterland 	for (argno = 0; argno < MAX_EXEC_CMD_ARGS; argno++) {
589*5c51f124SMoriah Waterland 		array[argno] = va_arg(ap, char *);
590*5c51f124SMoriah Waterland 		if (array[argno] == (char *)NULL) {
591*5c51f124SMoriah Waterland 			break;
592*5c51f124SMoriah Waterland 		}
593*5c51f124SMoriah Waterland 	}
594*5c51f124SMoriah Waterland 
595*5c51f124SMoriah Waterland 	va_end(ap);
596*5c51f124SMoriah Waterland 	return (e_ExecCmdArray(r_status, r_results, a_inputFile,
597*5c51f124SMoriah Waterland 								a_cmd, array));
598*5c51f124SMoriah Waterland }
599*5c51f124SMoriah Waterland 
600*5c51f124SMoriah Waterland /*
601*5c51f124SMoriah Waterland  * Name:	e_new_args
602*5c51f124SMoriah Waterland  * Description:	create a new argument array for use in exec() calls
603*5c51f124SMoriah Waterland  * Arguments:	initialCount - [RO, *RO] - (int)
604*5c51f124SMoriah Waterland  *			Initial number of elements to populate the
605*5c51f124SMoriah Waterland  *			argument array with - use best guess
606*5c51f124SMoriah Waterland  * Returns:	argArray_t *
607*5c51f124SMoriah Waterland  *			Pointer to argument array that can be used in other
608*5c51f124SMoriah Waterland  *			functions that accept it as an argument
609*5c51f124SMoriah Waterland  *			== (argArray_t *)NULL - error
610*5c51f124SMoriah Waterland  * NOTE: you must call e_free_args() when the returned argument array is
611*5c51f124SMoriah Waterland  * no longer needed so that all storage used can be freed up.
612*5c51f124SMoriah Waterland  */
613*5c51f124SMoriah Waterland 
614*5c51f124SMoriah Waterland argArray_t *
615*5c51f124SMoriah Waterland e_new_args(int initialCount)
616*5c51f124SMoriah Waterland {
617*5c51f124SMoriah Waterland 	argArray_t	*aa;
618*5c51f124SMoriah Waterland 
619*5c51f124SMoriah Waterland 	/* allocate new argument array structure */
620*5c51f124SMoriah Waterland 
621*5c51f124SMoriah Waterland 	aa = (argArray_t *)calloc(1, sizeof (argArray_t));
622*5c51f124SMoriah Waterland 	if (aa == (argArray_t *)NULL) {
623*5c51f124SMoriah Waterland 		progerr(ERR_MALLOC, strerror(errno), sizeof (argArray_t),
624*5c51f124SMoriah Waterland 			"<argArray_t>");
625*5c51f124SMoriah Waterland 		return ((argArray_t *)NULL);
626*5c51f124SMoriah Waterland 	}
627*5c51f124SMoriah Waterland 
628*5c51f124SMoriah Waterland 	/* allocate initial argument array */
629*5c51f124SMoriah Waterland 
630*5c51f124SMoriah Waterland 	aa->_aaArgs = (char **)calloc(initialCount+1, sizeof (char *));
631*5c51f124SMoriah Waterland 	if (aa->_aaArgs == (char **)NULL) {
632*5c51f124SMoriah Waterland 		progerr(ERR_MALLOC, strerror(errno),
633*5c51f124SMoriah Waterland 			(initialCount+1)*sizeof (char *), "<char **>");
634*5c51f124SMoriah Waterland 		return ((argArray_t *)NULL);
635*5c51f124SMoriah Waterland 	}
636*5c51f124SMoriah Waterland 
637*5c51f124SMoriah Waterland 	/* initialize argument indexes */
638*5c51f124SMoriah Waterland 
639*5c51f124SMoriah Waterland 	aa->_aaNumArgs = 0;
640*5c51f124SMoriah Waterland 	aa->_aaMaxArgs = initialCount;
641*5c51f124SMoriah Waterland 
642*5c51f124SMoriah Waterland 	return (aa);
643*5c51f124SMoriah Waterland }
644*5c51f124SMoriah Waterland 
645*5c51f124SMoriah Waterland /*
646*5c51f124SMoriah Waterland  * Name:	e_add_arg
647*5c51f124SMoriah Waterland  * Description:	add new argument to argument array for use in exec() calls
648*5c51f124SMoriah Waterland  * Arguments:	a_args - [RO, *RW] - (argArray_t *)
649*5c51f124SMoriah Waterland  *			Pointer to argument array (previously allocated via
650*5c51f124SMoriah Waterland  *			a call to e_new_args) to add the argument to
651*5c51f124SMoriah Waterland  *		a_format - [RO, *RO] - (char *)
652*5c51f124SMoriah Waterland  *			Pointer to "printf" style format argument
653*5c51f124SMoriah Waterland  *		... - [RO, *RO] - (varies)
654*5c51f124SMoriah Waterland  *			Arguments as appropriate for format statement
655*5c51f124SMoriah Waterland  * Returns:	boolean_t
656*5c51f124SMoriah Waterland  *			B_TRUE - success
657*5c51f124SMoriah Waterland  *			B_FALSE - failure
658*5c51f124SMoriah Waterland  * Examples:
659*5c51f124SMoriah Waterland  * - to add an argument that specifies a file descriptor:
660*5c51f124SMoriah Waterland  *	int fd;
661*5c51f124SMoriah Waterland  *	e_add_arg(aa, "/proc/self/fd/%d", fd);
662*5c51f124SMoriah Waterland  * - to add a flag or other known text:
663*5c51f124SMoriah Waterland  *	e_add_arg(aa, "-s")
664*5c51f124SMoriah Waterland  * - to add random text:
665*5c51f124SMoriah Waterland  *	char *random_text;
666*5c51f124SMoriah Waterland  *	e_add_arg(aa, "%s", random_text);
667*5c51f124SMoriah Waterland  */
668*5c51f124SMoriah Waterland 
669*5c51f124SMoriah Waterland /*PRINTFLIKE2*/
670*5c51f124SMoriah Waterland boolean_t
671*5c51f124SMoriah Waterland e_add_arg(argArray_t *a_args, char *a_format, ...)
672*5c51f124SMoriah Waterland {
673*5c51f124SMoriah Waterland 	char		*rstr = (char *)NULL;
674*5c51f124SMoriah Waterland 	char		bfr[MAX_CANON];
675*5c51f124SMoriah Waterland 	size_t		vres = 0;
676*5c51f124SMoriah Waterland 	va_list		ap;
677*5c51f124SMoriah Waterland 
678*5c51f124SMoriah Waterland 	/*
679*5c51f124SMoriah Waterland 	 * double argument array if array is full
680*5c51f124SMoriah Waterland 	 */
681*5c51f124SMoriah Waterland 
682*5c51f124SMoriah Waterland 	if (a_args->_aaNumArgs >= a_args->_aaMaxArgs) {
683*5c51f124SMoriah Waterland 		int	newMax;
684*5c51f124SMoriah Waterland 		char	**newArgs;
685*5c51f124SMoriah Waterland 
686*5c51f124SMoriah Waterland 		newMax = a_args->_aaMaxArgs * 2;
687*5c51f124SMoriah Waterland 		newArgs = (char **)realloc(a_args->_aaArgs,
688*5c51f124SMoriah Waterland 			(newMax+1) * sizeof (char *));
689*5c51f124SMoriah Waterland 		if (newArgs == (char **)NULL) {
690*5c51f124SMoriah Waterland 			progerr(ERR_MALLOC, strerror(errno),
691*5c51f124SMoriah Waterland 				((newMax+1) * sizeof (char *)), "<char **>");
692*5c51f124SMoriah Waterland 			return (B_FALSE);
693*5c51f124SMoriah Waterland 		}
694*5c51f124SMoriah Waterland 		a_args->_aaArgs = newArgs;
695*5c51f124SMoriah Waterland 		a_args->_aaMaxArgs = newMax;
696*5c51f124SMoriah Waterland 	}
697*5c51f124SMoriah Waterland 
698*5c51f124SMoriah Waterland 	/* determine size of argument to add to list */
699*5c51f124SMoriah Waterland 
700*5c51f124SMoriah Waterland 	va_start(ap, a_format);
701*5c51f124SMoriah Waterland 	vres = vsnprintf(bfr, sizeof (bfr), a_format, ap);
702*5c51f124SMoriah Waterland 	va_end(ap);
703*5c51f124SMoriah Waterland 
704*5c51f124SMoriah Waterland 	/* if it fit in the built in buffer, use that */
705*5c51f124SMoriah Waterland 	if (vres < sizeof (bfr)) {
706*5c51f124SMoriah Waterland 		/* dup text already generated in bfr */
707*5c51f124SMoriah Waterland 		rstr = strdup(bfr);
708*5c51f124SMoriah Waterland 		if (rstr == (char *)NULL) {
709*5c51f124SMoriah Waterland 			progerr(ERR_MALLOC, strerror(errno), vres+2,
710*5c51f124SMoriah Waterland 				"<char *>");
711*5c51f124SMoriah Waterland 			return (B_FALSE);
712*5c51f124SMoriah Waterland 		}
713*5c51f124SMoriah Waterland 	} else {
714*5c51f124SMoriah Waterland 		/* allocate space for argument to add */
715*5c51f124SMoriah Waterland 
716*5c51f124SMoriah Waterland 		rstr = (char *)malloc(vres+2);
717*5c51f124SMoriah Waterland 		if (rstr == (char *)NULL) {
718*5c51f124SMoriah Waterland 			progerr(ERR_MALLOC, strerror(errno), vres+2,
719*5c51f124SMoriah Waterland 				"<char *>");
720*5c51f124SMoriah Waterland 			return (B_FALSE);
721*5c51f124SMoriah Waterland 		}
722*5c51f124SMoriah Waterland 
723*5c51f124SMoriah Waterland 		/* generate argument to add */
724*5c51f124SMoriah Waterland 
725*5c51f124SMoriah Waterland 		va_start(ap, a_format);
726*5c51f124SMoriah Waterland 		vres = vsnprintf(rstr, vres+1, a_format, ap);
727*5c51f124SMoriah Waterland 		va_end(ap);
728*5c51f124SMoriah Waterland 	}
729*5c51f124SMoriah Waterland 
730*5c51f124SMoriah Waterland 	/* add argument to the end of the argument array */
731*5c51f124SMoriah Waterland 
732*5c51f124SMoriah Waterland 	a_args->_aaArgs[a_args->_aaNumArgs++] = rstr;
733*5c51f124SMoriah Waterland 	a_args->_aaArgs[a_args->_aaNumArgs] = (char *)NULL;
734*5c51f124SMoriah Waterland 
735*5c51f124SMoriah Waterland 	return (B_TRUE);
736*5c51f124SMoriah Waterland }
737*5c51f124SMoriah Waterland 
738*5c51f124SMoriah Waterland /*
739*5c51f124SMoriah Waterland  * Name:	e_get_argv
740*5c51f124SMoriah Waterland  * Description:	return (char **)argv pointer from argument array
741*5c51f124SMoriah Waterland  * Arguments:	a_args - [RO, *RW] - (argArray_t *)
742*5c51f124SMoriah Waterland  *			Pointer to argument array (previously allocated via
743*5c51f124SMoriah Waterland  *			a call to e_new_args) to return argv pointer for
744*5c51f124SMoriah Waterland  * Returns:	char **
745*5c51f124SMoriah Waterland  *			Pointer to (char **)argv pointer suitable for use
746*5c51f124SMoriah Waterland  *			in an exec*() call
747*5c51f124SMoriah Waterland  * NOTE: the actual character array is always terminated with a (char *)NULL
748*5c51f124SMoriah Waterland  */
749*5c51f124SMoriah Waterland 
750*5c51f124SMoriah Waterland char **
751*5c51f124SMoriah Waterland e_get_argv(argArray_t *a_args)
752*5c51f124SMoriah Waterland {
753*5c51f124SMoriah Waterland 	return (a_args->_aaArgs);
754*5c51f124SMoriah Waterland }
755*5c51f124SMoriah Waterland 
756*5c51f124SMoriah Waterland /*
757*5c51f124SMoriah Waterland  * Name:	e_get_argc
758*5c51f124SMoriah Waterland  * Description:	return (int) argc count from argument array
759*5c51f124SMoriah Waterland  * Arguments:	a_args - [RO, *RW] - (argArray_t *)
760*5c51f124SMoriah Waterland  *			Pointer to argument array (previously allocated via
761*5c51f124SMoriah Waterland  *			a call to e_new_args) to return argc count for
762*5c51f124SMoriah Waterland  * Returns:	int
763*5c51f124SMoriah Waterland  *			Count of the number of arguments in the argument array
764*5c51f124SMoriah Waterland  *			suitable for use in an exec*() call
765*5c51f124SMoriah Waterland  */
766*5c51f124SMoriah Waterland 
767*5c51f124SMoriah Waterland int
768*5c51f124SMoriah Waterland e_get_argc(argArray_t *a_args)
769*5c51f124SMoriah Waterland {
770*5c51f124SMoriah Waterland 	return (a_args->_aaNumArgs);
771*5c51f124SMoriah Waterland }
772*5c51f124SMoriah Waterland 
773*5c51f124SMoriah Waterland /*
774*5c51f124SMoriah Waterland  * Name:	e_free_args
775*5c51f124SMoriah Waterland  * Description:	free all storage contained in an argument array previously
776*5c51f124SMoriah Waterland  *		allocated by a call to e_new_args
777*5c51f124SMoriah Waterland  * Arguments:	a_args - [RO, *RW] - (argArray_t *)
778*5c51f124SMoriah Waterland  *			Pointer to argument array (previously allocated via
779*5c51f124SMoriah Waterland  *			a call to e_new_args) to free
780*5c51f124SMoriah Waterland  * Returns:	void
781*5c51f124SMoriah Waterland  * NOTE:	preserves errno (usually called right after e_execCmd*())
782*5c51f124SMoriah Waterland  */
783*5c51f124SMoriah Waterland 
784*5c51f124SMoriah Waterland void
785*5c51f124SMoriah Waterland e_free_args(argArray_t *a_args)
786*5c51f124SMoriah Waterland {
787*5c51f124SMoriah Waterland 	int	i;
788*5c51f124SMoriah Waterland 	int	lerrno = errno;
789*5c51f124SMoriah Waterland 
790*5c51f124SMoriah Waterland 	/* free all arguments in the argument array */
791*5c51f124SMoriah Waterland 
792*5c51f124SMoriah Waterland 	for (i = (a_args->_aaNumArgs-1); i >= 0; i--) {
793*5c51f124SMoriah Waterland 		(void) free(a_args->_aaArgs[i]);
794*5c51f124SMoriah Waterland 		a_args->_aaArgs[i] = (char *)NULL;
795*5c51f124SMoriah Waterland 	}
796*5c51f124SMoriah Waterland 
797*5c51f124SMoriah Waterland 	/* free argument array */
798*5c51f124SMoriah Waterland 
799*5c51f124SMoriah Waterland 	(void) free(a_args->_aaArgs);
800*5c51f124SMoriah Waterland 
801*5c51f124SMoriah Waterland 	/* free argument array structure */
802*5c51f124SMoriah Waterland 
803*5c51f124SMoriah Waterland 	(void) free(a_args);
804*5c51f124SMoriah Waterland 
805*5c51f124SMoriah Waterland 	/* restore errno */
806*5c51f124SMoriah Waterland 
807*5c51f124SMoriah Waterland 	errno = lerrno;
808*5c51f124SMoriah Waterland }
809