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