1 /* 2 * Copyright (c) 1980, 1993 3 * The Regents of the University of California. 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 #if 0 36 static char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 6/6/93"; 37 #endif 38 #endif /* not lint */ 39 #include <sys/cdefs.h> 40 __FBSDID("$FreeBSD$"); 41 42 #include "rcv.h" 43 #include <sys/wait.h> 44 #include <fcntl.h> 45 #include "extern.h" 46 47 #define READ 0 48 #define WRITE 1 49 50 struct fp { 51 FILE *fp; 52 int pipe; 53 int pid; 54 struct fp *link; 55 }; 56 static struct fp *fp_head; 57 58 struct child { 59 int pid; 60 char done; 61 char free; 62 int status; 63 struct child *link; 64 }; 65 static struct child *child; 66 static struct child *findchild(int); 67 static void delchild(struct child *); 68 static int file_pid(FILE *); 69 70 FILE * 71 Fopen(path, mode) 72 const char *path, *mode; 73 { 74 FILE *fp; 75 76 if ((fp = fopen(path, mode)) != NULL) { 77 register_file(fp, 0, 0); 78 (void)fcntl(fileno(fp), F_SETFD, 1); 79 } 80 return (fp); 81 } 82 83 FILE * 84 Fdopen(fd, mode) 85 int fd; 86 const char *mode; 87 { 88 FILE *fp; 89 90 if ((fp = fdopen(fd, mode)) != NULL) { 91 register_file(fp, 0, 0); 92 (void)fcntl(fileno(fp), F_SETFD, 1); 93 } 94 return (fp); 95 } 96 97 int 98 Fclose(fp) 99 FILE *fp; 100 { 101 unregister_file(fp); 102 return (fclose(fp)); 103 } 104 105 FILE * 106 Popen(cmd, mode) 107 char *cmd; 108 const char *mode; 109 { 110 int p[2]; 111 int myside, hisside, fd0, fd1; 112 int pid; 113 sigset_t nset; 114 FILE *fp; 115 116 if (pipe(p) < 0) 117 return (NULL); 118 (void)fcntl(p[READ], F_SETFD, 1); 119 (void)fcntl(p[WRITE], F_SETFD, 1); 120 if (*mode == 'r') { 121 myside = p[READ]; 122 fd0 = -1; 123 hisside = fd1 = p[WRITE]; 124 } else { 125 myside = p[WRITE]; 126 hisside = fd0 = p[READ]; 127 fd1 = -1; 128 } 129 (void)sigemptyset(&nset); 130 if ((pid = start_command(cmd, &nset, fd0, fd1, NULL, NULL, NULL)) < 0) { 131 (void)close(p[READ]); 132 (void)close(p[WRITE]); 133 return (NULL); 134 } 135 (void)close(hisside); 136 if ((fp = fdopen(myside, mode)) != NULL) 137 register_file(fp, 1, pid); 138 return (fp); 139 } 140 141 int 142 Pclose(ptr) 143 FILE *ptr; 144 { 145 int i; 146 sigset_t nset, oset; 147 148 i = file_pid(ptr); 149 unregister_file(ptr); 150 (void)fclose(ptr); 151 (void)sigemptyset(&nset); 152 (void)sigaddset(&nset, SIGINT); 153 (void)sigaddset(&nset, SIGHUP); 154 (void)sigprocmask(SIG_BLOCK, &nset, &oset); 155 i = wait_child(i); 156 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 157 return (i); 158 } 159 160 void 161 close_all_files() 162 { 163 164 while (fp_head != NULL) 165 if (fp_head->pipe) 166 (void)Pclose(fp_head->fp); 167 else 168 (void)Fclose(fp_head->fp); 169 } 170 171 void 172 register_file(fp, pipe, pid) 173 FILE *fp; 174 int pipe, pid; 175 { 176 struct fp *fpp; 177 178 if ((fpp = malloc(sizeof(*fpp))) == NULL) 179 err(1, "Out of memory"); 180 fpp->fp = fp; 181 fpp->pipe = pipe; 182 fpp->pid = pid; 183 fpp->link = fp_head; 184 fp_head = fpp; 185 } 186 187 void 188 unregister_file(fp) 189 FILE *fp; 190 { 191 struct fp **pp, *p; 192 193 for (pp = &fp_head; (p = *pp) != NULL; pp = &p->link) 194 if (p->fp == fp) { 195 *pp = p->link; 196 (void)free(p); 197 return; 198 } 199 errx(1, "Invalid file pointer"); 200 /*NOTREACHED*/ 201 } 202 203 int 204 file_pid(fp) 205 FILE *fp; 206 { 207 struct fp *p; 208 209 for (p = fp_head; p != NULL; 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 = fork()) < 0) { 249 warn("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) != NULL && 257 (argv[i++] = a1) != NULL && 258 (argv[i++] = a2) != NULL) 259 argv[i] = NULL; 260 prepare_child(mask, infd, outfd); 261 execvp(argv[0], argv); 262 warn("%s", 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 eset; 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 for (i = 1; i < NSIG; i++) 285 if (nset != NULL && sigismember(nset, i)) 286 (void)signal(i, SIG_IGN); 287 if (nset == NULL || !sigismember(nset, SIGINT)) 288 (void)signal(SIGINT, SIG_DFL); 289 (void)sigemptyset(&eset); 290 (void)sigprocmask(SIG_SETMASK, &eset, NULL); 291 } 292 293 int 294 wait_command(pid) 295 int pid; 296 { 297 298 if (wait_child(pid) < 0) { 299 printf("Fatal error in process.\n"); 300 return (-1); 301 } 302 return (0); 303 } 304 305 static struct child * 306 findchild(pid) 307 int pid; 308 { 309 struct child **cpp; 310 311 for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid; 312 cpp = &(*cpp)->link) 313 ; 314 if (*cpp == NULL) { 315 *cpp = malloc(sizeof(struct child)); 316 if (*cpp == NULL) 317 err(1, "Out of memory"); 318 (*cpp)->pid = pid; 319 (*cpp)->done = (*cpp)->free = 0; 320 (*cpp)->link = NULL; 321 } 322 return (*cpp); 323 } 324 325 static void 326 delchild(cp) 327 struct child *cp; 328 { 329 struct child **cpp; 330 331 for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link) 332 ; 333 *cpp = cp->link; 334 (void)free(cp); 335 } 336 337 /*ARGSUSED*/ 338 void 339 sigchild(signo) 340 int signo; 341 { 342 int pid; 343 int status; 344 struct child *cp; 345 346 while ((pid = waitpid((pid_t)-1, &status, WNOHANG)) > 0) { 347 cp = findchild(pid); 348 if (cp->free) 349 delchild(cp); 350 else { 351 cp->done = 1; 352 cp->status = status; 353 } 354 } 355 } 356 357 int wait_status; 358 359 /* 360 * Wait for a specific child to die. 361 */ 362 int 363 wait_child(pid) 364 int pid; 365 { 366 sigset_t nset, oset; 367 struct child *cp = findchild(pid); 368 369 (void)sigemptyset(&nset); 370 (void)sigaddset(&nset, SIGCHLD); 371 (void)sigprocmask(SIG_BLOCK, &nset, &oset); 372 373 while (!cp->done) 374 (void)sigsuspend(&oset); 375 wait_status = cp->status; 376 delchild(cp); 377 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 378 return ((WIFEXITED(wait_status) && WEXITSTATUS(wait_status)) ? -1 : 0); 379 } 380 381 /* 382 * Mark a child as don't care. 383 */ 384 void 385 free_child(pid) 386 int pid; 387 { 388 sigset_t nset, oset; 389 struct child *cp = findchild(pid); 390 391 (void)sigemptyset(&nset); 392 (void)sigaddset(&nset, SIGCHLD); 393 (void)sigprocmask(SIG_BLOCK, &nset, &oset); 394 395 if (cp->done) 396 delchild(cp); 397 else 398 cp->free = 1; 399 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 400 } 401