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