popen.c revision 88150
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1980, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 341590Srgrimes#ifndef lint 3574769Smikeh#if 0 361590Srgrimesstatic char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 6/6/93"; 3774769Smikeh#endif 3874769Smikehstatic const char rcsid[] = 3974769Smikeh "$FreeBSD: head/usr.bin/mail/popen.c 88150 2001-12-18 20:52:09Z mikeh $"; 401590Srgrimes#endif /* not lint */ 411590Srgrimes 421590Srgrimes#include "rcv.h" 431590Srgrimes#include <sys/wait.h> 441590Srgrimes#include <fcntl.h> 451590Srgrimes#include "extern.h" 461590Srgrimes 471590Srgrimes#define READ 0 481590Srgrimes#define WRITE 1 491590Srgrimes 501590Srgrimesstruct fp { 5177274Smikeh FILE *fp; 5277274Smikeh int pipe; 5377274Smikeh int pid; 5477274Smikeh struct fp *link; 551590Srgrimes}; 561590Srgrimesstatic struct fp *fp_head; 571590Srgrimes 581590Srgrimesstruct child { 5977274Smikeh int pid; 6077274Smikeh char done; 6177274Smikeh char free; 6277274Smikeh int status; 6377274Smikeh struct child *link; 641590Srgrimes}; 651590Srgrimesstatic struct child *child; 661590Srgrimesstatic struct child *findchild __P((int)); 671590Srgrimesstatic void delchild __P((struct child *)); 6874769Smikehstatic int file_pid __P((FILE *)); 691590Srgrimes 701590SrgrimesFILE * 7177274SmikehFopen(path, mode) 7277274Smikeh const char *path, *mode; 731590Srgrimes{ 741590Srgrimes FILE *fp; 751590Srgrimes 7677274Smikeh if ((fp = fopen(path, mode)) != NULL) { 771590Srgrimes register_file(fp, 0, 0); 7877274Smikeh (void)fcntl(fileno(fp), F_SETFD, 1); 791590Srgrimes } 8077274Smikeh return (fp); 811590Srgrimes} 821590Srgrimes 831590SrgrimesFILE * 841590SrgrimesFdopen(fd, mode) 851590Srgrimes int fd; 8677274Smikeh const char *mode; 871590Srgrimes{ 881590Srgrimes FILE *fp; 891590Srgrimes 901590Srgrimes if ((fp = fdopen(fd, mode)) != NULL) { 911590Srgrimes register_file(fp, 0, 0); 9277274Smikeh (void)fcntl(fileno(fp), F_SETFD, 1); 931590Srgrimes } 9477274Smikeh return (fp); 951590Srgrimes} 961590Srgrimes 971590Srgrimesint 981590SrgrimesFclose(fp) 991590Srgrimes FILE *fp; 1001590Srgrimes{ 1011590Srgrimes unregister_file(fp); 10277274Smikeh return (fclose(fp)); 1031590Srgrimes} 1041590Srgrimes 1051590SrgrimesFILE * 1061590SrgrimesPopen(cmd, mode) 1071590Srgrimes char *cmd; 10877274Smikeh const char *mode; 1091590Srgrimes{ 1101590Srgrimes int p[2]; 1111590Srgrimes int myside, hisside, fd0, fd1; 1121590Srgrimes int pid; 11388150Smikeh sigset_t nset; 1141590Srgrimes FILE *fp; 1151590Srgrimes 1161590Srgrimes if (pipe(p) < 0) 11777274Smikeh return (NULL); 11877274Smikeh (void)fcntl(p[READ], F_SETFD, 1); 11977274Smikeh (void)fcntl(p[WRITE], F_SETFD, 1); 1201590Srgrimes if (*mode == 'r') { 1211590Srgrimes myside = p[READ]; 1221590Srgrimes fd0 = -1; 1231590Srgrimes hisside = fd1 = p[WRITE]; 1241590Srgrimes } else { 1251590Srgrimes myside = p[WRITE]; 1261590Srgrimes hisside = fd0 = p[READ]; 1271590Srgrimes fd1 = -1; 1281590Srgrimes } 12988150Smikeh (void)sigemptyset(&nset); 13088150Smikeh if ((pid = start_command(cmd, &nset, fd0, fd1, NULL, NULL, NULL)) < 0) { 13177274Smikeh (void)close(p[READ]); 13277274Smikeh (void)close(p[WRITE]); 13377274Smikeh return (NULL); 1341590Srgrimes } 13577274Smikeh (void)close(hisside); 1361590Srgrimes if ((fp = fdopen(myside, mode)) != NULL) 1371590Srgrimes register_file(fp, 1, pid); 13877274Smikeh return (fp); 1391590Srgrimes} 1401590Srgrimes 1411590Srgrimesint 1421590SrgrimesPclose(ptr) 1431590Srgrimes FILE *ptr; 1441590Srgrimes{ 1451590Srgrimes int i; 14688150Smikeh sigset_t nset, oset; 1471590Srgrimes 1481590Srgrimes i = file_pid(ptr); 1491590Srgrimes unregister_file(ptr); 15077274Smikeh (void)fclose(ptr); 15188150Smikeh (void)sigemptyset(&nset); 15288150Smikeh (void)sigaddset(&nset, SIGINT); 15388150Smikeh (void)sigaddset(&nset, SIGHUP); 15488150Smikeh (void)sigprocmask(SIG_BLOCK, &nset, &oset); 1551590Srgrimes i = wait_child(i); 15688150Smikeh (void)sigprocmask(SIG_SETMASK, &oset, NULL); 15777274Smikeh return (i); 1581590Srgrimes} 1591590Srgrimes 1601590Srgrimesvoid 1611590Srgrimesclose_all_files() 1621590Srgrimes{ 1631590Srgrimes 16477274Smikeh while (fp_head != NULL) 1651590Srgrimes if (fp_head->pipe) 16677274Smikeh (void)Pclose(fp_head->fp); 1671590Srgrimes else 16877274Smikeh (void)Fclose(fp_head->fp); 1691590Srgrimes} 1701590Srgrimes 1711590Srgrimesvoid 1721590Srgrimesregister_file(fp, pipe, pid) 1731590Srgrimes FILE *fp; 1741590Srgrimes int pipe, pid; 1751590Srgrimes{ 1761590Srgrimes struct fp *fpp; 1771590Srgrimes 17877274Smikeh if ((fpp = malloc(sizeof(*fpp))) == NULL) 17974769Smikeh err(1, "Out of memory"); 1801590Srgrimes fpp->fp = fp; 1811590Srgrimes fpp->pipe = pipe; 1821590Srgrimes fpp->pid = pid; 1831590Srgrimes fpp->link = fp_head; 1841590Srgrimes fp_head = fpp; 1851590Srgrimes} 1861590Srgrimes 1871590Srgrimesvoid 1881590Srgrimesunregister_file(fp) 1891590Srgrimes FILE *fp; 1901590Srgrimes{ 1911590Srgrimes struct fp **pp, *p; 1921590Srgrimes 19377274Smikeh for (pp = &fp_head; (p = *pp) != NULL; pp = &p->link) 1941590Srgrimes if (p->fp == fp) { 1951590Srgrimes *pp = p->link; 19677274Smikeh (void)free(p); 1971590Srgrimes return; 1981590Srgrimes } 19974769Smikeh errx(1, "Invalid file pointer"); 20074769Smikeh /*NOTREACHED*/ 2011590Srgrimes} 2021590Srgrimes 20374769Smikehint 2041590Srgrimesfile_pid(fp) 2051590Srgrimes FILE *fp; 2061590Srgrimes{ 2071590Srgrimes struct fp *p; 2081590Srgrimes 20977274Smikeh for (p = fp_head; p != NULL; p = p->link) 2101590Srgrimes if (p->fp == fp) 2111590Srgrimes return (p->pid); 21274769Smikeh errx(1, "Invalid file pointer"); 2131590Srgrimes /*NOTREACHED*/ 2141590Srgrimes} 2151590Srgrimes 2161590Srgrimes/* 2171590Srgrimes * Run a command without a shell, with optional arguments and splicing 2181590Srgrimes * of stdin and stdout. The command name can be a sequence of words. 2191590Srgrimes * Signals must be handled by the caller. 2201590Srgrimes * "Mask" contains the signals to ignore in the new process. 2211590Srgrimes * SIGINT is enabled unless it's in the mask. 2221590Srgrimes */ 2231590Srgrimes/*VARARGS4*/ 2241590Srgrimesint 2251590Srgrimesrun_command(cmd, mask, infd, outfd, a0, a1, a2) 2261590Srgrimes char *cmd; 22788150Smikeh sigset_t *mask; 22888150Smikeh int infd, outfd; 2291590Srgrimes char *a0, *a1, *a2; 2301590Srgrimes{ 2311590Srgrimes int pid; 2321590Srgrimes 2331590Srgrimes if ((pid = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0) 23477274Smikeh return (-1); 23577274Smikeh return (wait_command(pid)); 2361590Srgrimes} 2371590Srgrimes 2381590Srgrimes/*VARARGS4*/ 2391590Srgrimesint 2401590Srgrimesstart_command(cmd, mask, infd, outfd, a0, a1, a2) 2411590Srgrimes char *cmd; 24288150Smikeh sigset_t *mask; 24388150Smikeh int infd, outfd; 2441590Srgrimes char *a0, *a1, *a2; 2451590Srgrimes{ 2461590Srgrimes int pid; 2471590Srgrimes 24840188Sbde if ((pid = fork()) < 0) { 24974769Smikeh warn("fork"); 25077274Smikeh return (-1); 2511590Srgrimes } 2521590Srgrimes if (pid == 0) { 2531590Srgrimes char *argv[100]; 25477274Smikeh int i = getrawlist(cmd, argv, sizeof(argv) / sizeof(*argv)); 2551590Srgrimes 25677274Smikeh if ((argv[i++] = a0) != NULL && 25777274Smikeh (argv[i++] = a1) != NULL && 25877274Smikeh (argv[i++] = a2) != NULL) 25977274Smikeh argv[i] = NULL; 2601590Srgrimes prepare_child(mask, infd, outfd); 2611590Srgrimes execvp(argv[0], argv); 26274769Smikeh warn("%s", argv[0]); 2631590Srgrimes _exit(1); 2641590Srgrimes } 26577274Smikeh return (pid); 2661590Srgrimes} 2671590Srgrimes 2681590Srgrimesvoid 26988150Smikehprepare_child(nset, infd, outfd) 27088150Smikeh sigset_t *nset; 27188150Smikeh int infd, outfd; 2721590Srgrimes{ 2731590Srgrimes int i; 27488150Smikeh sigset_t eset; 2751590Srgrimes 2761590Srgrimes /* 2771590Srgrimes * All file descriptors other than 0, 1, and 2 are supposed to be 2781590Srgrimes * close-on-exec. 2791590Srgrimes */ 2801590Srgrimes if (infd >= 0) 2811590Srgrimes dup2(infd, 0); 2821590Srgrimes if (outfd >= 0) 2831590Srgrimes dup2(outfd, 1); 28488150Smikeh for (i = 1; i < NSIG; i++) 28588150Smikeh if (nset != NULL && sigismember(nset, i)) 28677274Smikeh (void)signal(i, SIG_IGN); 28788150Smikeh if (nset == NULL || !sigismember(nset, SIGINT)) 28877274Smikeh (void)signal(SIGINT, SIG_DFL); 28988150Smikeh (void)sigemptyset(&eset); 29088150Smikeh (void)sigprocmask(SIG_SETMASK, &eset, NULL); 2911590Srgrimes} 2921590Srgrimes 2931590Srgrimesint 2941590Srgrimeswait_command(pid) 2951590Srgrimes int pid; 2961590Srgrimes{ 2971590Srgrimes 2981590Srgrimes if (wait_child(pid) < 0) { 2991590Srgrimes printf("Fatal error in process.\n"); 30077274Smikeh return (-1); 3011590Srgrimes } 30277274Smikeh return (0); 3031590Srgrimes} 3041590Srgrimes 3051590Srgrimesstatic struct child * 3061590Srgrimesfindchild(pid) 3071590Srgrimes int pid; 3081590Srgrimes{ 30977274Smikeh struct child **cpp; 3101590Srgrimes 3111590Srgrimes for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid; 31277274Smikeh cpp = &(*cpp)->link) 3131590Srgrimes ; 3141590Srgrimes if (*cpp == NULL) { 31577274Smikeh *cpp = malloc(sizeof(struct child)); 31674769Smikeh if (*cpp == NULL) 31774769Smikeh err(1, "Out of memory"); 3181590Srgrimes (*cpp)->pid = pid; 3191590Srgrimes (*cpp)->done = (*cpp)->free = 0; 3201590Srgrimes (*cpp)->link = NULL; 3211590Srgrimes } 32277274Smikeh return (*cpp); 3231590Srgrimes} 3241590Srgrimes 3251590Srgrimesstatic void 3261590Srgrimesdelchild(cp) 32777274Smikeh struct child *cp; 3281590Srgrimes{ 32977274Smikeh struct child **cpp; 3301590Srgrimes 3311590Srgrimes for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link) 3321590Srgrimes ; 3331590Srgrimes *cpp = cp->link; 33477274Smikeh (void)free(cp); 3351590Srgrimes} 3361590Srgrimes 33777274Smikeh/*ARGSUSED*/ 3381590Srgrimesvoid 3391590Srgrimessigchild(signo) 3401590Srgrimes int signo; 3411590Srgrimes{ 3421590Srgrimes int pid; 34374769Smikeh int status; 34477274Smikeh struct child *cp; 3451590Srgrimes 34674769Smikeh while ((pid = waitpid((pid_t)-1, &status, WNOHANG)) > 0) { 3471590Srgrimes cp = findchild(pid); 3481590Srgrimes if (cp->free) 3491590Srgrimes delchild(cp); 3501590Srgrimes else { 3511590Srgrimes cp->done = 1; 3521590Srgrimes cp->status = status; 3531590Srgrimes } 3541590Srgrimes } 3551590Srgrimes} 3561590Srgrimes 35774769Smikehint wait_status; 3581590Srgrimes 3591590Srgrimes/* 3601590Srgrimes * Wait for a specific child to die. 3611590Srgrimes */ 3621590Srgrimesint 3631590Srgrimeswait_child(pid) 3641590Srgrimes int pid; 3651590Srgrimes{ 36688150Smikeh sigset_t nset, oset; 36777274Smikeh struct child *cp = findchild(pid); 3681590Srgrimes 36988150Smikeh (void)sigemptyset(&nset); 37088150Smikeh (void)sigaddset(&nset, SIGCHLD); 37188150Smikeh (void)sigprocmask(SIG_BLOCK, &nset, &oset); 37288150Smikeh 3731590Srgrimes while (!cp->done) 37488150Smikeh (void)sigsuspend(&oset); 3751590Srgrimes wait_status = cp->status; 3761590Srgrimes delchild(cp); 37788150Smikeh (void)sigprocmask(SIG_SETMASK, &oset, NULL); 37877274Smikeh return ((WIFEXITED(wait_status) && WEXITSTATUS(wait_status)) ? -1 : 0); 3791590Srgrimes} 3801590Srgrimes 3811590Srgrimes/* 3821590Srgrimes * Mark a child as don't care. 3831590Srgrimes */ 3841590Srgrimesvoid 3851590Srgrimesfree_child(pid) 3861590Srgrimes int pid; 3871590Srgrimes{ 38888150Smikeh sigset_t nset, oset; 38977274Smikeh struct child *cp = findchild(pid); 3901590Srgrimes 39188150Smikeh (void)sigemptyset(&nset); 39288150Smikeh (void)sigaddset(&nset, SIGCHLD); 39388150Smikeh (void)sigprocmask(SIG_BLOCK, &nset, &oset); 39488150Smikeh 3951590Srgrimes if (cp->done) 3961590Srgrimes delchild(cp); 3971590Srgrimes else 3981590Srgrimes cp->free = 1; 39988150Smikeh (void)sigprocmask(SIG_SETMASK, &oset, NULL); 4001590Srgrimes} 401