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