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