1 /* 2 * Copyright (c) 1988 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software written by Ken Arnold and 6 * published in UNIX Review, Vol. 6, No. 8. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #if defined(LIBC_SCCS) && !defined(lint) 12 static char sccsid[] = "@(#)popen.c 5.17 (Berkeley) 04/14/92"; 13 #endif /* LIBC_SCCS and not lint */ 14 15 #include <sys/param.h> 16 #include <sys/wait.h> 17 18 #include <signal.h> 19 #include <errno.h> 20 #include <unistd.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <paths.h> 25 26 static struct pid { 27 struct pid *next; 28 FILE *fp; 29 pid_t pid; 30 } *pidlist; 31 32 FILE * 33 popen(program, type) 34 const char *program; 35 const char *type; 36 { 37 struct pid *cur; 38 FILE *iop; 39 int pdes[2], pid; 40 41 if (*type != 'r' && *type != 'w' || type[1]) 42 return (NULL); 43 44 if ((cur = malloc(sizeof(struct pid))) == NULL) 45 return (NULL); 46 47 if (pipe(pdes) < 0) { 48 (void)free(cur); 49 return (NULL); 50 } 51 52 switch (pid = vfork()) { 53 case -1: /* Error. */ 54 (void)close(pdes[0]); 55 (void)close(pdes[1]); 56 (void)free(cur); 57 return (NULL); 58 /* NOTREACHED */ 59 case 0: /* Child. */ 60 if (*type == 'r') { 61 if (pdes[1] != STDOUT_FILENO) { 62 (void)dup2(pdes[1], STDOUT_FILENO); 63 (void)close(pdes[1]); 64 } 65 (void) close(pdes[0]); 66 } else { 67 if (pdes[0] != STDIN_FILENO) { 68 (void)dup2(pdes[0], STDIN_FILENO); 69 (void)close(pdes[0]); 70 } 71 (void)close(pdes[1]); 72 } 73 execl(_PATH_BSHELL, "sh", "-c", program, NULL); 74 _exit(127); 75 /* NOTREACHED */ 76 } 77 78 /* Parent; assume fdopen can't fail. */ 79 if (*type == 'r') { 80 iop = fdopen(pdes[0], type); 81 (void)close(pdes[1]); 82 } else { 83 iop = fdopen(pdes[1], type); 84 (void)close(pdes[0]); 85 } 86 87 /* Link into list of file descriptors. */ 88 cur->fp = iop; 89 cur->pid = pid; 90 cur->next = pidlist; 91 pidlist = cur; 92 93 return (iop); 94 } 95 96 /* 97 * pclose -- 98 * Pclose returns -1 if stream is not associated with a `popened' command, 99 * if already `pclosed', or waitpid returns an error. 100 */ 101 int 102 pclose(iop) 103 FILE *iop; 104 { 105 register struct pid *cur, *last; 106 int omask; 107 union wait pstat; 108 pid_t pid; 109 110 (void)fclose(iop); 111 112 /* Find the appropriate file pointer. */ 113 for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next) 114 if (cur->fp == iop) 115 break; 116 if (cur == NULL) 117 return (-1); 118 119 /* Get the status of the process. */ 120 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 121 do { 122 pid = waitpid(cur->pid, (int *) &pstat, 0); 123 } while (pid == -1 && errno == EINTR); 124 (void)sigsetmask(omask); 125 126 /* Remove the entry from the linked list. */ 127 if (last == NULL) 128 pidlist = cur->next; 129 else 130 last->next = cur->next; 131 free(cur); 132 133 return (pid == -1 ? -1 : pstat.w_status); 134 } 135