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 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 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 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 * 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 ** 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 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 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