1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)popen.c 5.14 (Berkeley) 06/01/90"; 10 #endif /* not lint */ 11 12 #include "rcv.h" 13 #include <sys/signal.h> 14 #include <sys/wait.h> 15 16 #define READ 0 17 #define WRITE 1 18 static int *pid; 19 20 FILE * 21 Popen(cmd, mode) 22 char *cmd; 23 char *mode; 24 { 25 int p[2]; 26 int myside, hisside, fd0, fd1; 27 28 if (pid == 0) 29 pid = (int *) malloc((unsigned) sizeof (int) * getdtablesize()); 30 if (pipe(p) < 0) 31 return NULL; 32 if (*mode == 'r') { 33 myside = p[READ]; 34 fd0 = -1; 35 hisside = fd1 = p[WRITE]; 36 } else { 37 myside = p[WRITE]; 38 hisside = fd0 = p[READ]; 39 fd1 = -1; 40 } 41 if ((pid[myside] = start_command(cmd, 0, fd0, fd1, NOSTR)) < 0) { 42 close(p[READ]); 43 close(p[WRITE]); 44 return NULL; 45 } 46 close(hisside); 47 return fdopen(myside, mode); 48 } 49 50 Pclose(ptr) 51 FILE *ptr; 52 { 53 int i; 54 int omask; 55 56 i = fileno(ptr); 57 fclose(ptr); 58 omask = sigblock(sigmask(SIGINT)|sigmask(SIGHUP)); 59 i = wait_child(pid[i]); 60 sigsetmask(omask); 61 return i; 62 } 63 64 /* 65 * Run a command without a shell, with optional arguments and splicing 66 * of stdin and stdout. The command name can be a sequence of words. 67 * Signals must be handled by the caller. 68 * "Mask" contains the signals to ignore in the new process. 69 * SIGINT is enabled unless it's in the mask. 70 */ 71 /*VARARGS4*/ 72 run_command(cmd, mask, infd, outfd, a0, a1, a2) 73 char *cmd; 74 int mask, infd, outfd; 75 char *a0, *a1, *a2; 76 { 77 int pid; 78 79 if ((pid = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0) 80 return -1; 81 return wait_command(pid); 82 } 83 84 /*VARARGS4*/ 85 start_command(cmd, mask, infd, outfd, a0, a1, a2) 86 char *cmd; 87 int mask, infd, outfd; 88 char *a0, *a1, *a2; 89 { 90 int pid; 91 92 if ((pid = vfork()) < 0) { 93 perror("fork"); 94 return -1; 95 } 96 if (pid == 0) { 97 char *argv[100]; 98 int i = getrawlist(cmd, argv, sizeof argv / sizeof *argv); 99 100 if ((argv[i++] = a0) != NOSTR && 101 (argv[i++] = a1) != NOSTR && 102 (argv[i++] = a2) != NOSTR) 103 argv[i] = NOSTR; 104 prepare_child(mask, infd, outfd); 105 execvp(argv[0], argv); 106 perror(argv[0]); 107 _exit(1); 108 } 109 return pid; 110 } 111 112 prepare_child(mask, infd, outfd) 113 int mask, infd, outfd; 114 { 115 int i; 116 117 if (infd >= 0) 118 dup2(infd, 0); 119 if (outfd >= 0) 120 dup2(outfd, 1); 121 for (i = getdtablesize(); --i > 2;) 122 close(i); 123 for (i = 1; i <= NSIG; i++) 124 if (mask & sigmask(i)) 125 (void) signal(i, SIG_IGN); 126 if ((mask & sigmask(SIGINT)) == 0) 127 (void) signal(SIGINT, SIG_DFL); 128 (void) sigsetmask(0); 129 } 130 131 wait_command(pid) 132 int pid; 133 { 134 135 if (wait_child(pid) < 0) { 136 printf("Fatal error in process.\n"); 137 return -1; 138 } 139 return 0; 140 } 141 142 struct child { 143 int pid; 144 char done; 145 char free; 146 union wait status; 147 struct child *link; 148 }; 149 static struct child *child; 150 151 struct child * 152 findchild(pid) 153 int pid; 154 { 155 register struct child **cpp; 156 157 for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid; 158 cpp = &(*cpp)->link) 159 ; 160 if (*cpp == NULL) { 161 *cpp = (struct child *) malloc(sizeof (struct child)); 162 (*cpp)->pid = pid; 163 (*cpp)->done = (*cpp)->free = 0; 164 (*cpp)->link = NULL; 165 } 166 return *cpp; 167 } 168 169 delchild(cp) 170 register struct child *cp; 171 { 172 register struct child **cpp; 173 174 for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link) 175 ; 176 *cpp = cp->link; 177 free((char *) cp); 178 } 179 180 sigchild() 181 { 182 int pid; 183 union wait status; 184 register struct child *cp; 185 186 while ((pid = wait3(&status, WNOHANG, (struct timeval *)0)) > 0) { 187 cp = findchild(pid); 188 if (cp->free) 189 delchild(cp); 190 else { 191 cp->done = 1; 192 cp->status = status; 193 } 194 } 195 } 196 197 union wait wait_status; 198 199 /* 200 * Wait for a specific child to die. 201 */ 202 wait_child(pid) 203 int pid; 204 { 205 int mask = sigblock(sigmask(SIGCHLD)); 206 register struct child *cp = findchild(pid); 207 208 while (!cp->done) 209 sigpause(mask); 210 wait_status = cp->status; 211 delchild(cp); 212 sigsetmask(mask); 213 return wait_status.w_status ? -1 : 0; 214 } 215 216 /* 217 * Mark a child as don't care. 218 */ 219 free_child(pid) 220 int pid; 221 { 222 int mask = sigblock(sigmask(SIGCHLD)); 223 register struct child *cp = findchild(pid); 224 225 if (cp->done) 226 delchild(cp); 227 else 228 cp->free = 1; 229 sigsetmask(mask); 230 } 231