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