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