1331722Seadler/* 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 * 4. Neither the name of the University nor the names of its contributors 141590Srgrimes * may be used to endorse or promote products derived from this software 151590Srgrimes * without specific prior written permission. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 301590Srgrimes#ifndef lint 3174769Smikeh#if 0 321590Srgrimesstatic char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 6/6/93"; 3374769Smikeh#endif 341590Srgrimes#endif /* not lint */ 3599112Sobrien#include <sys/cdefs.h> 3699112Sobrien__FBSDID("$FreeBSD: stable/11/usr.bin/mail/popen.c 336953 2018-07-31 00:37:25Z markj $"); 371590Srgrimes 381590Srgrimes#include "rcv.h" 391590Srgrimes#include <sys/wait.h> 401590Srgrimes#include <fcntl.h> 411590Srgrimes#include "extern.h" 421590Srgrimes 431590Srgrimes#define READ 0 441590Srgrimes#define WRITE 1 451590Srgrimes 461590Srgrimesstruct fp { 4777274Smikeh FILE *fp; 4877274Smikeh int pipe; 49336953Smarkj int pid; 5077274Smikeh struct fp *link; 511590Srgrimes}; 521590Srgrimesstatic struct fp *fp_head; 531590Srgrimes 541590Srgrimesstruct child { 55336953Smarkj int pid; 5677274Smikeh char done; 5777274Smikeh char free; 5877274Smikeh int status; 5977274Smikeh struct child *link; 601590Srgrimes}; 61336953Smarkjstatic struct child *child; 62336953Smarkjstatic struct child *findchild(int); 6392921Simpstatic void delchild(struct child *); 64336953Smarkjstatic int file_pid(FILE *); 651590Srgrimes 661590SrgrimesFILE * 67216564ScharnierFopen(const char *path, const char *mode) 681590Srgrimes{ 691590Srgrimes FILE *fp; 701590Srgrimes 7177274Smikeh if ((fp = fopen(path, mode)) != NULL) { 721590Srgrimes register_file(fp, 0, 0); 7377274Smikeh (void)fcntl(fileno(fp), F_SETFD, 1); 741590Srgrimes } 7577274Smikeh return (fp); 761590Srgrimes} 771590Srgrimes 781590SrgrimesFILE * 79216564ScharnierFdopen(int fd, const char *mode) 801590Srgrimes{ 811590Srgrimes FILE *fp; 821590Srgrimes 831590Srgrimes if ((fp = fdopen(fd, mode)) != NULL) { 841590Srgrimes register_file(fp, 0, 0); 8577274Smikeh (void)fcntl(fileno(fp), F_SETFD, 1); 861590Srgrimes } 8777274Smikeh return (fp); 881590Srgrimes} 891590Srgrimes 901590Srgrimesint 91216564ScharnierFclose(FILE *fp) 921590Srgrimes{ 931590Srgrimes unregister_file(fp); 9477274Smikeh return (fclose(fp)); 951590Srgrimes} 961590Srgrimes 971590SrgrimesFILE * 98216564ScharnierPopen(char *cmd, const char *mode) 991590Srgrimes{ 1001590Srgrimes int p[2]; 1011590Srgrimes int myside, hisside, fd0, fd1; 102336953Smarkj int pid; 10388150Smikeh sigset_t nset; 1041590Srgrimes FILE *fp; 1051590Srgrimes 1061590Srgrimes if (pipe(p) < 0) 10777274Smikeh return (NULL); 10877274Smikeh (void)fcntl(p[READ], F_SETFD, 1); 10977274Smikeh (void)fcntl(p[WRITE], F_SETFD, 1); 1101590Srgrimes if (*mode == 'r') { 1111590Srgrimes myside = p[READ]; 112336953Smarkj fd0 = -1; 113336953Smarkj hisside = fd1 = p[WRITE]; 1141590Srgrimes } else { 1151590Srgrimes myside = p[WRITE]; 1161590Srgrimes hisside = fd0 = p[READ]; 1171590Srgrimes fd1 = -1; 1181590Srgrimes } 11988150Smikeh (void)sigemptyset(&nset); 120336953Smarkj if ((pid = start_command(cmd, &nset, fd0, fd1, NULL, NULL, NULL)) < 0) { 12177274Smikeh (void)close(p[READ]); 12277274Smikeh (void)close(p[WRITE]); 12377274Smikeh return (NULL); 1241590Srgrimes } 12577274Smikeh (void)close(hisside); 1261590Srgrimes if ((fp = fdopen(myside, mode)) != NULL) 1271590Srgrimes register_file(fp, 1, pid); 12877274Smikeh return (fp); 1291590Srgrimes} 1301590Srgrimes 1311590Srgrimesint 132216564ScharnierPclose(FILE *ptr) 1331590Srgrimes{ 1341590Srgrimes int i; 13588150Smikeh sigset_t nset, oset; 1361590Srgrimes 1371590Srgrimes i = file_pid(ptr); 1381590Srgrimes unregister_file(ptr); 13977274Smikeh (void)fclose(ptr); 14088150Smikeh (void)sigemptyset(&nset); 14188150Smikeh (void)sigaddset(&nset, SIGINT); 14288150Smikeh (void)sigaddset(&nset, SIGHUP); 14388150Smikeh (void)sigprocmask(SIG_BLOCK, &nset, &oset); 1441590Srgrimes i = wait_child(i); 14588150Smikeh (void)sigprocmask(SIG_SETMASK, &oset, NULL); 14677274Smikeh return (i); 1471590Srgrimes} 1481590Srgrimes 1491590Srgrimesvoid 150216564Scharnierclose_all_files(void) 1511590Srgrimes{ 1521590Srgrimes 15377274Smikeh while (fp_head != NULL) 1541590Srgrimes if (fp_head->pipe) 15577274Smikeh (void)Pclose(fp_head->fp); 1561590Srgrimes else 15777274Smikeh (void)Fclose(fp_head->fp); 1581590Srgrimes} 1591590Srgrimes 1601590Srgrimesvoid 161336953Smarkjregister_file(FILE *fp, int pipe, int pid) 1621590Srgrimes{ 1631590Srgrimes struct fp *fpp; 1641590Srgrimes 16577274Smikeh if ((fpp = malloc(sizeof(*fpp))) == NULL) 16674769Smikeh err(1, "Out of memory"); 1671590Srgrimes fpp->fp = fp; 1681590Srgrimes fpp->pipe = pipe; 1691590Srgrimes fpp->pid = pid; 1701590Srgrimes fpp->link = fp_head; 1711590Srgrimes fp_head = fpp; 1721590Srgrimes} 1731590Srgrimes 1741590Srgrimesvoid 175216564Scharnierunregister_file(FILE *fp) 1761590Srgrimes{ 1771590Srgrimes struct fp **pp, *p; 1781590Srgrimes 17977274Smikeh for (pp = &fp_head; (p = *pp) != NULL; pp = &p->link) 1801590Srgrimes if (p->fp == fp) { 1811590Srgrimes *pp = p->link; 18277274Smikeh (void)free(p); 1831590Srgrimes return; 1841590Srgrimes } 18574769Smikeh errx(1, "Invalid file pointer"); 18674769Smikeh /*NOTREACHED*/ 1871590Srgrimes} 1881590Srgrimes 189336953Smarkjint 190216564Scharnierfile_pid(FILE *fp) 1911590Srgrimes{ 1921590Srgrimes struct fp *p; 1931590Srgrimes 19477274Smikeh for (p = fp_head; p != NULL; p = p->link) 1951590Srgrimes if (p->fp == fp) 1961590Srgrimes return (p->pid); 19774769Smikeh errx(1, "Invalid file pointer"); 1981590Srgrimes /*NOTREACHED*/ 1991590Srgrimes} 2001590Srgrimes 2011590Srgrimes/* 2021590Srgrimes * Run a command without a shell, with optional arguments and splicing 203336953Smarkj * of stdin and stdout. The command name can be a sequence of words. 2041590Srgrimes * Signals must be handled by the caller. 205336953Smarkj * "Mask" contains the signals to ignore in the new process. 206336953Smarkj * SIGINT is enabled unless it's in the mask. 2071590Srgrimes */ 208336953Smarkj/*VARARGS4*/ 209336953Smarkjint 210336953Smarkjrun_command(char *cmd, sigset_t *mask, int infd, int outfd, char *a0, 211336953Smarkj char *a1, char *a2) 2121590Srgrimes{ 213336953Smarkj int pid; 2141590Srgrimes 215336953Smarkj if ((pid = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0) 216336953Smarkj return (-1); 217336953Smarkj return (wait_command(pid)); 218336953Smarkj} 219336953Smarkj 220336953Smarkj/*VARARGS4*/ 221336953Smarkjint 222336953Smarkjstart_command(char *cmd, sigset_t *mask, int infd, int outfd, char *a0, 223336953Smarkj char *a1, char *a2) 224336953Smarkj{ 225336953Smarkj int pid; 226336953Smarkj 22740188Sbde if ((pid = fork()) < 0) { 22874769Smikeh warn("fork"); 22977274Smikeh return (-1); 2301590Srgrimes } 2311590Srgrimes if (pid == 0) { 2321590Srgrimes char *argv[100]; 23377274Smikeh int i = getrawlist(cmd, argv, sizeof(argv) / sizeof(*argv)); 2341590Srgrimes 235336953Smarkj if ((argv[i++] = a0) != NULL && 236336953Smarkj (argv[i++] = a1) != NULL && 237336953Smarkj (argv[i++] = a2) != NULL) 238336953Smarkj argv[i] = NULL; 239336953Smarkj prepare_child(mask, infd, outfd); 2401590Srgrimes execvp(argv[0], argv); 24174769Smikeh warn("%s", argv[0]); 2421590Srgrimes _exit(1); 2431590Srgrimes } 24477274Smikeh return (pid); 2451590Srgrimes} 2461590Srgrimes 2471590Srgrimesvoid 248216564Scharnierprepare_child(sigset_t *nset, int infd, int outfd) 2491590Srgrimes{ 2501590Srgrimes int i; 25188150Smikeh sigset_t eset; 2521590Srgrimes 2531590Srgrimes /* 2541590Srgrimes * All file descriptors other than 0, 1, and 2 are supposed to be 2551590Srgrimes * close-on-exec. 2561590Srgrimes */ 2571590Srgrimes if (infd >= 0) 2581590Srgrimes dup2(infd, 0); 2591590Srgrimes if (outfd >= 0) 2601590Srgrimes dup2(outfd, 1); 26188150Smikeh for (i = 1; i < NSIG; i++) 26288150Smikeh if (nset != NULL && sigismember(nset, i)) 26377274Smikeh (void)signal(i, SIG_IGN); 26488150Smikeh if (nset == NULL || !sigismember(nset, SIGINT)) 26577274Smikeh (void)signal(SIGINT, SIG_DFL); 26688150Smikeh (void)sigemptyset(&eset); 26788150Smikeh (void)sigprocmask(SIG_SETMASK, &eset, NULL); 2681590Srgrimes} 2691590Srgrimes 2701590Srgrimesint 271336953Smarkjwait_command(int pid) 2721590Srgrimes{ 2731590Srgrimes 2741590Srgrimes if (wait_child(pid) < 0) { 2751590Srgrimes printf("Fatal error in process.\n"); 27677274Smikeh return (-1); 2771590Srgrimes } 27877274Smikeh return (0); 2791590Srgrimes} 2801590Srgrimes 2811590Srgrimesstatic struct child * 282336953Smarkjfindchild(int pid) 2831590Srgrimes{ 28477274Smikeh struct child **cpp; 2851590Srgrimes 2861590Srgrimes for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid; 28777274Smikeh cpp = &(*cpp)->link) 2881590Srgrimes ; 2891590Srgrimes if (*cpp == NULL) { 290336953Smarkj *cpp = malloc(sizeof(struct child)); 291336953Smarkj if (*cpp == NULL) 292336953Smarkj err(1, "Out of memory"); 2931590Srgrimes (*cpp)->pid = pid; 2941590Srgrimes (*cpp)->done = (*cpp)->free = 0; 2951590Srgrimes (*cpp)->link = NULL; 2961590Srgrimes } 29777274Smikeh return (*cpp); 2981590Srgrimes} 2991590Srgrimes 3001590Srgrimesstatic void 301216564Scharnierdelchild(struct child *cp) 3021590Srgrimes{ 30377274Smikeh struct child **cpp; 3041590Srgrimes 3051590Srgrimes for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link) 3061590Srgrimes ; 3071590Srgrimes *cpp = cp->link; 308336953Smarkj (void)free(cp); 3091590Srgrimes} 3101590Srgrimes 31177274Smikeh/*ARGSUSED*/ 3121590Srgrimesvoid 313216564Scharniersigchild(int signo __unused) 3141590Srgrimes{ 315336953Smarkj int pid; 31674769Smikeh int status; 31777274Smikeh struct child *cp; 3181590Srgrimes 319252679Skevlo while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { 320336953Smarkj cp = findchild(pid); 3211590Srgrimes if (cp->free) 3221590Srgrimes delchild(cp); 3231590Srgrimes else { 3241590Srgrimes cp->done = 1; 3251590Srgrimes cp->status = status; 3261590Srgrimes } 3271590Srgrimes } 3281590Srgrimes} 3291590Srgrimes 33074769Smikehint wait_status; 3311590Srgrimes 3321590Srgrimes/* 3331590Srgrimes * Wait for a specific child to die. 3341590Srgrimes */ 3351590Srgrimesint 336336953Smarkjwait_child(int pid) 3371590Srgrimes{ 338336953Smarkj sigset_t nset, oset; 339335693Seadler struct child *cp; 3401590Srgrimes 34188150Smikeh (void)sigemptyset(&nset); 34288150Smikeh (void)sigaddset(&nset, SIGCHLD); 343336953Smarkj (void)sigprocmask(SIG_BLOCK, &nset, &oset); 344336953Smarkj 345336953Smarkj cp = findchild(pid); 346336953Smarkj 347336953Smarkj while (!cp->done) 348336953Smarkj (void)sigsuspend(&oset); 349336953Smarkj wait_status = cp->status; 350336953Smarkj delchild(cp); 35188150Smikeh (void)sigprocmask(SIG_SETMASK, &oset, NULL); 352336953Smarkj return ((WIFEXITED(wait_status) && WEXITSTATUS(wait_status)) ? -1 : 0); 3531590Srgrimes} 3541590Srgrimes 3551590Srgrimes/* 3561590Srgrimes * Mark a child as don't care. 3571590Srgrimes */ 3581590Srgrimesvoid 359336953Smarkjfree_child(int pid) 3601590Srgrimes{ 36188150Smikeh sigset_t nset, oset; 362336953Smarkj struct child *cp = findchild(pid); 3631590Srgrimes 36488150Smikeh (void)sigemptyset(&nset); 36588150Smikeh (void)sigaddset(&nset, SIGCHLD); 366336953Smarkj (void)sigprocmask(SIG_BLOCK, &nset, &oset); 367336953Smarkj 368336953Smarkj if (cp->done) 369336953Smarkj delchild(cp); 370336953Smarkj else 371336953Smarkj cp->free = 1; 37288150Smikeh (void)sigprocmask(SIG_SETMASK, &oset, NULL); 3731590Srgrimes} 374