1 /* $NetBSD: popen.c,v 1.7 1997/10/19 05:03:45 lukem 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 #include <sys/cdefs.h> 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 6/6/93"; 40 #else 41 __RCSID("$NetBSD: popen.c,v 1.7 1997/10/19 05:03:45 lukem Exp $"); 42 #endif 43 #endif /* not lint */ 44 45 #include "rcv.h" 46 #include "extern.h" 47 48 #define READ 0 49 #define WRITE 1 50 51 struct fp { 52 FILE *fp; 53 int pipe; 54 int pid; 55 struct fp *link; 56 }; 57 static struct fp *fp_head; 58 59 struct child { 60 int pid; 61 char done; 62 char free; 63 union wait status; 64 struct child *link; 65 }; 66 static struct child *child; 67 static struct child *findchild __P((int)); 68 static void delchild __P((struct child *)); 69 static int file_pid __P((FILE *)); 70 71 FILE * 72 Fopen(file, mode) 73 char *file, *mode; 74 { 75 FILE *fp; 76 77 if ((fp = fopen(file, mode)) != NULL) { 78 register_file(fp, 0, 0); 79 (void) fcntl(fileno(fp), F_SETFD, 1); 80 } 81 return fp; 82 } 83 84 FILE * 85 Fdopen(fd, mode) 86 int fd; 87 char *mode; 88 { 89 FILE *fp; 90 91 if ((fp = fdopen(fd, mode)) != NULL) { 92 register_file(fp, 0, 0); 93 (void) fcntl(fileno(fp), F_SETFD, 1); 94 } 95 return fp; 96 } 97 98 int 99 Fclose(fp) 100 FILE *fp; 101 { 102 unregister_file(fp); 103 return fclose(fp); 104 } 105 106 FILE * 107 Popen(cmd, mode) 108 char *cmd; 109 char *mode; 110 { 111 int p[2]; 112 int myside, hisside, fd0, fd1; 113 int pid; 114 sigset_t nset; 115 FILE *fp; 116 117 if (pipe(p) < 0) 118 return NULL; 119 (void) fcntl(p[READ], F_SETFD, 1); 120 (void) fcntl(p[WRITE], F_SETFD, 1); 121 if (*mode == 'r') { 122 myside = p[READ]; 123 fd0 = -1; 124 hisside = fd1 = p[WRITE]; 125 } else { 126 myside = p[WRITE]; 127 hisside = fd0 = p[READ]; 128 fd1 = -1; 129 } 130 sigemptyset(&nset); 131 if ((pid = start_command(cmd, &nset, fd0, fd1, NOSTR, NOSTR, NOSTR)) < 0) { 132 close(p[READ]); 133 close(p[WRITE]); 134 return NULL; 135 } 136 (void) close(hisside); 137 if ((fp = fdopen(myside, mode)) != NULL) 138 register_file(fp, 1, pid); 139 return fp; 140 } 141 142 int 143 Pclose(ptr) 144 FILE *ptr; 145 { 146 int i; 147 sigset_t nset, oset; 148 149 i = file_pid(ptr); 150 unregister_file(ptr); 151 (void) fclose(ptr); 152 sigemptyset(&nset); 153 sigaddset(&nset, SIGINT); 154 sigaddset(&nset, SIGHUP); 155 sigprocmask(SIG_BLOCK, &nset, &oset); 156 i = wait_child(i); 157 sigprocmask(SIG_SETMASK, &oset, NULL); 158 return i; 159 } 160 161 void 162 close_all_files() 163 { 164 165 while (fp_head) 166 if (fp_head->pipe) 167 (void) Pclose(fp_head->fp); 168 else 169 (void) Fclose(fp_head->fp); 170 } 171 172 void 173 register_file(fp, pipe, pid) 174 FILE *fp; 175 int pipe, pid; 176 { 177 struct fp *fpp; 178 179 if ((fpp = (struct fp *) malloc(sizeof *fpp)) == NULL) 180 errx(1, "Out of memory"); 181 fpp->fp = fp; 182 fpp->pipe = pipe; 183 fpp->pid = pid; 184 fpp->link = fp_head; 185 fp_head = fpp; 186 } 187 188 void 189 unregister_file(fp) 190 FILE *fp; 191 { 192 struct fp **pp, *p; 193 194 for (pp = &fp_head; (p = *pp) != NULL; pp = &p->link) 195 if (p->fp == fp) { 196 *pp = p->link; 197 free((char *) p); 198 return; 199 } 200 errx(1, "Invalid file pointer"); 201 } 202 203 static int 204 file_pid(fp) 205 FILE *fp; 206 { 207 struct fp *p; 208 209 for (p = fp_head; p; p = p->link) 210 if (p->fp == fp) 211 return (p->pid); 212 errx(1, "Invalid file pointer"); 213 /*NOTREACHED*/ 214 } 215 216 /* 217 * Run a command without a shell, with optional arguments and splicing 218 * of stdin and stdout. The command name can be a sequence of words. 219 * Signals must be handled by the caller. 220 * "Mask" contains the signals to ignore in the new process. 221 * SIGINT is enabled unless it's in the mask. 222 */ 223 /*VARARGS4*/ 224 int 225 run_command(cmd, mask, infd, outfd, a0, a1, a2) 226 char *cmd; 227 sigset_t *mask; 228 int infd, outfd; 229 char *a0, *a1, *a2; 230 { 231 int pid; 232 233 if ((pid = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0) 234 return -1; 235 return wait_command(pid); 236 } 237 238 /*VARARGS4*/ 239 int 240 start_command(cmd, mask, infd, outfd, a0, a1, a2) 241 char *cmd; 242 sigset_t *mask; 243 int infd, outfd; 244 char *a0, *a1, *a2; 245 { 246 int pid; 247 248 if ((pid = vfork()) < 0) { 249 perror("fork"); 250 return -1; 251 } 252 if (pid == 0) { 253 char *argv[100]; 254 int i = getrawlist(cmd, argv, sizeof argv / sizeof *argv); 255 256 if ((argv[i++] = a0) != NOSTR && 257 (argv[i++] = a1) != NOSTR && 258 (argv[i++] = a2) != NOSTR) 259 argv[i] = NOSTR; 260 prepare_child(mask, infd, outfd); 261 execvp(argv[0], argv); 262 perror(argv[0]); 263 _exit(1); 264 } 265 return pid; 266 } 267 268 void 269 prepare_child(nset, infd, outfd) 270 sigset_t *nset; 271 int infd, outfd; 272 { 273 int i; 274 sigset_t fset; 275 276 /* 277 * All file descriptors other than 0, 1, and 2 are supposed to be 278 * close-on-exec. 279 */ 280 if (infd >= 0) 281 dup2(infd, 0); 282 if (outfd >= 0) 283 dup2(outfd, 1); 284 if (nset == NULL) 285 return; 286 if (nset != NULL) { 287 for (i = 1; i < NSIG; i++) 288 if (sigismember(nset, i)) 289 (void) signal(i, SIG_IGN); 290 } 291 if (nset == NULL || !sigismember(nset, SIGINT)) 292 (void) signal(SIGINT, SIG_DFL); 293 sigfillset(&fset); 294 (void) sigprocmask(SIG_UNBLOCK, &fset, NULL); 295 } 296 297 int 298 wait_command(pid) 299 int pid; 300 { 301 302 if (wait_child(pid) < 0) { 303 printf("Fatal error in process.\n"); 304 return -1; 305 } 306 return 0; 307 } 308 309 static struct child * 310 findchild(pid) 311 int pid; 312 { 313 struct child **cpp; 314 315 for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid; 316 cpp = &(*cpp)->link) 317 ; 318 if (*cpp == NULL) { 319 *cpp = (struct child *) malloc(sizeof (struct child)); 320 (*cpp)->pid = pid; 321 (*cpp)->done = (*cpp)->free = 0; 322 (*cpp)->link = NULL; 323 } 324 return *cpp; 325 } 326 327 static void 328 delchild(cp) 329 struct child *cp; 330 { 331 struct child **cpp; 332 333 for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link) 334 ; 335 *cpp = cp->link; 336 free((char *) cp); 337 } 338 339 void 340 sigchild(signo) 341 int signo; 342 { 343 int pid; 344 union wait status; 345 struct child *cp; 346 347 while ((pid = 348 wait3((int *)&status, WNOHANG, (struct rusage *)0)) > 0) { 349 cp = findchild(pid); 350 if (cp->free) 351 delchild(cp); 352 else { 353 cp->done = 1; 354 cp->status = status; 355 } 356 } 357 } 358 359 union wait wait_status; 360 361 /* 362 * Wait for a specific child to die. 363 */ 364 int 365 wait_child(pid) 366 int pid; 367 { 368 sigset_t nset, oset; 369 struct child *cp = findchild(pid); 370 sigemptyset(&nset); 371 sigaddset(&nset, SIGCHLD); 372 sigprocmask(SIG_BLOCK, &nset, &oset); 373 374 while (!cp->done) 375 sigsuspend(&oset); 376 wait_status = cp->status; 377 delchild(cp); 378 sigprocmask(SIG_SETMASK, &oset, NULL); 379 return wait_status.w_status ? -1 : 0; 380 } 381 382 /* 383 * Mark a child as don't care. 384 */ 385 void 386 free_child(pid) 387 int pid; 388 { 389 sigset_t nset, oset; 390 struct child *cp = findchild(pid); 391 sigemptyset(&nset); 392 sigaddset(&nset, SIGCHLD); 393 sigprocmask(SIG_BLOCK, &nset, &oset); 394 395 if (cp->done) 396 delchild(cp); 397 else 398 cp->free = 1; 399 sigprocmask(SIG_SETMASK, &oset, NULL); 400 } 401