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
rpterr(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
ecleanup(void)111 ecleanup(void)
112 {
113 if (errfile[0]) {
114 (void) unlink(errfile);
115 errfile[0] = NULL;
116 }
117 }
118
119 int
esystem(char * cmd,int ifd,int ofd)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 *
epopen(char * cmd,char * mode)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
epclose(FILE * pp)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
e_ExecCmdArray(int * r_status,char ** r_results,char * a_inputFile,char * a_cmd,char ** a_args)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
e_ExecCmdList(int * r_status,char ** r_results,char * a_inputFile,char * a_cmd,...)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 *
e_new_args(int initialCount)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
e_add_arg(argArray_t * a_args,char * a_format,...)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 **
e_get_argv(argArray_t * a_args)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
e_get_argc(argArray_t * a_args)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
e_free_args(argArray_t * a_args)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