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