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