1*5c51f124SMoriah Waterland /*
2*5c51f124SMoriah Waterland  * CDDL HEADER START
3*5c51f124SMoriah Waterland  *
4*5c51f124SMoriah Waterland  * The contents of this file are subject to the terms of the
5*5c51f124SMoriah Waterland  * Common Development and Distribution License (the "License").
6*5c51f124SMoriah Waterland  * You may not use this file except in compliance with the License.
7*5c51f124SMoriah Waterland  *
8*5c51f124SMoriah Waterland  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*5c51f124SMoriah Waterland  * or http://www.opensolaris.org/os/licensing.
10*5c51f124SMoriah Waterland  * See the License for the specific language governing permissions
11*5c51f124SMoriah Waterland  * and limitations under the License.
12*5c51f124SMoriah Waterland  *
13*5c51f124SMoriah Waterland  * When distributing Covered Code, include this CDDL HEADER in each
14*5c51f124SMoriah Waterland  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*5c51f124SMoriah Waterland  * If applicable, add the following below this CDDL HEADER, with the
16*5c51f124SMoriah Waterland  * fields enclosed by brackets "[]" replaced with your own identifying
17*5c51f124SMoriah Waterland  * information: Portions Copyright [yyyy] [name of copyright owner]
18*5c51f124SMoriah Waterland  *
19*5c51f124SMoriah Waterland  * CDDL HEADER END
20*5c51f124SMoriah Waterland  */
21*5c51f124SMoriah Waterland 
22*5c51f124SMoriah Waterland /*
23*5c51f124SMoriah Waterland  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*5c51f124SMoriah Waterland  * Use is subject to license terms.
25*5c51f124SMoriah Waterland  */
26*5c51f124SMoriah Waterland 
27*5c51f124SMoriah Waterland 
28*5c51f124SMoriah Waterland 
29*5c51f124SMoriah Waterland /*
30*5c51f124SMoriah Waterland  * Module:	zones_exec.c
31*5c51f124SMoriah Waterland  * Group:	libinstzones
32*5c51f124SMoriah Waterland  * Description:	Provide "zones" execution interface for install
33*5c51f124SMoriah Waterland  *		consolidation code
34*5c51f124SMoriah Waterland  *
35*5c51f124SMoriah Waterland  * Public Methods:
36*5c51f124SMoriah Waterland  *
37*5c51f124SMoriah Waterland  * z_ExecCmdArray - Execute a Unix command and return results and status
38*5c51f124SMoriah Waterland  * _zexec - run a command with arguments on a specified zone
39*5c51f124SMoriah Waterland  * _zexec_init_template - used by _zexec to establish contracts
40*5c51f124SMoriah Waterland  * _z_zone_exec - Execute a Unix command in a specified zone and return results
41*5c51f124SMoriah Waterland  * z_ExecCmdList - Execute a Unix command and return results and status
42*5c51f124SMoriah Waterland  */
43*5c51f124SMoriah Waterland 
44*5c51f124SMoriah Waterland /*
45*5c51f124SMoriah Waterland  * System includes
46*5c51f124SMoriah Waterland  */
47*5c51f124SMoriah Waterland 
48*5c51f124SMoriah Waterland #include <stdio.h>
49*5c51f124SMoriah Waterland #include <stdlib.h>
50*5c51f124SMoriah Waterland #include <unistd.h>
51*5c51f124SMoriah Waterland #include <fcntl.h>
52*5c51f124SMoriah Waterland #include <ctype.h>
53*5c51f124SMoriah Waterland #include <sys/types.h>
54*5c51f124SMoriah Waterland #include <sys/param.h>
55*5c51f124SMoriah Waterland #include <string.h>
56*5c51f124SMoriah Waterland #include <strings.h>
57*5c51f124SMoriah Waterland #include <stdarg.h>
58*5c51f124SMoriah Waterland #include <limits.h>
59*5c51f124SMoriah Waterland #include <errno.h>
60*5c51f124SMoriah Waterland #include <signal.h>
61*5c51f124SMoriah Waterland #include <wait.h>
62*5c51f124SMoriah Waterland #include <stropts.h>
63*5c51f124SMoriah Waterland #include <libintl.h>
64*5c51f124SMoriah Waterland #include <locale.h>
65*5c51f124SMoriah Waterland #include <libcontract.h>
66*5c51f124SMoriah Waterland #include <sys/contract/process.h>
67*5c51f124SMoriah Waterland #include <sys/ctfs.h>
68*5c51f124SMoriah Waterland #include <assert.h>
69*5c51f124SMoriah Waterland 
70*5c51f124SMoriah Waterland /*
71*5c51f124SMoriah Waterland  * local includes
72*5c51f124SMoriah Waterland  */
73*5c51f124SMoriah Waterland 
74*5c51f124SMoriah Waterland #include "instzones_lib.h"
75*5c51f124SMoriah Waterland #include "zones_strings.h"
76*5c51f124SMoriah Waterland 
77*5c51f124SMoriah Waterland /*
78*5c51f124SMoriah Waterland  * Private structures
79*5c51f124SMoriah Waterland  */
80*5c51f124SMoriah Waterland 
81*5c51f124SMoriah Waterland /*
82*5c51f124SMoriah Waterland  * Library Function Prototypes
83*5c51f124SMoriah Waterland  */
84*5c51f124SMoriah Waterland 
85*5c51f124SMoriah Waterland /*
86*5c51f124SMoriah Waterland  * Local Function Prototypes
87*5c51f124SMoriah Waterland  */
88*5c51f124SMoriah Waterland 
89*5c51f124SMoriah Waterland /*
90*5c51f124SMoriah Waterland  * global internal (private) declarations
91*5c51f124SMoriah Waterland  */
92*5c51f124SMoriah Waterland 
93*5c51f124SMoriah Waterland /*
94*5c51f124SMoriah Waterland  * *****************************************************************************
95*5c51f124SMoriah Waterland  * global external (public) functions
96*5c51f124SMoriah Waterland  * *****************************************************************************
97*5c51f124SMoriah Waterland  */
98*5c51f124SMoriah Waterland 
99*5c51f124SMoriah Waterland /*
100*5c51f124SMoriah Waterland  * Name:	z_ExecCmdArray
101*5c51f124SMoriah Waterland  * Synopsis:	Execute Unix command and return results
102*5c51f124SMoriah Waterland  * Description:	Execute a Unix command and return results and status
103*5c51f124SMoriah Waterland  * Arguments:
104*5c51f124SMoriah Waterland  *		r_status - [RO, *RW] - (int *)
105*5c51f124SMoriah Waterland  *			Return (exit) status from Unix command:
106*5c51f124SMoriah Waterland  *			== -1 : child terminated with a signal
107*5c51f124SMoriah Waterland  *			!= -1 : lower 8-bit value child passed to exit()
108*5c51f124SMoriah Waterland  *		r_results - [RO, *RW] - (char **)
109*5c51f124SMoriah Waterland  *			Any output generated by the Unix command to stdout
110*5c51f124SMoriah Waterland  *			and to stderr
111*5c51f124SMoriah Waterland  *			== (char *)NULL if no output generated
112*5c51f124SMoriah Waterland  *		a_inputFile - [RO, *RO] - (char *)
113*5c51f124SMoriah Waterland  *			Pointer to character string representing file to be
114*5c51f124SMoriah Waterland  *			used as "standard input" for the command.
115*5c51f124SMoriah Waterland  *			== (char *)NULL to use "/dev/null" as standard input
116*5c51f124SMoriah Waterland  *		a_cmd - [RO, *RO] - (char *)
117*5c51f124SMoriah Waterland  *			Pointer to character string representing the full path
118*5c51f124SMoriah Waterland  *			of the Unix command to execute
119*5c51f124SMoriah Waterland  *		char **a_args - [RO, *RO] - (char **)
120*5c51f124SMoriah Waterland  *			List of character strings representing the arguments
121*5c51f124SMoriah Waterland  *			to be passed to the Unix command. The list must be
122*5c51f124SMoriah Waterland  *			terminated with an element that is (char *)NULL
123*5c51f124SMoriah Waterland  * Returns:	int
124*5c51f124SMoriah Waterland  *			== 0 - Command executed
125*5c51f124SMoriah Waterland  *				Look at r_status for results of Unix command
126*5c51f124SMoriah Waterland  *			!= 0 - problems executing command
127*5c51f124SMoriah Waterland  *				r_status and r_results have no meaning;
128*5c51f124SMoriah Waterland  *				r_status will be -1
129*5c51f124SMoriah Waterland  *				r_results will be NULL
130*5c51f124SMoriah Waterland  * NOTE:    	Any results returned is placed in new storage for the
131*5c51f124SMoriah Waterland  *		calling method. The caller must use 'free' to dispose
132*5c51f124SMoriah Waterland  *		of the storage once the results are no longer needed.
133*5c51f124SMoriah Waterland  * NOTE:	If 0 is returned, 'r_status' must be queried to
134*5c51f124SMoriah Waterland  *		determine the results of the Unix command.
135*5c51f124SMoriah Waterland  * NOTE:	The system "errno" value from immediately after waitpid() call
136*5c51f124SMoriah Waterland  *		is preserved for the calling method to use to determine
137*5c51f124SMoriah Waterland  *		the system reason why the operation failed.
138*5c51f124SMoriah Waterland  */
139*5c51f124SMoriah Waterland 
140*5c51f124SMoriah Waterland int
z_ExecCmdArray(int * r_status,char ** r_results,char * a_inputFile,char * a_cmd,char ** a_args)141*5c51f124SMoriah Waterland z_ExecCmdArray(int *r_status, char **r_results,
142*5c51f124SMoriah Waterland     char *a_inputFile, char *a_cmd, char **a_args)
143*5c51f124SMoriah Waterland {
144*5c51f124SMoriah Waterland 	char		*buffer;
145*5c51f124SMoriah Waterland 	int		bufferIndex;
146*5c51f124SMoriah Waterland 	int		bufferSize;
147*5c51f124SMoriah Waterland 	int		ipipe[2] = {0, 0};
148*5c51f124SMoriah Waterland 	int		lerrno;
149*5c51f124SMoriah Waterland 	int		status;
150*5c51f124SMoriah Waterland 	int		stdinfile = -1;
151*5c51f124SMoriah Waterland 	pid_t		pid;
152*5c51f124SMoriah Waterland 	pid_t		resultPid;
153*5c51f124SMoriah Waterland 
154*5c51f124SMoriah Waterland 	/* entry assertions */
155*5c51f124SMoriah Waterland 
156*5c51f124SMoriah Waterland 	assert(r_status != NULL);
157*5c51f124SMoriah Waterland 	assert(a_cmd != NULL);
158*5c51f124SMoriah Waterland 	assert(*a_cmd != '\0');
159*5c51f124SMoriah Waterland 	assert(a_args != NULL);
160*5c51f124SMoriah Waterland 
161*5c51f124SMoriah Waterland 	/* reset return results buffer pointer */
162*5c51f124SMoriah Waterland 
163*5c51f124SMoriah Waterland 	if (r_results != (char **)NULL) {
164*5c51f124SMoriah Waterland 		*r_results = (char *)NULL;
165*5c51f124SMoriah Waterland 	}
166*5c51f124SMoriah Waterland 
167*5c51f124SMoriah Waterland 	*r_status = -1;
168*5c51f124SMoriah Waterland 
169*5c51f124SMoriah Waterland 	/*
170*5c51f124SMoriah Waterland 	 * See if command exists
171*5c51f124SMoriah Waterland 	 */
172*5c51f124SMoriah Waterland 
173*5c51f124SMoriah Waterland 	if (access(a_cmd, F_OK|X_OK) != 0) {
174*5c51f124SMoriah Waterland 		return (-1);
175*5c51f124SMoriah Waterland 	}
176*5c51f124SMoriah Waterland 
177*5c51f124SMoriah Waterland 	/*
178*5c51f124SMoriah Waterland 	 * See if input file exists
179*5c51f124SMoriah Waterland 	 */
180*5c51f124SMoriah Waterland 
181*5c51f124SMoriah Waterland 	if (a_inputFile != (char *)NULL) {
182*5c51f124SMoriah Waterland 		stdinfile = open(a_inputFile, O_RDONLY);
183*5c51f124SMoriah Waterland 	} else {
184*5c51f124SMoriah Waterland 		stdinfile = open("/dev/null", O_RDONLY); /* stdin = /dev/null */
185*5c51f124SMoriah Waterland 	}
186*5c51f124SMoriah Waterland 
187*5c51f124SMoriah Waterland 	if (stdinfile < 0) {
188*5c51f124SMoriah Waterland 		return (-1);
189*5c51f124SMoriah Waterland 	}
190*5c51f124SMoriah Waterland 
191*5c51f124SMoriah Waterland 	/*
192*5c51f124SMoriah Waterland 	 * Create a pipe to be used to capture the command output
193*5c51f124SMoriah Waterland 	 */
194*5c51f124SMoriah Waterland 
195*5c51f124SMoriah Waterland 	if (pipe(ipipe) != 0) {
196*5c51f124SMoriah Waterland 		(void) close(stdinfile);
197*5c51f124SMoriah Waterland 		return (-1);
198*5c51f124SMoriah Waterland 	}
199*5c51f124SMoriah Waterland 
200*5c51f124SMoriah Waterland 
201*5c51f124SMoriah Waterland 	bufferSize = PIPE_BUFFER_INCREMENT;
202*5c51f124SMoriah Waterland 	bufferIndex = 0;
203*5c51f124SMoriah Waterland 	buffer = calloc(1, bufferSize);
204*5c51f124SMoriah Waterland 	if (buffer == (char *)NULL) {
205*5c51f124SMoriah Waterland 		(void) close(stdinfile);
206*5c51f124SMoriah Waterland 		return (-1);
207*5c51f124SMoriah Waterland 	}
208*5c51f124SMoriah Waterland 
209*5c51f124SMoriah Waterland 	/* flush standard i/o before creating new process */
210*5c51f124SMoriah Waterland 
211*5c51f124SMoriah Waterland 	(void) fflush(stderr);
212*5c51f124SMoriah Waterland 	(void) fflush(stdout);
213*5c51f124SMoriah Waterland 
214*5c51f124SMoriah Waterland 	/*
215*5c51f124SMoriah Waterland 	 * create new process to execute command in;
216*5c51f124SMoriah Waterland 	 * vfork() is being used to avoid duplicating the parents
217*5c51f124SMoriah Waterland 	 * memory space - this means that the child process may
218*5c51f124SMoriah Waterland 	 * not modify any of the parents memory including the
219*5c51f124SMoriah Waterland 	 * standard i/o descriptors - all the child can do is
220*5c51f124SMoriah Waterland 	 * adjust interrupts and open files as a prelude to a
221*5c51f124SMoriah Waterland 	 * call to exec().
222*5c51f124SMoriah Waterland 	 */
223*5c51f124SMoriah Waterland 
224*5c51f124SMoriah Waterland 	pid = vfork();
225*5c51f124SMoriah Waterland 
226*5c51f124SMoriah Waterland 	if (pid == 0) {
227*5c51f124SMoriah Waterland 		/*
228*5c51f124SMoriah Waterland 		 * This is the forked (child) process ======================
229*5c51f124SMoriah Waterland 		 */
230*5c51f124SMoriah Waterland 
231*5c51f124SMoriah Waterland 		int	i;
232*5c51f124SMoriah Waterland 
233*5c51f124SMoriah Waterland 		/* reset any signals to default */
234*5c51f124SMoriah Waterland 
235*5c51f124SMoriah Waterland 		for (i = 0; i < NSIG; i++) {
236*5c51f124SMoriah Waterland 			(void) sigset(i, SIG_DFL);
237*5c51f124SMoriah Waterland 		}
238*5c51f124SMoriah Waterland 
239*5c51f124SMoriah Waterland 		/* assign stdin, stdout, stderr as appropriate */
240*5c51f124SMoriah Waterland 
241*5c51f124SMoriah Waterland 		(void) dup2(stdinfile, STDIN_FILENO);
242*5c51f124SMoriah Waterland 		(void) close(ipipe[0]);		/* close out pipe reader side */
243*5c51f124SMoriah Waterland 		(void) dup2(ipipe[1], STDOUT_FILENO);
244*5c51f124SMoriah Waterland 		(void) dup2(ipipe[1], STDERR_FILENO);
245*5c51f124SMoriah Waterland 
246*5c51f124SMoriah Waterland 		/* Close all open files except standard i/o */
247*5c51f124SMoriah Waterland 
248*5c51f124SMoriah Waterland 		closefrom(3);
249*5c51f124SMoriah Waterland 
250*5c51f124SMoriah Waterland 		/* execute target executable */
251*5c51f124SMoriah Waterland 
252*5c51f124SMoriah Waterland 		(void) execvp(a_cmd, a_args);
253*5c51f124SMoriah Waterland 		perror(a_cmd);	/* Emit error msg - ends up in callers buffer */
254*5c51f124SMoriah Waterland 		_exit(0x00FE);
255*5c51f124SMoriah Waterland 	} else if (pid == -1) {
256*5c51f124SMoriah Waterland 		_z_program_error(ERR_FORK, strerror(errno));
257*5c51f124SMoriah Waterland 		*r_status = -1;
258*5c51f124SMoriah Waterland 		return (-1);
259*5c51f124SMoriah Waterland 	}
260*5c51f124SMoriah Waterland 
261*5c51f124SMoriah Waterland 	/*
262*5c51f124SMoriah Waterland 	 * This is the forking (parent) process ====================
263*5c51f124SMoriah Waterland 	 */
264*5c51f124SMoriah Waterland 
265*5c51f124SMoriah Waterland 	(void) close(stdinfile);
266*5c51f124SMoriah Waterland 	(void) close(ipipe[1]);		/* Close write side of pipe */
267*5c51f124SMoriah Waterland 
268*5c51f124SMoriah Waterland 	/*
269*5c51f124SMoriah Waterland 	 * Spin reading data from the child into the buffer - when the read eofs
270*5c51f124SMoriah Waterland 	 * the child has exited
271*5c51f124SMoriah Waterland 	 */
272*5c51f124SMoriah Waterland 
273*5c51f124SMoriah Waterland 	for (;;) {
274*5c51f124SMoriah Waterland 		ssize_t	bytesRead;
275*5c51f124SMoriah Waterland 
276*5c51f124SMoriah Waterland 		/* read as much child data as there is available buffer space */
277*5c51f124SMoriah Waterland 
278*5c51f124SMoriah Waterland 		bytesRead = read(ipipe[0], buffer + bufferIndex,
279*5c51f124SMoriah Waterland 		    bufferSize - bufferIndex);
280*5c51f124SMoriah Waterland 
281*5c51f124SMoriah Waterland 		/* break out of read loop if end-of-file encountered */
282*5c51f124SMoriah Waterland 
283*5c51f124SMoriah Waterland 		if (bytesRead == 0) {
284*5c51f124SMoriah Waterland 			break;
285*5c51f124SMoriah Waterland 		}
286*5c51f124SMoriah Waterland 
287*5c51f124SMoriah Waterland 		/* if error, continue if recoverable, else break out of loop */
288*5c51f124SMoriah Waterland 
289*5c51f124SMoriah Waterland 		if (bytesRead == -1) {
290*5c51f124SMoriah Waterland 			/* try again: EAGAIN - insufficient resources */
291*5c51f124SMoriah Waterland 
292*5c51f124SMoriah Waterland 			if (errno == EAGAIN) {
293*5c51f124SMoriah Waterland 				continue;
294*5c51f124SMoriah Waterland 			}
295*5c51f124SMoriah Waterland 
296*5c51f124SMoriah Waterland 			/* try again: EINTR - interrupted system call */
297*5c51f124SMoriah Waterland 
298*5c51f124SMoriah Waterland 			if (errno == EINTR) {
299*5c51f124SMoriah Waterland 				continue;
300*5c51f124SMoriah Waterland 			}
301*5c51f124SMoriah Waterland 
302*5c51f124SMoriah Waterland 			/* break out of loop - error not recoverable */
303*5c51f124SMoriah Waterland 			break;
304*5c51f124SMoriah Waterland 		}
305*5c51f124SMoriah Waterland 
306*5c51f124SMoriah Waterland 		/* at least 1 byte read: expand buffer if at end */
307*5c51f124SMoriah Waterland 
308*5c51f124SMoriah Waterland 		bufferIndex += bytesRead;
309*5c51f124SMoriah Waterland 		if (bufferIndex >= bufferSize) {
310*5c51f124SMoriah Waterland 			buffer = realloc(buffer,
311*5c51f124SMoriah Waterland 			    bufferSize += PIPE_BUFFER_INCREMENT);
312*5c51f124SMoriah Waterland 			(void) memset(buffer + bufferIndex, 0,
313*5c51f124SMoriah Waterland 			    bufferSize - bufferIndex);
314*5c51f124SMoriah Waterland 		}
315*5c51f124SMoriah Waterland 	}
316*5c51f124SMoriah Waterland 
317*5c51f124SMoriah Waterland 	(void) close(ipipe[0]);		/* Close read side of pipe */
318*5c51f124SMoriah Waterland 
319*5c51f124SMoriah Waterland 	/* Get subprocess exit status */
320*5c51f124SMoriah Waterland 
321*5c51f124SMoriah Waterland 	for (;;) {
322*5c51f124SMoriah Waterland 		resultPid = waitpid(pid, &status, 0L);
323*5c51f124SMoriah Waterland 		lerrno = (resultPid == -1 ? errno : 0);
324*5c51f124SMoriah Waterland 
325*5c51f124SMoriah Waterland 		/* break loop if child process status reaped */
326*5c51f124SMoriah Waterland 
327*5c51f124SMoriah Waterland 		if (resultPid != -1) {
328*5c51f124SMoriah Waterland 			break;
329*5c51f124SMoriah Waterland 		}
330*5c51f124SMoriah Waterland 
331*5c51f124SMoriah Waterland 		/* break loop if not interrupted out of waitpid */
332*5c51f124SMoriah Waterland 
333*5c51f124SMoriah Waterland 		if (errno != EINTR) {
334*5c51f124SMoriah Waterland 			break;
335*5c51f124SMoriah Waterland 		}
336*5c51f124SMoriah Waterland 	}
337*5c51f124SMoriah Waterland 
338*5c51f124SMoriah Waterland 	/*
339*5c51f124SMoriah Waterland 	 * If the child process terminated due to a call to exit(), then
340*5c51f124SMoriah Waterland 	 * set results equal to the 8-bit exit status of the child process;
341*5c51f124SMoriah Waterland 	 * otherwise, set the exit status to "-1" indicating that the child
342*5c51f124SMoriah Waterland 	 * exited via a signal.
343*5c51f124SMoriah Waterland 	 */
344*5c51f124SMoriah Waterland 
345*5c51f124SMoriah Waterland 	*r_status = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
346*5c51f124SMoriah Waterland 
347*5c51f124SMoriah Waterland 	/* return appropriate output */
348*5c51f124SMoriah Waterland 
349*5c51f124SMoriah Waterland 	if (!*buffer) {
350*5c51f124SMoriah Waterland 		/* No contents in output buffer - discard */
351*5c51f124SMoriah Waterland 		free(buffer);
352*5c51f124SMoriah Waterland 	} else if (r_results == (char **)NULL) {
353*5c51f124SMoriah Waterland 		/* Not requested to return results - discard */
354*5c51f124SMoriah Waterland 		free(buffer);
355*5c51f124SMoriah Waterland 	} else {
356*5c51f124SMoriah Waterland 		/* have output and request to return: pass to calling method */
357*5c51f124SMoriah Waterland 		*r_results = buffer;
358*5c51f124SMoriah Waterland 	}
359*5c51f124SMoriah Waterland 
360*5c51f124SMoriah Waterland 	errno = lerrno;
361*5c51f124SMoriah Waterland 	return (resultPid == -1 ? -1 : 0);
362*5c51f124SMoriah Waterland }
363*5c51f124SMoriah Waterland 
364*5c51f124SMoriah Waterland /*
365*5c51f124SMoriah Waterland  * Name:	_zexec
366*5c51f124SMoriah Waterland  * Description:	run a command with arguments on a specified zone
367*5c51f124SMoriah Waterland  * Arguments:	a_zoneName - pointer to string representing the name of the zone
368*5c51f124SMoriah Waterland  *			to execute the specified command in
369*5c51f124SMoriah Waterland  *		a_path - pointer to string representing the full path *in the
370*5c51f124SMoriah Waterland  *			non-global zone named by a_zoneName* of the Unix command
371*5c51f124SMoriah Waterland  *			to be executed
372*5c51f124SMoriah Waterland  *		a_argv[] - Pointer to array of character strings representing
373*5c51f124SMoriah Waterland  *			the arguments to be passed to the Unix command. The list
374*5c51f124SMoriah Waterland  *			must be termianted with an element that is (char *)NULL
375*5c51f124SMoriah Waterland  *		NOTE: a_argv[0] is the "command name" passed to the command
376*5c51f124SMoriah Waterland  * Returns:	int
377*5c51f124SMoriah Waterland  *			This function must be treated like a call to exec()
378*5c51f124SMoriah Waterland  *			If the exec() is successful, the thread of control is
379*5c51f124SMoriah Waterland  *			NOT returned, and the process will exit when completed.
380*5c51f124SMoriah Waterland  *			If this function returns, it means the exec() could not
381*5c51f124SMoriah Waterland  *			be done, or another fatal error occurred.
382*5c51f124SMoriah Waterland  */
383*5c51f124SMoriah Waterland 
384*5c51f124SMoriah Waterland int
_zexec(const char * a_zoneName,const char * a_path,char * a_argv[])385*5c51f124SMoriah Waterland _zexec(const char *a_zoneName, const char *a_path, char *a_argv[])
386*5c51f124SMoriah Waterland {
387*5c51f124SMoriah Waterland 	zoneid_t zoneid;
388*5c51f124SMoriah Waterland 	zone_state_t st;
389*5c51f124SMoriah Waterland 	char **new_env = { NULL };
390*5c51f124SMoriah Waterland 	priv_set_t *privset;
391*5c51f124SMoriah Waterland 
392*5c51f124SMoriah Waterland 	/* entry assertions */
393*5c51f124SMoriah Waterland 
394*5c51f124SMoriah Waterland 	assert(a_zoneName != NULL);
395*5c51f124SMoriah Waterland 	assert(*a_zoneName != '\0');
396*5c51f124SMoriah Waterland 	assert(a_path != NULL);
397*5c51f124SMoriah Waterland 	assert(*a_path != '\0');
398*5c51f124SMoriah Waterland 
399*5c51f124SMoriah Waterland 	/* establish locale settings */
400*5c51f124SMoriah Waterland 
401*5c51f124SMoriah Waterland 	(void) setlocale(LC_ALL, "");
402*5c51f124SMoriah Waterland 	(void) textdomain(TEXT_DOMAIN);
403*5c51f124SMoriah Waterland 
404*5c51f124SMoriah Waterland 	/* can only be invoked from within the global zone */
405*5c51f124SMoriah Waterland 
406*5c51f124SMoriah Waterland 	if (getzoneid() != GLOBAL_ZONEID) {
407*5c51f124SMoriah Waterland 		_z_program_error(ERR_ZEXEC_NOT_IN_GZ, a_zoneName);
408*5c51f124SMoriah Waterland 		return (-1);
409*5c51f124SMoriah Waterland 	}
410*5c51f124SMoriah Waterland 
411*5c51f124SMoriah Waterland 	if (strcmp(a_zoneName, GLOBAL_ZONENAME) == 0) {
412*5c51f124SMoriah Waterland 		_z_program_error(ERR_ZEXEC_GZUSED, a_zoneName);
413*5c51f124SMoriah Waterland 		return (-1);
414*5c51f124SMoriah Waterland 	}
415*5c51f124SMoriah Waterland 
416*5c51f124SMoriah Waterland 	/* get the state of the specified zone */
417*5c51f124SMoriah Waterland 
418*5c51f124SMoriah Waterland 	if (zone_get_state((char *)a_zoneName, &st) != Z_OK) {
419*5c51f124SMoriah Waterland 		_z_program_error(ERR_ZEXEC_BADZONE, a_zoneName);
420*5c51f124SMoriah Waterland 		return (-1);
421*5c51f124SMoriah Waterland 	}
422*5c51f124SMoriah Waterland 
423*5c51f124SMoriah Waterland 	if (st < ZONE_STATE_INSTALLED) {
424*5c51f124SMoriah Waterland 		_z_program_error(ERR_ZEXEC_BADSTATE, a_zoneName,
425*5c51f124SMoriah Waterland 		    zone_state_str(st));
426*5c51f124SMoriah Waterland 		return (-1);
427*5c51f124SMoriah Waterland 	}
428*5c51f124SMoriah Waterland 
429*5c51f124SMoriah Waterland 	if (st != ZONE_STATE_RUNNING && st != ZONE_STATE_MOUNTED) {
430*5c51f124SMoriah Waterland 		_z_program_error(ERR_ZEXEC_NOTRUNNING, a_zoneName,
431*5c51f124SMoriah Waterland 		    zone_state_str(st));
432*5c51f124SMoriah Waterland 		return (-1);
433*5c51f124SMoriah Waterland 	}
434*5c51f124SMoriah Waterland 
435*5c51f124SMoriah Waterland 	/*
436*5c51f124SMoriah Waterland 	 * In both console and non-console cases, we require all privs.
437*5c51f124SMoriah Waterland 	 * In the console case, because we may need to startup zoneadmd.
438*5c51f124SMoriah Waterland 	 * In the non-console case in order to do zone_enter(2), zonept()
439*5c51f124SMoriah Waterland 	 * and other tasks.
440*5c51f124SMoriah Waterland 	 *
441*5c51f124SMoriah Waterland 	 * Future work: this solution is temporary.  Ultimately, we need to
442*5c51f124SMoriah Waterland 	 * move to a flexible system which allows the global admin to
443*5c51f124SMoriah Waterland 	 * designate that a particular user can zlogin (and probably zlogin
444*5c51f124SMoriah Waterland 	 * -C) to a particular zone.  This all-root business we have now is
445*5c51f124SMoriah Waterland 	 * quite sketchy.
446*5c51f124SMoriah Waterland 	 */
447*5c51f124SMoriah Waterland 
448*5c51f124SMoriah Waterland 	if ((privset = priv_allocset()) == NULL) {
449*5c51f124SMoriah Waterland 		_z_program_error(ERR_ZEXEC_PRIV_ALLOCSET, a_zoneName,
450*5c51f124SMoriah Waterland 		    strerror(errno));
451*5c51f124SMoriah Waterland 		return (-1);
452*5c51f124SMoriah Waterland 	}
453*5c51f124SMoriah Waterland 
454*5c51f124SMoriah Waterland 	if (getppriv(PRIV_EFFECTIVE, privset) != 0) {
455*5c51f124SMoriah Waterland 		_z_program_error(ERR_ZEXEC_GETPPRIV, a_zoneName,
456*5c51f124SMoriah Waterland 		    strerror(errno));
457*5c51f124SMoriah Waterland 		priv_freeset(privset);
458*5c51f124SMoriah Waterland 		return (-1);
459*5c51f124SMoriah Waterland 	}
460*5c51f124SMoriah Waterland 
461*5c51f124SMoriah Waterland 	if (priv_isfullset(privset) == B_FALSE) {
462*5c51f124SMoriah Waterland 		_z_program_error(ERR_ZEXEC_PRIVS, a_zoneName);
463*5c51f124SMoriah Waterland 		priv_freeset(privset);
464*5c51f124SMoriah Waterland 		return (-1);
465*5c51f124SMoriah Waterland 	}
466*5c51f124SMoriah Waterland 	priv_freeset(privset);
467*5c51f124SMoriah Waterland 
468*5c51f124SMoriah Waterland 	if ((zoneid = getzoneidbyname(a_zoneName)) == -1) {
469*5c51f124SMoriah Waterland 		_z_program_error(ERR_ZEXEC_NOZONEID, a_zoneName,
470*5c51f124SMoriah Waterland 		    strerror(errno));
471*5c51f124SMoriah Waterland 		return (-1);
472*5c51f124SMoriah Waterland 	}
473*5c51f124SMoriah Waterland 
474*5c51f124SMoriah Waterland 	if ((new_env = _zexec_prep_env()) == NULL) {
475*5c51f124SMoriah Waterland 		_z_program_error(ERR_ZEXEC_ASSEMBLE, a_zoneName);
476*5c51f124SMoriah Waterland 		return (-1);
477*5c51f124SMoriah Waterland 	}
478*5c51f124SMoriah Waterland 
479*5c51f124SMoriah Waterland 	/*
480*5c51f124SMoriah Waterland 	 * In case any of stdin, stdout or stderr are streams,
481*5c51f124SMoriah Waterland 	 * anchor them to prevent malicious I_POPs.
482*5c51f124SMoriah Waterland 	 *
483*5c51f124SMoriah Waterland 	 * Future work: use pipes to entirely eliminate FD leakage
484*5c51f124SMoriah Waterland 	 * into the zone.
485*5c51f124SMoriah Waterland 	 */
486*5c51f124SMoriah Waterland 
487*5c51f124SMoriah Waterland 	(void) ioctl(STDIN_FILENO, I_ANCHOR);
488*5c51f124SMoriah Waterland 	(void) ioctl(STDOUT_FILENO, I_ANCHOR);
489*5c51f124SMoriah Waterland 	(void) ioctl(STDERR_FILENO, I_ANCHOR);
490*5c51f124SMoriah Waterland 
491*5c51f124SMoriah Waterland 	if (zone_enter(zoneid) == -1) {
492*5c51f124SMoriah Waterland 		int	lerrno = errno;
493*5c51f124SMoriah Waterland 
494*5c51f124SMoriah Waterland 		_z_program_error(ERR_ZEXEC_ZONEENTER, a_zoneName,
495*5c51f124SMoriah Waterland 		    strerror(errno));
496*5c51f124SMoriah Waterland 
497*5c51f124SMoriah Waterland 		if (lerrno == EFAULT) {
498*5c51f124SMoriah Waterland 			_z_program_error(ERR_ZEXEC_EFAULT, a_zoneName);
499*5c51f124SMoriah Waterland 		}
500*5c51f124SMoriah Waterland 
501*5c51f124SMoriah Waterland 		free(new_env);
502*5c51f124SMoriah Waterland 
503*5c51f124SMoriah Waterland 		return (-1);
504*5c51f124SMoriah Waterland 	}
505*5c51f124SMoriah Waterland 
506*5c51f124SMoriah Waterland 	(void) execve(a_path, &a_argv[0], new_env);
507*5c51f124SMoriah Waterland 
508*5c51f124SMoriah Waterland 	_z_program_error(ERR_ZEXEC_EXECFAILURE, a_zoneName, strerror(errno));
509*5c51f124SMoriah Waterland 
510*5c51f124SMoriah Waterland 	return (-1);
511*5c51f124SMoriah Waterland }
512*5c51f124SMoriah Waterland 
513*5c51f124SMoriah Waterland /*
514*5c51f124SMoriah Waterland  * Name:	_zexec_init_template
515*5c51f124SMoriah Waterland  * Description:	used by _zexec to establish contracts
516*5c51f124SMoriah Waterland  */
517*5c51f124SMoriah Waterland 
518*5c51f124SMoriah Waterland int
_zexec_init_template(void)519*5c51f124SMoriah Waterland _zexec_init_template(void)
520*5c51f124SMoriah Waterland {
521*5c51f124SMoriah Waterland 	int fd;
522*5c51f124SMoriah Waterland 	int err = 0;
523*5c51f124SMoriah Waterland 
524*5c51f124SMoriah Waterland 	fd = open64(CTFS_ROOT "/process/template", O_RDWR);
525*5c51f124SMoriah Waterland 	if (fd == -1) {
526*5c51f124SMoriah Waterland 		return (-1);
527*5c51f124SMoriah Waterland 	}
528*5c51f124SMoriah Waterland 
529*5c51f124SMoriah Waterland 	/*
530*5c51f124SMoriah Waterland 	 * zlogin doesn't do anything with the contract.
531*5c51f124SMoriah Waterland 	 * Deliver no events, don't inherit, and allow it to be orphaned.
532*5c51f124SMoriah Waterland 	 */
533*5c51f124SMoriah Waterland 	err |= ct_tmpl_set_critical(fd, 0);
534*5c51f124SMoriah Waterland 	err |= ct_tmpl_set_informative(fd, 0);
535*5c51f124SMoriah Waterland 	err |= ct_pr_tmpl_set_fatal(fd, CT_PR_EV_HWERR);
536*5c51f124SMoriah Waterland 	err |= ct_pr_tmpl_set_param(fd, CT_PR_PGRPONLY | CT_PR_REGENT);
537*5c51f124SMoriah Waterland 	if (err || ct_tmpl_activate(fd)) {
538*5c51f124SMoriah Waterland 		(void) close(fd);
539*5c51f124SMoriah Waterland 		return (-1);
540*5c51f124SMoriah Waterland 	}
541*5c51f124SMoriah Waterland 
542*5c51f124SMoriah Waterland 	return (fd);
543*5c51f124SMoriah Waterland }
544*5c51f124SMoriah Waterland 
545*5c51f124SMoriah Waterland /*
546*5c51f124SMoriah Waterland  * Helper routine for _zexec_prep_env below.
547*5c51f124SMoriah Waterland  */
548*5c51f124SMoriah Waterland char *
_zexec_add_env(char * name,char * value)549*5c51f124SMoriah Waterland _zexec_add_env(char *name, char *value)
550*5c51f124SMoriah Waterland {
551*5c51f124SMoriah Waterland 	size_t sz = strlen(name) + strlen(value) + 1;
552*5c51f124SMoriah Waterland 	char *str;
553*5c51f124SMoriah Waterland 
554*5c51f124SMoriah Waterland 	if ((str = malloc(sz)) == NULL)
555*5c51f124SMoriah Waterland 		return (NULL);
556*5c51f124SMoriah Waterland 
557*5c51f124SMoriah Waterland 	(void) snprintf(str, sz, "%s%s", name, value);
558*5c51f124SMoriah Waterland 	return (str);
559*5c51f124SMoriah Waterland }
560*5c51f124SMoriah Waterland 
561*5c51f124SMoriah Waterland /*
562*5c51f124SMoriah Waterland  * Prepare envp array for exec'd process.
563*5c51f124SMoriah Waterland  */
564*5c51f124SMoriah Waterland char **
_zexec_prep_env()565*5c51f124SMoriah Waterland _zexec_prep_env()
566*5c51f124SMoriah Waterland {
567*5c51f124SMoriah Waterland 	int e = 0, size = 1;
568*5c51f124SMoriah Waterland 	char **new_env, *estr;
569*5c51f124SMoriah Waterland 	char *term = getenv("TERM");
570*5c51f124SMoriah Waterland 
571*5c51f124SMoriah Waterland 	size++;	/* for $PATH */
572*5c51f124SMoriah Waterland 	if (term != NULL)
573*5c51f124SMoriah Waterland 		size++;
574*5c51f124SMoriah Waterland 
575*5c51f124SMoriah Waterland 	/*
576*5c51f124SMoriah Waterland 	 * In failsafe mode we set $HOME
577*5c51f124SMoriah Waterland 	 */
578*5c51f124SMoriah Waterland 	size++;
579*5c51f124SMoriah Waterland 
580*5c51f124SMoriah Waterland 	/*
581*5c51f124SMoriah Waterland 	 * In failsafe mode we set $SHELL, since login won't be around to do it.
582*5c51f124SMoriah Waterland 	 */
583*5c51f124SMoriah Waterland 	size++;
584*5c51f124SMoriah Waterland 
585*5c51f124SMoriah Waterland 	if ((new_env = malloc(sizeof (char *) * size)) == NULL)
586*5c51f124SMoriah Waterland 		return (NULL);
587*5c51f124SMoriah Waterland 
588*5c51f124SMoriah Waterland 	if ((estr = _zexec_add_env("PATH=", ZONE_DEF_PATH)) == NULL) {
589*5c51f124SMoriah Waterland 		free(new_env);
590*5c51f124SMoriah Waterland 		return (NULL);
591*5c51f124SMoriah Waterland 	}
592*5c51f124SMoriah Waterland 	new_env[e++] = estr;
593*5c51f124SMoriah Waterland 
594*5c51f124SMoriah Waterland 	if (term != NULL) {
595*5c51f124SMoriah Waterland 		if ((estr = _zexec_add_env("TERM=", term)) == NULL) {
596*5c51f124SMoriah Waterland 			free(new_env);
597*5c51f124SMoriah Waterland 			return (NULL);
598*5c51f124SMoriah Waterland 		}
599*5c51f124SMoriah Waterland 		new_env[e++] = estr;
600*5c51f124SMoriah Waterland 	}
601*5c51f124SMoriah Waterland 
602*5c51f124SMoriah Waterland 	if ((estr = _zexec_add_env("HOME=", "/")) == NULL) {
603*5c51f124SMoriah Waterland 		free(new_env);
604*5c51f124SMoriah Waterland 		return (NULL);
605*5c51f124SMoriah Waterland 	}
606*5c51f124SMoriah Waterland 	new_env[e++] = estr;
607*5c51f124SMoriah Waterland 
608*5c51f124SMoriah Waterland 	if ((estr = _zexec_add_env("SHELL=", ZONE_FAILSAFESHELL)) == NULL) {
609*5c51f124SMoriah Waterland 		free(new_env);
610*5c51f124SMoriah Waterland 		return (NULL);
611*5c51f124SMoriah Waterland 	}
612*5c51f124SMoriah Waterland 	new_env[e++] = estr;
613*5c51f124SMoriah Waterland 
614*5c51f124SMoriah Waterland 	new_env[e++] = NULL;
615*5c51f124SMoriah Waterland 
616*5c51f124SMoriah Waterland 	return (new_env);
617*5c51f124SMoriah Waterland }
618*5c51f124SMoriah Waterland 
619*5c51f124SMoriah Waterland /*
620*5c51f124SMoriah Waterland  * Name:	_z_zone_exec
621*5c51f124SMoriah Waterland  * Description:	Execute a Unix command in a specified zone and return results
622*5c51f124SMoriah Waterland  * Arguments:
623*5c51f124SMoriah Waterland  *		r_status - [RO, *RW] - (int *)
624*5c51f124SMoriah Waterland  *			Return (exit) status from Unix command:
625*5c51f124SMoriah Waterland  *			== -1 : child terminated with a signal
626*5c51f124SMoriah Waterland  *			!= -1 : lower 8-bit value child passed to exit()
627*5c51f124SMoriah Waterland  *		r_results - [RO, *RW] - (char **)
628*5c51f124SMoriah Waterland  *			Any output generated by the Unix command to stdout
629*5c51f124SMoriah Waterland  *			and to stderr
630*5c51f124SMoriah Waterland  *			== (char *)NULL if no output generated
631*5c51f124SMoriah Waterland  *		a_inputFile - [RO, *RO] - (char *)
632*5c51f124SMoriah Waterland  *			Pointer to character string representing file to be
633*5c51f124SMoriah Waterland  *			used as "standard input" for the command.
634*5c51f124SMoriah Waterland  *			== (char *)NULL to use "/dev/null" as standard input
635*5c51f124SMoriah Waterland  *		a_path - [RO, *RO] - (char *)
636*5c51f124SMoriah Waterland  *			Pointer to character string representing the full path
637*5c51f124SMoriah Waterland  *			*in the non-global zone named by a_zoneName*of the Unix
638*5c51f124SMoriah Waterland  *			command to be executed
639*5c51f124SMoriah Waterland  *		char **a_args - [RO, *RO] - (char **)
640*5c51f124SMoriah Waterland  *			List of character strings representing the arguments
641*5c51f124SMoriah Waterland  *			to be passed to the Unix command.
642*5c51f124SMoriah Waterland  *			NOTE: The list must be terminated with an element that
643*5c51f124SMoriah Waterland  *			----- is (char *)NULL
644*5c51f124SMoriah Waterland  *			NOTE: a_argv[0] is the "command name" passed to the
645*5c51f124SMoriah Waterland  *			----- command executed in the specified non-global zone
646*5c51f124SMoriah Waterland  *		a_zoneName - pointer to string representing the name of the zone
647*5c51f124SMoriah Waterland  *			to execute the specified command in
648*5c51f124SMoriah Waterland  *		a_fds - Pointer to array of integers representing file
649*5c51f124SMoriah Waterland  *			descriptors to remain open during the call - all
650*5c51f124SMoriah Waterland  *			file descriptors above STDERR_FILENO not in this
651*5c51f124SMoriah Waterland  *			list will be closed.
652*5c51f124SMoriah Waterland  * Returns:	int
653*5c51f124SMoriah Waterland  *			== 0 - Command executed
654*5c51f124SMoriah Waterland  *				Look at r_status for results of Unix command
655*5c51f124SMoriah Waterland  *			!= 0 - problems executing command
656*5c51f124SMoriah Waterland  *				r_status and r_results have no meaning;
657*5c51f124SMoriah Waterland  *				r_status will be -1
658*5c51f124SMoriah Waterland  *				r_results will be NULL
659*5c51f124SMoriah Waterland  *			The return (exit) code from the specified Unix command
660*5c51f124SMoriah Waterland  *			Special return codes:
661*5c51f124SMoriah Waterland  *			-1 : failure to exec process
662*5c51f124SMoriah Waterland  *			-2 : could not create contract for greenline
663*5c51f124SMoriah Waterland  *			-3 : fork() failed
664*5c51f124SMoriah Waterland  *			-4 : could not open stdin source file
665*5c51f124SMoriah Waterland  *			-5 : error from 'waitpid' other than EINTR
666*5c51f124SMoriah Waterland  *			-6 : zones are not supported
667*5c51f124SMoriah Waterland  *			-7 : interrupt received
668*5c51f124SMoriah Waterland  * NOTE:	All file descriptores other than 0, 1 and 2 are closed except
669*5c51f124SMoriah Waterland  *		for those file descriptors listed in the a_fds array.
670*5c51f124SMoriah Waterland  */
671*5c51f124SMoriah Waterland 
672*5c51f124SMoriah Waterland int
_z_zone_exec(int * r_status,char ** r_results,char * a_inputFile,char * a_path,char * a_argv[],const char * a_zoneName,int * a_fds)673*5c51f124SMoriah Waterland _z_zone_exec(int *r_status, char **r_results, char *a_inputFile,
674*5c51f124SMoriah Waterland 	char *a_path, char *a_argv[], const char *a_zoneName, int *a_fds)
675*5c51f124SMoriah Waterland {
676*5c51f124SMoriah Waterland 	struct sigaction	nact;
677*5c51f124SMoriah Waterland 	struct sigaction	oact;
678*5c51f124SMoriah Waterland 	char			*buffer;
679*5c51f124SMoriah Waterland 	char			*thisZoneName;
680*5c51f124SMoriah Waterland 	int			bufferIndex;
681*5c51f124SMoriah Waterland 	int			bufferSize;
682*5c51f124SMoriah Waterland 	int			exit_no;
683*5c51f124SMoriah Waterland 	int			ipipe[2] = {0, 0};
684*5c51f124SMoriah Waterland 	int			lerrno;
685*5c51f124SMoriah Waterland 	int			n;
686*5c51f124SMoriah Waterland 	int			status;
687*5c51f124SMoriah Waterland 	int			stdinfile = -1;
688*5c51f124SMoriah Waterland 	int			tmpl_fd;
689*5c51f124SMoriah Waterland 	pid_t			child_pid;
690*5c51f124SMoriah Waterland 	pid_t			result_pid;
691*5c51f124SMoriah Waterland 	void			(*funcSighup)();
692*5c51f124SMoriah Waterland 	void			(*funcSigint)();
693*5c51f124SMoriah Waterland 
694*5c51f124SMoriah Waterland 	/* entry assertions */
695*5c51f124SMoriah Waterland 
696*5c51f124SMoriah Waterland 	assert(a_path != (char *)NULL);
697*5c51f124SMoriah Waterland 	assert(*a_path != '\0');
698*5c51f124SMoriah Waterland 	assert(a_argv != (char **)NULL);
699*5c51f124SMoriah Waterland 	assert(a_argv[0] != (char *)NULL);
700*5c51f124SMoriah Waterland 	assert(*a_argv[0] != '\0');
701*5c51f124SMoriah Waterland 	assert(a_zoneName != (char *)NULL);
702*5c51f124SMoriah Waterland 
703*5c51f124SMoriah Waterland 	/*
704*5c51f124SMoriah Waterland 	 * if requested to execute in current zone name, directly execute
705*5c51f124SMoriah Waterland 	 */
706*5c51f124SMoriah Waterland 
707*5c51f124SMoriah Waterland 	thisZoneName = z_get_zonename();
708*5c51f124SMoriah Waterland 	status = (strcmp(a_zoneName, thisZoneName) == 0);
709*5c51f124SMoriah Waterland 
710*5c51f124SMoriah Waterland 	/* entry debugging info */
711*5c51f124SMoriah Waterland 
712*5c51f124SMoriah Waterland 	_z_echoDebug(DBG_ZONE_EXEC_CMD_ENTER, a_path, a_zoneName, thisZoneName);
713*5c51f124SMoriah Waterland 	(void) free(thisZoneName);
714*5c51f124SMoriah Waterland 	for (n = 0; a_argv[n]; n++) {
715*5c51f124SMoriah Waterland 		_z_echoDebug(DBG_ARG, n, a_argv[n]);
716*5c51f124SMoriah Waterland 	}
717*5c51f124SMoriah Waterland 
718*5c51f124SMoriah Waterland 	/* if this zone, just exec the command directly */
719*5c51f124SMoriah Waterland 
720*5c51f124SMoriah Waterland 	if (status != 0) {
721*5c51f124SMoriah Waterland 		return (z_ExecCmdArray(r_status, r_results, a_inputFile,
722*5c51f124SMoriah Waterland 		    a_path, a_argv));
723*5c51f124SMoriah Waterland 	}
724*5c51f124SMoriah Waterland 
725*5c51f124SMoriah Waterland 	/* reset return results buffer pointer */
726*5c51f124SMoriah Waterland 
727*5c51f124SMoriah Waterland 	if (r_results != (char **)NULL) {
728*5c51f124SMoriah Waterland 		*r_results = (char *)NULL;
729*5c51f124SMoriah Waterland 	}
730*5c51f124SMoriah Waterland 
731*5c51f124SMoriah Waterland 	*r_status = -1;	/* -1 : failure to exec process */
732*5c51f124SMoriah Waterland 
733*5c51f124SMoriah Waterland 	/* if zones are not implemented, return TRUE */
734*5c51f124SMoriah Waterland 
735*5c51f124SMoriah Waterland 	if (!z_zones_are_implemented()) {
736*5c51f124SMoriah Waterland 		return (-6);	/* -6 : zones are not supported */
737*5c51f124SMoriah Waterland 	}
738*5c51f124SMoriah Waterland 
739*5c51f124SMoriah Waterland 	if ((tmpl_fd = _zexec_init_template()) == -1) {
740*5c51f124SMoriah Waterland 		_z_program_error(ERR_CANNOT_CREATE_CONTRACT, strerror(errno));
741*5c51f124SMoriah Waterland 		return (-2);	/* -2 : cannot create greenline contract */
742*5c51f124SMoriah Waterland 	}
743*5c51f124SMoriah Waterland 
744*5c51f124SMoriah Waterland 	/*
745*5c51f124SMoriah Waterland 	 * See if input file exists
746*5c51f124SMoriah Waterland 	 */
747*5c51f124SMoriah Waterland 
748*5c51f124SMoriah Waterland 	if (a_inputFile != (char *)NULL) {
749*5c51f124SMoriah Waterland 		stdinfile = open(a_inputFile, O_RDONLY);
750*5c51f124SMoriah Waterland 	} else {
751*5c51f124SMoriah Waterland 		stdinfile = open("/dev/null", O_RDONLY); /* stdin = /dev/null */
752*5c51f124SMoriah Waterland 	}
753*5c51f124SMoriah Waterland 
754*5c51f124SMoriah Waterland 	if (stdinfile < 0) {
755*5c51f124SMoriah Waterland 		return (-4);	/* -4 : could not open stdin source file */
756*5c51f124SMoriah Waterland 	}
757*5c51f124SMoriah Waterland 
758*5c51f124SMoriah Waterland 	/*
759*5c51f124SMoriah Waterland 	 * Create a pipe to be used to capture the command output
760*5c51f124SMoriah Waterland 	 */
761*5c51f124SMoriah Waterland 
762*5c51f124SMoriah Waterland 	if (pipe(ipipe) != 0) {
763*5c51f124SMoriah Waterland 		(void) close(stdinfile);
764*5c51f124SMoriah Waterland 		return (-1);
765*5c51f124SMoriah Waterland 	}
766*5c51f124SMoriah Waterland 
767*5c51f124SMoriah Waterland 	bufferSize = PIPE_BUFFER_INCREMENT;
768*5c51f124SMoriah Waterland 	bufferIndex = 0;
769*5c51f124SMoriah Waterland 	buffer = calloc(1, bufferSize);
770*5c51f124SMoriah Waterland 	if (buffer == (char *)NULL) {
771*5c51f124SMoriah Waterland 		(void) close(stdinfile);
772*5c51f124SMoriah Waterland 		return (-1);
773*5c51f124SMoriah Waterland 	}
774*5c51f124SMoriah Waterland 
775*5c51f124SMoriah Waterland 	/* flush standard i/o before creating new process */
776*5c51f124SMoriah Waterland 
777*5c51f124SMoriah Waterland 	(void) fflush(stderr);
778*5c51f124SMoriah Waterland 	(void) fflush(stdout);
779*5c51f124SMoriah Waterland 
780*5c51f124SMoriah Waterland 	/*
781*5c51f124SMoriah Waterland 	 * hold SIGINT/SIGHUP signals and reset signal received counter;
782*5c51f124SMoriah Waterland 	 * after the fork1() the parent and child need to setup their respective
783*5c51f124SMoriah Waterland 	 * interrupt handling and release the hold on the signals
784*5c51f124SMoriah Waterland 	 */
785*5c51f124SMoriah Waterland 
786*5c51f124SMoriah Waterland 	(void) sighold(SIGINT);
787*5c51f124SMoriah Waterland 	(void) sighold(SIGHUP);
788*5c51f124SMoriah Waterland 
789*5c51f124SMoriah Waterland 	_z_global_data._z_SigReceived = 0;	/* no signals received */
790*5c51f124SMoriah Waterland 
791*5c51f124SMoriah Waterland 	/*
792*5c51f124SMoriah Waterland 	 * fork off a new process to execute command in;
793*5c51f124SMoriah Waterland 	 * fork1() is used instead of vfork() so the child process can
794*5c51f124SMoriah Waterland 	 * perform operations that would modify the parent process if
795*5c51f124SMoriah Waterland 	 * vfork() were used
796*5c51f124SMoriah Waterland 	 */
797*5c51f124SMoriah Waterland 
798*5c51f124SMoriah Waterland 	child_pid = fork1();
799*5c51f124SMoriah Waterland 
800*5c51f124SMoriah Waterland 	if (child_pid < 0) {
801*5c51f124SMoriah Waterland 		/*
802*5c51f124SMoriah Waterland 		 * *************************************************************
803*5c51f124SMoriah Waterland 		 * fork failed!
804*5c51f124SMoriah Waterland 		 * *************************************************************
805*5c51f124SMoriah Waterland 		 */
806*5c51f124SMoriah Waterland 
807*5c51f124SMoriah Waterland 		(void) ct_tmpl_clear(tmpl_fd);
808*5c51f124SMoriah Waterland 		(void) close(tmpl_fd);
809*5c51f124SMoriah Waterland 		(void) free(buffer);
810*5c51f124SMoriah Waterland 		_z_program_error(ERR_FORK, strerror(errno));
811*5c51f124SMoriah Waterland 
812*5c51f124SMoriah Waterland 		/* release hold on signals */
813*5c51f124SMoriah Waterland 		(void) sigrelse(SIGHUP);
814*5c51f124SMoriah Waterland 		(void) sigrelse(SIGINT);
815*5c51f124SMoriah Waterland 
816*5c51f124SMoriah Waterland 		return (-3);	/* -3 : fork() failed */
817*5c51f124SMoriah Waterland 	}
818*5c51f124SMoriah Waterland 
819*5c51f124SMoriah Waterland 	if (child_pid == 0) {
820*5c51f124SMoriah Waterland 		int	i;
821*5c51f124SMoriah Waterland 
822*5c51f124SMoriah Waterland 		/*
823*5c51f124SMoriah Waterland 		 * *************************************************************
824*5c51f124SMoriah Waterland 		 * This is the forked (child) process
825*5c51f124SMoriah Waterland 		 * *************************************************************
826*5c51f124SMoriah Waterland 		 */
827*5c51f124SMoriah Waterland 
828*5c51f124SMoriah Waterland 		(void) ct_tmpl_clear(tmpl_fd);
829*5c51f124SMoriah Waterland 		(void) close(tmpl_fd);
830*5c51f124SMoriah Waterland 
831*5c51f124SMoriah Waterland 		/* reset any signals to default */
832*5c51f124SMoriah Waterland 
833*5c51f124SMoriah Waterland 		for (i = 0; i < NSIG; i++) {
834*5c51f124SMoriah Waterland 			(void) sigset(i, SIG_DFL);
835*5c51f124SMoriah Waterland 		}
836*5c51f124SMoriah Waterland 
837*5c51f124SMoriah Waterland 		/* assign stdin, stdout, stderr as appropriate */
838*5c51f124SMoriah Waterland 
839*5c51f124SMoriah Waterland 		(void) dup2(stdinfile, STDIN_FILENO);
840*5c51f124SMoriah Waterland 		(void) close(ipipe[0]);		/* close out pipe reader side */
841*5c51f124SMoriah Waterland 		(void) dup2(ipipe[1], STDOUT_FILENO);
842*5c51f124SMoriah Waterland 		(void) dup2(ipipe[1], STDERR_FILENO);
843*5c51f124SMoriah Waterland 
844*5c51f124SMoriah Waterland 		/*
845*5c51f124SMoriah Waterland 		 * close all file descriptors not in the a_fds list
846*5c51f124SMoriah Waterland 		 */
847*5c51f124SMoriah Waterland 
848*5c51f124SMoriah Waterland 		(void) fdwalk(&_z_close_file_descriptors, (void *)a_fds);
849*5c51f124SMoriah Waterland 
850*5c51f124SMoriah Waterland 		/* release all held signals */
851*5c51f124SMoriah Waterland 
852*5c51f124SMoriah Waterland 		(void) sigrelse(SIGHUP);
853*5c51f124SMoriah Waterland 		(void) sigrelse(SIGINT);
854*5c51f124SMoriah Waterland 
855*5c51f124SMoriah Waterland 		/* execute command in the specified non-global zone */
856*5c51f124SMoriah Waterland 
857*5c51f124SMoriah Waterland 		_exit(_zexec(a_zoneName, a_path, a_argv));
858*5c51f124SMoriah Waterland 	}
859*5c51f124SMoriah Waterland 
860*5c51f124SMoriah Waterland 	/*
861*5c51f124SMoriah Waterland 	 * *********************************************************************
862*5c51f124SMoriah Waterland 	 * This is the forking (parent) process
863*5c51f124SMoriah Waterland 	 * *********************************************************************
864*5c51f124SMoriah Waterland 	 */
865*5c51f124SMoriah Waterland 
866*5c51f124SMoriah Waterland 	/* register child process i.d. so signal handlers can pass signal on */
867*5c51f124SMoriah Waterland 
868*5c51f124SMoriah Waterland 	_z_global_data._z_ChildProcessId = child_pid;
869*5c51f124SMoriah Waterland 
870*5c51f124SMoriah Waterland 	/*
871*5c51f124SMoriah Waterland 	 * setup signal handlers for SIGINT and SIGHUP and release hold
872*5c51f124SMoriah Waterland 	 */
873*5c51f124SMoriah Waterland 
874*5c51f124SMoriah Waterland 	/* hook SIGINT to _z_sig_trap() */
875*5c51f124SMoriah Waterland 
876*5c51f124SMoriah Waterland 	nact.sa_handler = _z_sig_trap;
877*5c51f124SMoriah Waterland 	nact.sa_flags = SA_RESTART;
878*5c51f124SMoriah Waterland 	(void) sigemptyset(&nact.sa_mask);
879*5c51f124SMoriah Waterland 
880*5c51f124SMoriah Waterland 	if (sigaction(SIGINT, &nact, &oact) < 0) {
881*5c51f124SMoriah Waterland 		funcSigint = SIG_DFL;
882*5c51f124SMoriah Waterland 	} else {
883*5c51f124SMoriah Waterland 		funcSigint = oact.sa_handler;
884*5c51f124SMoriah Waterland 	}
885*5c51f124SMoriah Waterland 
886*5c51f124SMoriah Waterland 	/* hook SIGHUP to _z_sig_trap() */
887*5c51f124SMoriah Waterland 
888*5c51f124SMoriah Waterland 	nact.sa_handler = _z_sig_trap;
889*5c51f124SMoriah Waterland 	nact.sa_flags = SA_RESTART;
890*5c51f124SMoriah Waterland 	(void) sigemptyset(&nact.sa_mask);
891*5c51f124SMoriah Waterland 
892*5c51f124SMoriah Waterland 	if (sigaction(SIGHUP, &nact, &oact) < 0) {
893*5c51f124SMoriah Waterland 		funcSighup = SIG_DFL;
894*5c51f124SMoriah Waterland 	} else {
895*5c51f124SMoriah Waterland 		funcSighup = oact.sa_handler;
896*5c51f124SMoriah Waterland 	}
897*5c51f124SMoriah Waterland 
898*5c51f124SMoriah Waterland 	/* release hold on signals */
899*5c51f124SMoriah Waterland 
900*5c51f124SMoriah Waterland 	(void) sigrelse(SIGHUP);
901*5c51f124SMoriah Waterland 	(void) sigrelse(SIGINT);
902*5c51f124SMoriah Waterland 
903*5c51f124SMoriah Waterland 	(void) ct_tmpl_clear(tmpl_fd);
904*5c51f124SMoriah Waterland 	(void) close(tmpl_fd);
905*5c51f124SMoriah Waterland 
906*5c51f124SMoriah Waterland 	(void) close(stdinfile);
907*5c51f124SMoriah Waterland 	(void) close(ipipe[1]);		/* Close write side of pipe */
908*5c51f124SMoriah Waterland 
909*5c51f124SMoriah Waterland 	/*
910*5c51f124SMoriah Waterland 	 * Spin reading data from the child into the buffer - when the read eofs
911*5c51f124SMoriah Waterland 	 * the child has exited
912*5c51f124SMoriah Waterland 	 */
913*5c51f124SMoriah Waterland 
914*5c51f124SMoriah Waterland 	for (;;) {
915*5c51f124SMoriah Waterland 		ssize_t	bytesRead;
916*5c51f124SMoriah Waterland 
917*5c51f124SMoriah Waterland 		/* read as much child data as there is available buffer space */
918*5c51f124SMoriah Waterland 
919*5c51f124SMoriah Waterland 		bytesRead = read(ipipe[0], buffer + bufferIndex,
920*5c51f124SMoriah Waterland 		    bufferSize - bufferIndex);
921*5c51f124SMoriah Waterland 
922*5c51f124SMoriah Waterland 		/* break out of read loop if end-of-file encountered */
923*5c51f124SMoriah Waterland 
924*5c51f124SMoriah Waterland 		if (bytesRead == 0) {
925*5c51f124SMoriah Waterland 			break;
926*5c51f124SMoriah Waterland 		}
927*5c51f124SMoriah Waterland 
928*5c51f124SMoriah Waterland 		/* if error, continue if recoverable, else break out of loop */
929*5c51f124SMoriah Waterland 
930*5c51f124SMoriah Waterland 		if (bytesRead == -1) {
931*5c51f124SMoriah Waterland 			/* try again: EAGAIN - insufficient resources */
932*5c51f124SMoriah Waterland 
933*5c51f124SMoriah Waterland 			if (errno == EAGAIN) {
934*5c51f124SMoriah Waterland 				continue;
935*5c51f124SMoriah Waterland 			}
936*5c51f124SMoriah Waterland 
937*5c51f124SMoriah Waterland 			/* try again: EINTR - interrupted system call */
938*5c51f124SMoriah Waterland 
939*5c51f124SMoriah Waterland 			if (errno == EINTR) {
940*5c51f124SMoriah Waterland 				continue;
941*5c51f124SMoriah Waterland 			}
942*5c51f124SMoriah Waterland 
943*5c51f124SMoriah Waterland 			/* break out of loop - error not recoverable */
944*5c51f124SMoriah Waterland 			break;
945*5c51f124SMoriah Waterland 		}
946*5c51f124SMoriah Waterland 
947*5c51f124SMoriah Waterland 		/* at least 1 byte read: expand buffer if at end */
948*5c51f124SMoriah Waterland 
949*5c51f124SMoriah Waterland 		bufferIndex += bytesRead;
950*5c51f124SMoriah Waterland 		if (bufferIndex >= bufferSize) {
951*5c51f124SMoriah Waterland 			buffer = realloc(buffer,
952*5c51f124SMoriah Waterland 			    bufferSize += PIPE_BUFFER_INCREMENT);
953*5c51f124SMoriah Waterland 			(void) memset(buffer + bufferIndex, 0,
954*5c51f124SMoriah Waterland 			    bufferSize - bufferIndex);
955*5c51f124SMoriah Waterland 		}
956*5c51f124SMoriah Waterland 	}
957*5c51f124SMoriah Waterland 
958*5c51f124SMoriah Waterland 	(void) close(ipipe[0]);		/* Close read side of pipe */
959*5c51f124SMoriah Waterland 
960*5c51f124SMoriah Waterland 	/*
961*5c51f124SMoriah Waterland 	 * wait for the process to exit, reap child exit status
962*5c51f124SMoriah Waterland 	 */
963*5c51f124SMoriah Waterland 
964*5c51f124SMoriah Waterland 	for (;;) {
965*5c51f124SMoriah Waterland 		result_pid = waitpid(child_pid, &status, 0L);
966*5c51f124SMoriah Waterland 		lerrno = (result_pid == -1 ? errno : 0);
967*5c51f124SMoriah Waterland 
968*5c51f124SMoriah Waterland 		/* break loop if child process status reaped */
969*5c51f124SMoriah Waterland 
970*5c51f124SMoriah Waterland 		if (result_pid != -1) {
971*5c51f124SMoriah Waterland 			break;
972*5c51f124SMoriah Waterland 		}
973*5c51f124SMoriah Waterland 
974*5c51f124SMoriah Waterland 		/* break loop if not interrupted out of waitpid */
975*5c51f124SMoriah Waterland 
976*5c51f124SMoriah Waterland 		if (errno != EINTR) {
977*5c51f124SMoriah Waterland 			break;
978*5c51f124SMoriah Waterland 		}
979*5c51f124SMoriah Waterland 	}
980*5c51f124SMoriah Waterland 
981*5c51f124SMoriah Waterland 	/* reset child process i.d. so signal handlers do not pass signals on */
982*5c51f124SMoriah Waterland 
983*5c51f124SMoriah Waterland 	_z_global_data._z_ChildProcessId = -1;
984*5c51f124SMoriah Waterland 
985*5c51f124SMoriah Waterland 	/*
986*5c51f124SMoriah Waterland 	 * If the child process terminated due to a call to exit(), then
987*5c51f124SMoriah Waterland 	 * set results equal to the 8-bit exit status of the child process;
988*5c51f124SMoriah Waterland 	 * otherwise, set the exit status to "-1" indicating that the child
989*5c51f124SMoriah Waterland 	 * exited via a signal.
990*5c51f124SMoriah Waterland 	 */
991*5c51f124SMoriah Waterland 
992*5c51f124SMoriah Waterland 	if (WIFEXITED(status)) {
993*5c51f124SMoriah Waterland 		*r_status = WEXITSTATUS(status);
994*5c51f124SMoriah Waterland 		if ((_z_global_data._z_SigReceived != 0) && (*r_status == 0)) {
995*5c51f124SMoriah Waterland 			*r_status = 1;
996*5c51f124SMoriah Waterland 		}
997*5c51f124SMoriah Waterland 	} else {
998*5c51f124SMoriah Waterland 		*r_status = -1;	/* -1 : failure to exec process */
999*5c51f124SMoriah Waterland 	}
1000*5c51f124SMoriah Waterland 
1001*5c51f124SMoriah Waterland 	/* determine proper exit code */
1002*5c51f124SMoriah Waterland 
1003*5c51f124SMoriah Waterland 	if (result_pid == -1) {
1004*5c51f124SMoriah Waterland 		exit_no = -5;	/* -5 : error from 'waitpid' other than EINTR */
1005*5c51f124SMoriah Waterland 	} else if (_z_global_data._z_SigReceived != 0) {
1006*5c51f124SMoriah Waterland 		exit_no = -7;	/* -7 : interrupt received */
1007*5c51f124SMoriah Waterland 	} else {
1008*5c51f124SMoriah Waterland 		exit_no = 0;
1009*5c51f124SMoriah Waterland 	}
1010*5c51f124SMoriah Waterland 
1011*5c51f124SMoriah Waterland 	/* return appropriate output */
1012*5c51f124SMoriah Waterland 
1013*5c51f124SMoriah Waterland 	if (!*buffer) {
1014*5c51f124SMoriah Waterland 		/* No contents in output buffer - discard */
1015*5c51f124SMoriah Waterland 		free(buffer);
1016*5c51f124SMoriah Waterland 	} else if (r_results == (char **)NULL) {
1017*5c51f124SMoriah Waterland 		/* Not requested to return results - discard */
1018*5c51f124SMoriah Waterland 		free(buffer);
1019*5c51f124SMoriah Waterland 	} else {
1020*5c51f124SMoriah Waterland 		/* have output and request to return: pass to calling method */
1021*5c51f124SMoriah Waterland 		*r_results = buffer;
1022*5c51f124SMoriah Waterland 	}
1023*5c51f124SMoriah Waterland 
1024*5c51f124SMoriah Waterland 	/*
1025*5c51f124SMoriah Waterland 	 * reset signal handlers
1026*5c51f124SMoriah Waterland 	 */
1027*5c51f124SMoriah Waterland 
1028*5c51f124SMoriah Waterland 	/* reset SIGINT */
1029*5c51f124SMoriah Waterland 
1030*5c51f124SMoriah Waterland 	nact.sa_handler = funcSigint;
1031*5c51f124SMoriah Waterland 	nact.sa_flags = SA_RESTART;
1032*5c51f124SMoriah Waterland 	(void) sigemptyset(&nact.sa_mask);
1033*5c51f124SMoriah Waterland 
1034*5c51f124SMoriah Waterland 	(void) sigaction(SIGINT, &nact, (struct sigaction *)NULL);
1035*5c51f124SMoriah Waterland 
1036*5c51f124SMoriah Waterland 	/* reset SIGHUP */
1037*5c51f124SMoriah Waterland 
1038*5c51f124SMoriah Waterland 	nact.sa_handler = funcSighup;
1039*5c51f124SMoriah Waterland 	nact.sa_flags = SA_RESTART;
1040*5c51f124SMoriah Waterland 	(void) sigemptyset(&nact.sa_mask);
1041*5c51f124SMoriah Waterland 
1042*5c51f124SMoriah Waterland 	(void) sigaction(SIGHUP, &nact, (struct sigaction *)NULL);
1043*5c51f124SMoriah Waterland 
1044*5c51f124SMoriah Waterland 	/*
1045*5c51f124SMoriah Waterland 	 * if signal received during command execution, interrupt
1046*5c51f124SMoriah Waterland 	 * this process now.
1047*5c51f124SMoriah Waterland 	 */
1048*5c51f124SMoriah Waterland 
1049*5c51f124SMoriah Waterland 	if (_z_global_data._z_SigReceived != 0) {
1050*5c51f124SMoriah Waterland 		(void) kill(getpid(), SIGINT);
1051*5c51f124SMoriah Waterland 	}
1052*5c51f124SMoriah Waterland 
1053*5c51f124SMoriah Waterland 	/* set errno and return */
1054*5c51f124SMoriah Waterland 
1055*5c51f124SMoriah Waterland 	errno = lerrno;
1056*5c51f124SMoriah Waterland 
1057*5c51f124SMoriah Waterland 	return (exit_no);
1058*5c51f124SMoriah Waterland }
1059*5c51f124SMoriah Waterland 
1060*5c51f124SMoriah Waterland /*
1061*5c51f124SMoriah Waterland  * Name:	z_ExecCmdList
1062*5c51f124SMoriah Waterland  * Synopsis:	Execute Unix command and return results
1063*5c51f124SMoriah Waterland  * Description:	Execute a Unix command and return results and status
1064*5c51f124SMoriah Waterland  * Arguments:
1065*5c51f124SMoriah Waterland  *		r_status - [RO, *RW] - (int *)
1066*5c51f124SMoriah Waterland  *			Return (exit) status from Unix command
1067*5c51f124SMoriah Waterland  *		r_results - [RO, *RW] - (char **)
1068*5c51f124SMoriah Waterland  *			Any output generated by the Unix command to stdout
1069*5c51f124SMoriah Waterland  *			and to stderr
1070*5c51f124SMoriah Waterland  *			== (char *)NULL if no output generated
1071*5c51f124SMoriah Waterland  *		a_inputFile - [RO, *RO] - (char *)
1072*5c51f124SMoriah Waterland  *			Pointer to character string representing file to be
1073*5c51f124SMoriah Waterland  *			used as "standard input" for the command.
1074*5c51f124SMoriah Waterland  *			== (char *)NULL to use "/dev/null" as standard input
1075*5c51f124SMoriah Waterland  *		a_cmd - [RO, *RO] - (char *)
1076*5c51f124SMoriah Waterland  *			Pointer to character string representing the full path
1077*5c51f124SMoriah Waterland  *			of the Unix command to execute
1078*5c51f124SMoriah Waterland  *		... - [RO] (?)
1079*5c51f124SMoriah Waterland  *			Zero or more arguments to the Unix command
1080*5c51f124SMoriah Waterland  *			The argument list must be ended with (void *)NULL
1081*5c51f124SMoriah Waterland  * Returns:	int
1082*5c51f124SMoriah Waterland  *			== 0 - Command executed
1083*5c51f124SMoriah Waterland  *				Look at r_status for results of Unix command
1084*5c51f124SMoriah Waterland  *			!= 0 - problems executing command
1085*5c51f124SMoriah Waterland  *				r_status and r_results have no meaning
1086*5c51f124SMoriah Waterland  * NOTE:    	Any results returned is placed in new storage for the
1087*5c51f124SMoriah Waterland  *		calling method. The caller must use 'free' to dispose
1088*5c51f124SMoriah Waterland  *		of the storage once the results are no longer needed.
1089*5c51f124SMoriah Waterland  * NOTE:	If LU_SUCCESS is returned, 'r_status' must be queried to
1090*5c51f124SMoriah Waterland  *		determine the results of the Unix command.
1091*5c51f124SMoriah Waterland  */
1092*5c51f124SMoriah Waterland 
1093*5c51f124SMoriah Waterland /*VARARGS*/
1094*5c51f124SMoriah Waterland int
z_ExecCmdList(int * r_status,char ** r_results,char * a_inputFile,char * a_cmd,...)1095*5c51f124SMoriah Waterland z_ExecCmdList(int *r_status, char **r_results,
1096*5c51f124SMoriah Waterland 	char *a_inputFile, char *a_cmd, ...)
1097*5c51f124SMoriah Waterland {
1098*5c51f124SMoriah Waterland 	va_list		ap;		/* references variable argument list */
1099*5c51f124SMoriah Waterland 	char		*array[MAX_EXEC_CMD_ARGS+1];
1100*5c51f124SMoriah Waterland 	int		argno = 0;
1101*5c51f124SMoriah Waterland 
1102*5c51f124SMoriah Waterland 	/*
1103*5c51f124SMoriah Waterland 	 * Create argument array for exec system call
1104*5c51f124SMoriah Waterland 	 */
1105*5c51f124SMoriah Waterland 
1106*5c51f124SMoriah Waterland 	bzero(array, sizeof (array));
1107*5c51f124SMoriah Waterland 
1108*5c51f124SMoriah Waterland 	va_start(ap, a_cmd);	/* Begin variable argument processing */
1109*5c51f124SMoriah Waterland 
1110*5c51f124SMoriah Waterland 	for (argno = 0; argno < MAX_EXEC_CMD_ARGS; argno++) {
1111*5c51f124SMoriah Waterland 		array[argno] = va_arg(ap, char *);
1112*5c51f124SMoriah Waterland 		if (array[argno] == (char *)NULL) {
1113*5c51f124SMoriah Waterland 			break;
1114*5c51f124SMoriah Waterland 		}
1115*5c51f124SMoriah Waterland 	}
1116*5c51f124SMoriah Waterland 
1117*5c51f124SMoriah Waterland 	va_end(ap);
1118*5c51f124SMoriah Waterland 	return (z_ExecCmdArray(r_status, r_results, a_inputFile,
1119*5c51f124SMoriah Waterland 	    a_cmd, array));
1120*5c51f124SMoriah Waterland }
1121