1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 static char sccsid[] = "@(#)popen.c 5.16 (Berkeley) 4/1/91"; 36 #endif /* not lint */ 37 38 #include "rcv.h" 39 #include <sys/signal.h> 40 #include <sys/wait.h> 41 42 #define READ 0 43 #define WRITE 1 44 static int *pid; 45 46 struct fp { 47 FILE *fp; 48 int pipe; 49 struct fp *link; 50 }; 51 static struct fp *fp_head; 52 53 FILE * 54 Fopen(file, mode) 55 char *file, *mode; 56 { 57 FILE *fp; 58 59 if ((fp = fopen(file, mode)) != NULL) 60 register_file(fp, 0); 61 return fp; 62 } 63 64 FILE * 65 Fdopen(fd, mode) 66 char *mode; 67 { 68 FILE *fp; 69 70 if ((fp = fdopen(fd, mode)) != NULL) 71 register_file(fp, 0); 72 return fp; 73 } 74 75 Fclose(fp) 76 FILE *fp; 77 { 78 unregister_file(fp); 79 return fclose(fp); 80 } 81 82 FILE * 83 Popen(cmd, mode) 84 char *cmd; 85 char *mode; 86 { 87 int p[2]; 88 int myside, hisside, fd0, fd1; 89 FILE *fp; 90 91 if (pid == 0) 92 pid = (int *) malloc((unsigned) sizeof (int) * getdtablesize()); 93 if (pipe(p) < 0) 94 return NULL; 95 if (*mode == 'r') { 96 myside = p[READ]; 97 fd0 = -1; 98 hisside = fd1 = p[WRITE]; 99 } else { 100 myside = p[WRITE]; 101 hisside = fd0 = p[READ]; 102 fd1 = -1; 103 } 104 if ((pid[myside] = start_command(cmd, 0, fd0, fd1, NOSTR)) < 0) { 105 close(p[READ]); 106 close(p[WRITE]); 107 return NULL; 108 } 109 (void) close(hisside); 110 if ((fp = fdopen(myside, mode)) != NULL) 111 register_file(fp, 1); 112 return fp; 113 } 114 115 Pclose(ptr) 116 FILE *ptr; 117 { 118 int i; 119 int omask; 120 121 i = fileno(ptr); 122 unregister_file(ptr); 123 (void) fclose(ptr); 124 omask = sigblock(sigmask(SIGINT)|sigmask(SIGHUP)); 125 i = wait_child(pid[i]); 126 sigsetmask(omask); 127 return i; 128 } 129 130 close_all_files() 131 { 132 133 while (fp_head) 134 if (fp_head->pipe) 135 (void) Pclose(fp_head->fp); 136 else 137 (void) Fclose(fp_head->fp); 138 } 139 140 register_file(fp, pipe) 141 FILE *fp; 142 { 143 struct fp *fpp; 144 145 if ((fpp = (struct fp *) malloc(sizeof *fpp)) == NULL) 146 panic("Out of memory"); 147 fpp->fp = fp; 148 fpp->pipe = pipe; 149 fpp->link = fp_head; 150 fp_head = fpp; 151 } 152 153 unregister_file(fp) 154 FILE *fp; 155 { 156 struct fp **pp, *p; 157 158 for (pp = &fp_head; p = *pp; pp = &p->link) 159 if (p->fp == fp) { 160 *pp = p->link; 161 free((char *) p); 162 return; 163 } 164 /* XXX 165 * Ignore this for now; there may still be uncaught 166 * duplicate closes. 167 panic("Invalid file pointer"); 168 */ 169 } 170 171 /* 172 * Run a command without a shell, with optional arguments and splicing 173 * of stdin and stdout. The command name can be a sequence of words. 174 * Signals must be handled by the caller. 175 * "Mask" contains the signals to ignore in the new process. 176 * SIGINT is enabled unless it's in the mask. 177 */ 178 /*VARARGS4*/ 179 run_command(cmd, mask, infd, outfd, a0, a1, a2) 180 char *cmd; 181 int mask, infd, outfd; 182 char *a0, *a1, *a2; 183 { 184 int pid; 185 186 if ((pid = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0) 187 return -1; 188 return wait_command(pid); 189 } 190 191 /*VARARGS4*/ 192 start_command(cmd, mask, infd, outfd, a0, a1, a2) 193 char *cmd; 194 int mask, infd, outfd; 195 char *a0, *a1, *a2; 196 { 197 int pid; 198 199 if ((pid = vfork()) < 0) { 200 perror("fork"); 201 return -1; 202 } 203 if (pid == 0) { 204 char *argv[100]; 205 int i = getrawlist(cmd, argv, sizeof argv / sizeof *argv); 206 207 if ((argv[i++] = a0) != NOSTR && 208 (argv[i++] = a1) != NOSTR && 209 (argv[i++] = a2) != NOSTR) 210 argv[i] = NOSTR; 211 prepare_child(mask, infd, outfd); 212 execvp(argv[0], argv); 213 perror(argv[0]); 214 _exit(1); 215 } 216 return pid; 217 } 218 219 prepare_child(mask, infd, outfd) 220 int mask, infd, outfd; 221 { 222 int i; 223 224 if (infd >= 0) 225 dup2(infd, 0); 226 if (outfd >= 0) 227 dup2(outfd, 1); 228 for (i = getdtablesize(); --i > 2;) 229 close(i); 230 for (i = 1; i <= NSIG; i++) 231 if (mask & sigmask(i)) 232 (void) signal(i, SIG_IGN); 233 if ((mask & sigmask(SIGINT)) == 0) 234 (void) signal(SIGINT, SIG_DFL); 235 (void) sigsetmask(0); 236 } 237 238 wait_command(pid) 239 int pid; 240 { 241 242 if (wait_child(pid) < 0) { 243 printf("Fatal error in process.\n"); 244 return -1; 245 } 246 return 0; 247 } 248 249 struct child { 250 int pid; 251 char done; 252 char free; 253 union wait status; 254 struct child *link; 255 }; 256 static struct child *child; 257 258 struct child * 259 findchild(pid) 260 int pid; 261 { 262 register struct child **cpp; 263 264 for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid; 265 cpp = &(*cpp)->link) 266 ; 267 if (*cpp == NULL) { 268 *cpp = (struct child *) malloc(sizeof (struct child)); 269 (*cpp)->pid = pid; 270 (*cpp)->done = (*cpp)->free = 0; 271 (*cpp)->link = NULL; 272 } 273 return *cpp; 274 } 275 276 delchild(cp) 277 register struct child *cp; 278 { 279 register struct child **cpp; 280 281 for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link) 282 ; 283 *cpp = cp->link; 284 free((char *) cp); 285 } 286 287 void 288 sigchild() 289 { 290 int pid; 291 union wait status; 292 register struct child *cp; 293 294 while ((pid = 295 wait3((int *)&status, WNOHANG, (struct rusage *)0)) > 0) { 296 cp = findchild(pid); 297 if (cp->free) 298 delchild(cp); 299 else { 300 cp->done = 1; 301 cp->status = status; 302 } 303 } 304 } 305 306 union wait wait_status; 307 308 /* 309 * Wait for a specific child to die. 310 */ 311 wait_child(pid) 312 int pid; 313 { 314 int mask = sigblock(sigmask(SIGCHLD)); 315 register struct child *cp = findchild(pid); 316 317 while (!cp->done) 318 sigpause(mask); 319 wait_status = cp->status; 320 delchild(cp); 321 sigsetmask(mask); 322 return wait_status.w_status ? -1 : 0; 323 } 324 325 /* 326 * Mark a child as don't care. 327 */ 328 free_child(pid) 329 int pid; 330 { 331 int mask = sigblock(sigmask(SIGCHLD)); 332 register struct child *cp = findchild(pid); 333 334 if (cp->done) 335 delchild(cp); 336 else 337 cp->free = 1; 338 sigsetmask(mask); 339 } 340