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[] = "from: @(#)popen.c 5.16 (Berkeley) 4/1/91";*/ 36 static char rcsid[] = "$Id: popen.c,v 1.2 1993/08/01 18:12:59 mycroft Exp $"; 37 #endif /* not lint */ 38 39 #include "rcv.h" 40 #include <sys/signal.h> 41 #include <sys/wait.h> 42 43 #define READ 0 44 #define WRITE 1 45 static int *pid; 46 47 struct fp { 48 FILE *fp; 49 int pipe; 50 struct fp *link; 51 }; 52 static struct fp *fp_head; 53 54 FILE * 55 Fopen(file, mode) 56 char *file, *mode; 57 { 58 FILE *fp; 59 60 if ((fp = fopen(file, mode)) != NULL) 61 register_file(fp, 0); 62 return fp; 63 } 64 65 FILE * 66 Fdopen(fd, mode) 67 char *mode; 68 { 69 FILE *fp; 70 71 if ((fp = fdopen(fd, mode)) != NULL) 72 register_file(fp, 0); 73 return fp; 74 } 75 76 Fclose(fp) 77 FILE *fp; 78 { 79 unregister_file(fp); 80 return fclose(fp); 81 } 82 83 FILE * 84 Popen(cmd, mode) 85 char *cmd; 86 char *mode; 87 { 88 int p[2]; 89 int myside, hisside, fd0, fd1; 90 FILE *fp; 91 92 if (pid == 0) 93 pid = (int *) malloc((unsigned) sizeof (int) * getdtablesize()); 94 if (pipe(p) < 0) 95 return NULL; 96 if (*mode == 'r') { 97 myside = p[READ]; 98 fd0 = -1; 99 hisside = fd1 = p[WRITE]; 100 } else { 101 myside = p[WRITE]; 102 hisside = fd0 = p[READ]; 103 fd1 = -1; 104 } 105 if ((pid[myside] = start_command(cmd, 0, fd0, fd1, NOSTR)) < 0) { 106 close(p[READ]); 107 close(p[WRITE]); 108 return NULL; 109 } 110 (void) close(hisside); 111 if ((fp = fdopen(myside, mode)) != NULL) 112 register_file(fp, 1); 113 return fp; 114 } 115 116 Pclose(ptr) 117 FILE *ptr; 118 { 119 int i; 120 int omask; 121 122 i = fileno(ptr); 123 unregister_file(ptr); 124 (void) fclose(ptr); 125 omask = sigblock(sigmask(SIGINT)|sigmask(SIGHUP)); 126 i = wait_child(pid[i]); 127 sigsetmask(omask); 128 return i; 129 } 130 131 close_all_files() 132 { 133 134 while (fp_head) 135 if (fp_head->pipe) 136 (void) Pclose(fp_head->fp); 137 else 138 (void) Fclose(fp_head->fp); 139 } 140 141 register_file(fp, pipe) 142 FILE *fp; 143 { 144 struct fp *fpp; 145 146 if ((fpp = (struct fp *) malloc(sizeof *fpp)) == NULL) 147 panic("Out of memory"); 148 fpp->fp = fp; 149 fpp->pipe = pipe; 150 fpp->link = fp_head; 151 fp_head = fpp; 152 } 153 154 unregister_file(fp) 155 FILE *fp; 156 { 157 struct fp **pp, *p; 158 159 for (pp = &fp_head; p = *pp; pp = &p->link) 160 if (p->fp == fp) { 161 *pp = p->link; 162 free((char *) p); 163 return; 164 } 165 /* XXX 166 * Ignore this for now; there may still be uncaught 167 * duplicate closes. 168 panic("Invalid file pointer"); 169 */ 170 } 171 172 /* 173 * Run a command without a shell, with optional arguments and splicing 174 * of stdin and stdout. The command name can be a sequence of words. 175 * Signals must be handled by the caller. 176 * "Mask" contains the signals to ignore in the new process. 177 * SIGINT is enabled unless it's in the mask. 178 */ 179 /*VARARGS4*/ 180 run_command(cmd, mask, infd, outfd, a0, a1, a2) 181 char *cmd; 182 int mask, infd, outfd; 183 char *a0, *a1, *a2; 184 { 185 int pid; 186 187 if ((pid = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0) 188 return -1; 189 return wait_command(pid); 190 } 191 192 /*VARARGS4*/ 193 start_command(cmd, mask, infd, outfd, a0, a1, a2) 194 char *cmd; 195 int mask, infd, outfd; 196 char *a0, *a1, *a2; 197 { 198 int pid; 199 200 if ((pid = vfork()) < 0) { 201 perror("fork"); 202 return -1; 203 } 204 if (pid == 0) { 205 char *argv[100]; 206 int i = getrawlist(cmd, argv, sizeof argv / sizeof *argv); 207 208 if ((argv[i++] = a0) != NOSTR && 209 (argv[i++] = a1) != NOSTR && 210 (argv[i++] = a2) != NOSTR) 211 argv[i] = NOSTR; 212 prepare_child(mask, infd, outfd); 213 execvp(argv[0], argv); 214 perror(argv[0]); 215 _exit(1); 216 } 217 return pid; 218 } 219 220 prepare_child(mask, infd, outfd) 221 int mask, infd, outfd; 222 { 223 int i; 224 225 if (infd >= 0) 226 dup2(infd, 0); 227 if (outfd >= 0) 228 dup2(outfd, 1); 229 for (i = getdtablesize(); --i > 2;) 230 close(i); 231 for (i = 1; i <= NSIG; i++) 232 if (mask & sigmask(i)) 233 (void) signal(i, SIG_IGN); 234 if ((mask & sigmask(SIGINT)) == 0) 235 (void) signal(SIGINT, SIG_DFL); 236 (void) sigsetmask(0); 237 } 238 239 wait_command(pid) 240 int pid; 241 { 242 243 if (wait_child(pid) < 0) { 244 printf("Fatal error in process.\n"); 245 return -1; 246 } 247 return 0; 248 } 249 250 struct child { 251 int pid; 252 char done; 253 char free; 254 union wait status; 255 struct child *link; 256 }; 257 static struct child *child; 258 259 struct child * 260 findchild(pid) 261 int pid; 262 { 263 register struct child **cpp; 264 265 for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid; 266 cpp = &(*cpp)->link) 267 ; 268 if (*cpp == NULL) { 269 *cpp = (struct child *) malloc(sizeof (struct child)); 270 (*cpp)->pid = pid; 271 (*cpp)->done = (*cpp)->free = 0; 272 (*cpp)->link = NULL; 273 } 274 return *cpp; 275 } 276 277 delchild(cp) 278 register struct child *cp; 279 { 280 register struct child **cpp; 281 282 for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link) 283 ; 284 *cpp = cp->link; 285 free((char *) cp); 286 } 287 288 void 289 sigchild() 290 { 291 int pid; 292 union wait status; 293 register struct child *cp; 294 295 while ((pid = 296 wait3((int *)&status, WNOHANG, (struct rusage *)0)) > 0) { 297 cp = findchild(pid); 298 if (cp->free) 299 delchild(cp); 300 else { 301 cp->done = 1; 302 cp->status = status; 303 } 304 } 305 } 306 307 union wait wait_status; 308 309 /* 310 * Wait for a specific child to die. 311 */ 312 wait_child(pid) 313 int pid; 314 { 315 int mask = sigblock(sigmask(SIGCHLD)); 316 register struct child *cp = findchild(pid); 317 318 while (!cp->done) 319 sigpause(mask); 320 wait_status = cp->status; 321 delchild(cp); 322 sigsetmask(mask); 323 return wait_status.w_status ? -1 : 0; 324 } 325 326 /* 327 * Mark a child as don't care. 328 */ 329 free_child(pid) 330 int pid; 331 { 332 int mask = sigblock(sigmask(SIGCHLD)); 333 register struct child *cp = findchild(pid); 334 335 if (cp->done) 336 delchild(cp); 337 else 338 cp->free = 1; 339 sigsetmask(mask); 340 } 341