xref: /freebsd/usr.bin/mail/popen.c (revision 5e3934b1)
18a16b7a1SPedro F. Giffuni /*-
28a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni  *
49b50d902SRodney W. Grimes  * Copyright (c) 1980, 1993
59b50d902SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
69b50d902SRodney W. Grimes  *
79b50d902SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
89b50d902SRodney W. Grimes  * modification, are permitted provided that the following conditions
99b50d902SRodney W. Grimes  * are met:
109b50d902SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
119b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
129b50d902SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
139b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
149b50d902SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
169b50d902SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
179b50d902SRodney W. Grimes  *    without specific prior written permission.
189b50d902SRodney W. Grimes  *
199b50d902SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
209b50d902SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
219b50d902SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
229b50d902SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
239b50d902SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
249b50d902SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
259b50d902SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
269b50d902SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
279b50d902SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
289b50d902SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
299b50d902SRodney W. Grimes  * SUCH DAMAGE.
309b50d902SRodney W. Grimes  */
319b50d902SRodney W. Grimes 
329b50d902SRodney W. Grimes #include "rcv.h"
339b50d902SRodney W. Grimes #include <sys/wait.h>
349b50d902SRodney W. Grimes #include <fcntl.h>
35b22a8699SPedro F. Giffuni #include <errno.h>
36b22a8699SPedro F. Giffuni #include <stdarg.h>
379b50d902SRodney W. Grimes #include "extern.h"
389b50d902SRodney W. Grimes 
399b50d902SRodney W. Grimes #define READ 0
409b50d902SRodney W. Grimes #define WRITE 1
419b50d902SRodney W. Grimes 
429b50d902SRodney W. Grimes struct fp {
439b50d902SRodney W. Grimes 	FILE	*fp;
449b50d902SRodney W. Grimes 	int	pipe;
45b22a8699SPedro F. Giffuni 	pid_t	pid;
469b50d902SRodney W. Grimes 	struct	fp *link;
479b50d902SRodney W. Grimes };
489b50d902SRodney W. Grimes static struct fp *fp_head;
499b50d902SRodney W. Grimes 
509b50d902SRodney W. Grimes struct child {
51b22a8699SPedro F. Giffuni 	pid_t	pid;
529b50d902SRodney W. Grimes 	char	done;
539b50d902SRodney W. Grimes 	char	free;
540c3a8314SMike Heffner 	int	status;
559b50d902SRodney W. Grimes 	struct	child *link;
569b50d902SRodney W. Grimes };
57b22a8699SPedro F. Giffuni static struct child *child, *child_freelist = NULL;
58b22a8699SPedro F. Giffuni 
59d3cb5dedSWarner Losh static void delchild(struct child *);
60b22a8699SPedro F. Giffuni static pid_t file_pid(FILE *);
61b22a8699SPedro F. Giffuni static pid_t start_commandv(char *, sigset_t *, int, int, va_list);
629b50d902SRodney W. Grimes 
639b50d902SRodney W. Grimes FILE *
Fopen(const char * path,const char * mode)646d8484b0SPhilippe Charnier Fopen(const char *path, const char *mode)
659b50d902SRodney W. Grimes {
669b50d902SRodney W. Grimes 	FILE *fp;
679b50d902SRodney W. Grimes 
689ce73e90SMike Heffner 	if ((fp = fopen(path, mode)) != NULL) {
699b50d902SRodney W. Grimes 		register_file(fp, 0, 0);
709b50d902SRodney W. Grimes 		(void)fcntl(fileno(fp), F_SETFD, 1);
719b50d902SRodney W. Grimes 	}
729ce73e90SMike Heffner 	return (fp);
739b50d902SRodney W. Grimes }
749b50d902SRodney W. Grimes 
759b50d902SRodney W. Grimes FILE *
Fdopen(int fd,const char * mode)766d8484b0SPhilippe Charnier Fdopen(int fd, const char *mode)
779b50d902SRodney W. Grimes {
789b50d902SRodney W. Grimes 	FILE *fp;
799b50d902SRodney W. Grimes 
809b50d902SRodney W. Grimes 	if ((fp = fdopen(fd, mode)) != NULL) {
819b50d902SRodney W. Grimes 		register_file(fp, 0, 0);
829b50d902SRodney W. Grimes 		(void)fcntl(fileno(fp), F_SETFD, 1);
839b50d902SRodney W. Grimes 	}
849ce73e90SMike Heffner 	return (fp);
859b50d902SRodney W. Grimes }
869b50d902SRodney W. Grimes 
879b50d902SRodney W. Grimes int
Fclose(FILE * fp)886d8484b0SPhilippe Charnier Fclose(FILE *fp)
899b50d902SRodney W. Grimes {
90b22a8699SPedro F. Giffuni 
919b50d902SRodney W. Grimes 	unregister_file(fp);
929ce73e90SMike Heffner 	return (fclose(fp));
939b50d902SRodney W. Grimes }
949b50d902SRodney W. Grimes 
959b50d902SRodney W. Grimes FILE *
Popen(char * cmd,const char * mode)966d8484b0SPhilippe Charnier Popen(char *cmd, const char *mode)
979b50d902SRodney W. Grimes {
989b50d902SRodney W. Grimes 	int p[2];
999b50d902SRodney W. Grimes 	int myside, hisside, fd0, fd1;
100b22a8699SPedro F. Giffuni 	pid_t pid;
101856f23edSMike Heffner 	sigset_t nset;
1029b50d902SRodney W. Grimes 	FILE *fp;
1039b50d902SRodney W. Grimes 
1049b50d902SRodney W. Grimes 	if (pipe(p) < 0)
1059ce73e90SMike Heffner 		return (NULL);
1069b50d902SRodney W. Grimes 	(void)fcntl(p[READ], F_SETFD, 1);
1079b50d902SRodney W. Grimes 	(void)fcntl(p[WRITE], F_SETFD, 1);
1089b50d902SRodney W. Grimes 	if (*mode == 'r') {
1099b50d902SRodney W. Grimes 		myside = p[READ];
110b22a8699SPedro F. Giffuni 		hisside = fd0 = fd1 = p[WRITE];
1119b50d902SRodney W. Grimes 	} else {
1129b50d902SRodney W. Grimes 		myside = p[WRITE];
1139b50d902SRodney W. Grimes 		hisside = fd0 = p[READ];
1149b50d902SRodney W. Grimes 		fd1 = -1;
1159b50d902SRodney W. Grimes 	}
116856f23edSMike Heffner 	(void)sigemptyset(&nset);
117b22a8699SPedro F. Giffuni 	pid = start_command(value("SHELL"), &nset, fd0, fd1, "-c", cmd, NULL);
118b22a8699SPedro F. Giffuni 	if (pid < 0) {
1199ce73e90SMike Heffner 		(void)close(p[READ]);
1209ce73e90SMike Heffner 		(void)close(p[WRITE]);
1219ce73e90SMike Heffner 		return (NULL);
1229b50d902SRodney W. Grimes 	}
1239b50d902SRodney W. Grimes 	(void)close(hisside);
1249b50d902SRodney W. Grimes 	if ((fp = fdopen(myside, mode)) != NULL)
1259b50d902SRodney W. Grimes 		register_file(fp, 1, pid);
1269ce73e90SMike Heffner 	return (fp);
1279b50d902SRodney W. Grimes }
1289b50d902SRodney W. Grimes 
1299b50d902SRodney W. Grimes int
Pclose(FILE * ptr)1306d8484b0SPhilippe Charnier Pclose(FILE *ptr)
1319b50d902SRodney W. Grimes {
1329b50d902SRodney W. Grimes 	int i;
133856f23edSMike Heffner 	sigset_t nset, oset;
1349b50d902SRodney W. Grimes 
1359b50d902SRodney W. Grimes 	i = file_pid(ptr);
1369b50d902SRodney W. Grimes 	unregister_file(ptr);
1379b50d902SRodney W. Grimes 	(void)fclose(ptr);
138856f23edSMike Heffner 	(void)sigemptyset(&nset);
139856f23edSMike Heffner 	(void)sigaddset(&nset, SIGINT);
140856f23edSMike Heffner 	(void)sigaddset(&nset, SIGHUP);
141856f23edSMike Heffner 	(void)sigprocmask(SIG_BLOCK, &nset, &oset);
1429b50d902SRodney W. Grimes 	i = wait_child(i);
143856f23edSMike Heffner 	(void)sigprocmask(SIG_SETMASK, &oset, NULL);
1449ce73e90SMike Heffner 	return (i);
1459b50d902SRodney W. Grimes }
1469b50d902SRodney W. Grimes 
1479b50d902SRodney W. Grimes void
close_all_files(void)1486d8484b0SPhilippe Charnier close_all_files(void)
1499b50d902SRodney W. Grimes {
1509b50d902SRodney W. Grimes 
1519ce73e90SMike Heffner 	while (fp_head != NULL)
1529b50d902SRodney W. Grimes 		if (fp_head->pipe)
1539b50d902SRodney W. Grimes 			(void)Pclose(fp_head->fp);
1549b50d902SRodney W. Grimes 		else
1559b50d902SRodney W. Grimes 			(void)Fclose(fp_head->fp);
1569b50d902SRodney W. Grimes }
1579b50d902SRodney W. Grimes 
1589b50d902SRodney W. Grimes void
register_file(FILE * fp,int pipe,pid_t pid)159b22a8699SPedro F. Giffuni register_file(FILE *fp, int pipe, pid_t pid)
1609b50d902SRodney W. Grimes {
1619b50d902SRodney W. Grimes 	struct fp *fpp;
1629b50d902SRodney W. Grimes 
1639ce73e90SMike Heffner 	if ((fpp = malloc(sizeof(*fpp))) == NULL)
1640c3a8314SMike Heffner 		err(1, "Out of memory");
1659b50d902SRodney W. Grimes 	fpp->fp = fp;
1669b50d902SRodney W. Grimes 	fpp->pipe = pipe;
1679b50d902SRodney W. Grimes 	fpp->pid = pid;
1689b50d902SRodney W. Grimes 	fpp->link = fp_head;
1699b50d902SRodney W. Grimes 	fp_head = fpp;
1709b50d902SRodney W. Grimes }
1719b50d902SRodney W. Grimes 
1729b50d902SRodney W. Grimes void
unregister_file(FILE * fp)1736d8484b0SPhilippe Charnier unregister_file(FILE *fp)
1749b50d902SRodney W. Grimes {
1759b50d902SRodney W. Grimes 	struct fp **pp, *p;
1769b50d902SRodney W. Grimes 
1779ce73e90SMike Heffner 	for (pp = &fp_head; (p = *pp) != NULL; pp = &p->link)
1789b50d902SRodney W. Grimes 		if (p->fp == fp) {
1799b50d902SRodney W. Grimes 			*pp = p->link;
1809ce73e90SMike Heffner 			(void)free(p);
1819b50d902SRodney W. Grimes 			return;
1829b50d902SRodney W. Grimes 		}
1830c3a8314SMike Heffner 	errx(1, "Invalid file pointer");
1840c3a8314SMike Heffner 	/*NOTREACHED*/
1859b50d902SRodney W. Grimes }
1869b50d902SRodney W. Grimes 
187b22a8699SPedro F. Giffuni pid_t
file_pid(FILE * fp)1886d8484b0SPhilippe Charnier file_pid(FILE *fp)
1899b50d902SRodney W. Grimes {
1909b50d902SRodney W. Grimes 	struct fp *p;
1919b50d902SRodney W. Grimes 
1929ce73e90SMike Heffner 	for (p = fp_head; p != NULL; p = p->link)
1939b50d902SRodney W. Grimes 		if (p->fp == fp)
1949b50d902SRodney W. Grimes 			return (p->pid);
1950c3a8314SMike Heffner 	errx(1, "Invalid file pointer");
1969b50d902SRodney W. Grimes 	/*NOTREACHED*/
1979b50d902SRodney W. Grimes }
1989b50d902SRodney W. Grimes 
1999b50d902SRodney W. Grimes /*
2009b50d902SRodney W. Grimes  * Run a command without a shell, with optional arguments and splicing
201b22a8699SPedro F. Giffuni  * of stdin (-1 means none) and stdout.  The command name can be a sequence
202b22a8699SPedro F. Giffuni  * of words.
2039b50d902SRodney W. Grimes  * Signals must be handled by the caller.
204b22a8699SPedro F. Giffuni  * "nset" contains the signals to ignore in the new process.
205b22a8699SPedro F. Giffuni  * SIGINT is enabled unless it's in "nset".
2069b50d902SRodney W. Grimes  */
207b22a8699SPedro F. Giffuni static pid_t
start_commandv(char * cmd,sigset_t * nset,int infd,int outfd,va_list args)208b22a8699SPedro F. Giffuni start_commandv(char *cmd, sigset_t *nset, int infd, int outfd, va_list args)
2099b50d902SRodney W. Grimes {
210b22a8699SPedro F. Giffuni 	pid_t pid;
2119b50d902SRodney W. Grimes 
212db6b6910SBruce Evans 	if ((pid = fork()) < 0) {
2130c3a8314SMike Heffner 		warn("fork");
2149ce73e90SMike Heffner 		return (-1);
2159b50d902SRodney W. Grimes 	}
2169b50d902SRodney W. Grimes 	if (pid == 0) {
2179b50d902SRodney W. Grimes 		char *argv[100];
2189ce73e90SMike Heffner 		int i = getrawlist(cmd, argv, sizeof(argv) / sizeof(*argv));
2199b50d902SRodney W. Grimes 
220b22a8699SPedro F. Giffuni 		while ((argv[i++] = va_arg(args, char *)))
221b22a8699SPedro F. Giffuni 			;
2229ce73e90SMike Heffner 		argv[i] = NULL;
223b22a8699SPedro F. Giffuni 		prepare_child(nset, infd, outfd);
2249b50d902SRodney W. Grimes 		execvp(argv[0], argv);
2250c3a8314SMike Heffner 		warn("%s", argv[0]);
2269b50d902SRodney W. Grimes 		_exit(1);
2279b50d902SRodney W. Grimes 	}
2289ce73e90SMike Heffner 	return (pid);
2299b50d902SRodney W. Grimes }
2309b50d902SRodney W. Grimes 
231b22a8699SPedro F. Giffuni int
run_command(char * cmd,sigset_t * nset,int infd,int outfd,...)232b22a8699SPedro F. Giffuni run_command(char *cmd, sigset_t *nset, int infd, int outfd, ...)
233b22a8699SPedro F. Giffuni {
234b22a8699SPedro F. Giffuni 	pid_t pid;
235b22a8699SPedro F. Giffuni 	va_list args;
236b22a8699SPedro F. Giffuni 
237b22a8699SPedro F. Giffuni 	va_start(args, outfd);
238b22a8699SPedro F. Giffuni 	pid = start_commandv(cmd, nset, infd, outfd, args);
239b22a8699SPedro F. Giffuni 	va_end(args);
240b22a8699SPedro F. Giffuni 	if (pid < 0)
241b22a8699SPedro F. Giffuni 		return -1;
242b22a8699SPedro F. Giffuni 	return wait_command(pid);
243b22a8699SPedro F. Giffuni }
244b22a8699SPedro F. Giffuni 
245b22a8699SPedro F. Giffuni int
start_command(char * cmd,sigset_t * nset,int infd,int outfd,...)246b22a8699SPedro F. Giffuni start_command(char *cmd, sigset_t *nset, int infd, int outfd, ...)
247b22a8699SPedro F. Giffuni {
248b22a8699SPedro F. Giffuni 	va_list args;
249b22a8699SPedro F. Giffuni 	int r;
250b22a8699SPedro F. Giffuni 
251b22a8699SPedro F. Giffuni 	va_start(args, outfd);
252b22a8699SPedro F. Giffuni 	r = start_commandv(cmd, nset, infd, outfd, args);
253b22a8699SPedro F. Giffuni 	va_end(args);
254b22a8699SPedro F. Giffuni 	return r;
255b22a8699SPedro F. Giffuni }
256b22a8699SPedro F. Giffuni 
2579b50d902SRodney W. Grimes void
prepare_child(sigset_t * nset,int infd,int outfd)2586d8484b0SPhilippe Charnier prepare_child(sigset_t *nset, int infd, int outfd)
2599b50d902SRodney W. Grimes {
2609b50d902SRodney W. Grimes 	int i;
261856f23edSMike Heffner 	sigset_t eset;
2629b50d902SRodney W. Grimes 
2639b50d902SRodney W. Grimes 	/*
2649b50d902SRodney W. Grimes 	 * All file descriptors other than 0, 1, and 2 are supposed to be
2659b50d902SRodney W. Grimes 	 * close-on-exec.
2669b50d902SRodney W. Grimes 	 */
2679b50d902SRodney W. Grimes 	if (infd >= 0)
2689b50d902SRodney W. Grimes 		dup2(infd, 0);
2699b50d902SRodney W. Grimes 	if (outfd >= 0)
2709b50d902SRodney W. Grimes 		dup2(outfd, 1);
271856f23edSMike Heffner 	for (i = 1; i < NSIG; i++)
272856f23edSMike Heffner 		if (nset != NULL && sigismember(nset, i))
2739b50d902SRodney W. Grimes 			(void)signal(i, SIG_IGN);
274856f23edSMike Heffner 	if (nset == NULL || !sigismember(nset, SIGINT))
2759b50d902SRodney W. Grimes 		(void)signal(SIGINT, SIG_DFL);
276856f23edSMike Heffner 	(void)sigemptyset(&eset);
277856f23edSMike Heffner 	(void)sigprocmask(SIG_SETMASK, &eset, NULL);
2789b50d902SRodney W. Grimes }
2799b50d902SRodney W. Grimes 
2809b50d902SRodney W. Grimes int
wait_command(pid_t pid)281b22a8699SPedro F. Giffuni wait_command(pid_t pid)
2829b50d902SRodney W. Grimes {
2839b50d902SRodney W. Grimes 
2849b50d902SRodney W. Grimes 	if (wait_child(pid) < 0) {
2859b50d902SRodney W. Grimes 		printf("Fatal error in process.\n");
2869ce73e90SMike Heffner 		return (-1);
2879b50d902SRodney W. Grimes 	}
2889ce73e90SMike Heffner 	return (0);
2899b50d902SRodney W. Grimes }
2909b50d902SRodney W. Grimes 
2919b50d902SRodney W. Grimes static struct child *
findchild(pid_t pid,int dont_alloc)292b22a8699SPedro F. Giffuni findchild(pid_t pid, int dont_alloc)
2939b50d902SRodney W. Grimes {
2949ce73e90SMike Heffner 	struct child **cpp;
2959b50d902SRodney W. Grimes 
2969b50d902SRodney W. Grimes 	for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid;
2979b50d902SRodney W. Grimes 	    cpp = &(*cpp)->link)
2989b50d902SRodney W. Grimes 			;
2999b50d902SRodney W. Grimes 	if (*cpp == NULL) {
300b22a8699SPedro F. Giffuni 		if (dont_alloc)
301b22a8699SPedro F. Giffuni 			return(NULL);
302b22a8699SPedro F. Giffuni 		if (child_freelist) {
303b22a8699SPedro F. Giffuni 			*cpp = child_freelist;
304b22a8699SPedro F. Giffuni 			child_freelist = (*cpp)->link;
305b22a8699SPedro F. Giffuni 		} else {
3069ce73e90SMike Heffner 			*cpp = malloc(sizeof(struct child));
3070c3a8314SMike Heffner 			if (*cpp == NULL)
308b22a8699SPedro F. Giffuni 				err(1, "malloc");
309b22a8699SPedro F. Giffuni 		}
3109b50d902SRodney W. Grimes 		(*cpp)->pid = pid;
3119b50d902SRodney W. Grimes 		(*cpp)->done = (*cpp)->free = 0;
3129b50d902SRodney W. Grimes 		(*cpp)->link = NULL;
3139b50d902SRodney W. Grimes 	}
3149ce73e90SMike Heffner 	return (*cpp);
3159b50d902SRodney W. Grimes }
3169b50d902SRodney W. Grimes 
3179b50d902SRodney W. Grimes static void
delchild(struct child * cp)3186d8484b0SPhilippe Charnier delchild(struct child *cp)
3199b50d902SRodney W. Grimes {
3209ce73e90SMike Heffner 	struct child **cpp;
3219b50d902SRodney W. Grimes 
3229b50d902SRodney W. Grimes 	for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link)
3239b50d902SRodney W. Grimes 		;
3249b50d902SRodney W. Grimes 	*cpp = cp->link;
325b22a8699SPedro F. Giffuni 	cp->link = child_freelist;
326b22a8699SPedro F. Giffuni 	child_freelist = cp;
3279b50d902SRodney W. Grimes }
3289b50d902SRodney W. Grimes 
3299ce73e90SMike Heffner /*ARGSUSED*/
3309b50d902SRodney W. Grimes void
sigchild(int signo __unused)3316d8484b0SPhilippe Charnier sigchild(int signo __unused)
3329b50d902SRodney W. Grimes {
333b22a8699SPedro F. Giffuni 	pid_t pid;
3340c3a8314SMike Heffner 	int status;
3359ce73e90SMike Heffner 	struct child *cp;
336b22a8699SPedro F. Giffuni 	int save_errno;
3379b50d902SRodney W. Grimes 
338b22a8699SPedro F. Giffuni 	save_errno = errno;
339ed74b69cSKevin Lo 	while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
340b22a8699SPedro F. Giffuni 		cp = findchild(pid, 1);
3411d1e1f63SXin LI 		if (cp == NULL)
3421d1e1f63SXin LI 			continue;
3439b50d902SRodney W. Grimes 		if (cp->free)
3449b50d902SRodney W. Grimes 			delchild(cp);
3459b50d902SRodney W. Grimes 		else {
3469b50d902SRodney W. Grimes 			cp->done = 1;
3479b50d902SRodney W. Grimes 			cp->status = status;
3489b50d902SRodney W. Grimes 		}
3499b50d902SRodney W. Grimes 	}
350b22a8699SPedro F. Giffuni 	errno = save_errno;
3519b50d902SRodney W. Grimes }
3529b50d902SRodney W. Grimes 
3530c3a8314SMike Heffner int wait_status;
3549b50d902SRodney W. Grimes 
3559b50d902SRodney W. Grimes /*
3569b50d902SRodney W. Grimes  * Wait for a specific child to die.
3579b50d902SRodney W. Grimes  */
3589b50d902SRodney W. Grimes int
wait_child(pid_t pid)359b22a8699SPedro F. Giffuni wait_child(pid_t pid)
3609b50d902SRodney W. Grimes {
36135f8ab70SEitan Adler 	struct child *cp;
36292fa728bSPedro F. Giffuni 	sigset_t nset, oset;
36392fa728bSPedro F. Giffuni 	pid_t rv = 0;
3649b50d902SRodney W. Grimes 
365856f23edSMike Heffner 	(void)sigemptyset(&nset);
366856f23edSMike Heffner 	(void)sigaddset(&nset, SIGCHLD);
367856f23edSMike Heffner 	(void)sigprocmask(SIG_BLOCK, &nset, &oset);
36892fa728bSPedro F. Giffuni 	/*
36992fa728bSPedro F. Giffuni 	 * If we have not already waited on the pid (via sigchild)
37092fa728bSPedro F. Giffuni 	 * wait on it now.  Otherwise, use the wait status stashed
37192fa728bSPedro F. Giffuni 	 * by sigchild.
37292fa728bSPedro F. Giffuni 	 */
373b22a8699SPedro F. Giffuni 	cp = findchild(pid, 1);
37492fa728bSPedro F. Giffuni 	if (cp == NULL || !cp->done)
37592fa728bSPedro F. Giffuni 		rv = waitpid(pid, &wait_status, 0);
37692fa728bSPedro F. Giffuni 	else
3779b50d902SRodney W. Grimes 		wait_status = cp->status;
37892fa728bSPedro F. Giffuni 	if (cp != NULL)
3799b50d902SRodney W. Grimes 		delchild(cp);
380856f23edSMike Heffner 	(void)sigprocmask(SIG_SETMASK, &oset, NULL);
38192fa728bSPedro F. Giffuni 	if (rv == -1 || (WIFEXITED(wait_status) && WEXITSTATUS(wait_status)))
38292fa728bSPedro F. Giffuni 		return -1;
38392fa728bSPedro F. Giffuni 	else
38492fa728bSPedro F. Giffuni 		return 0;
3859b50d902SRodney W. Grimes }
3869b50d902SRodney W. Grimes 
3879b50d902SRodney W. Grimes /*
3889b50d902SRodney W. Grimes  * Mark a child as don't care.
3899b50d902SRodney W. Grimes  */
3909b50d902SRodney W. Grimes void
free_child(pid_t pid)391b22a8699SPedro F. Giffuni free_child(pid_t pid)
3929b50d902SRodney W. Grimes {
393b22a8699SPedro F. Giffuni 	struct child *cp;
394856f23edSMike Heffner 	sigset_t nset, oset;
3959b50d902SRodney W. Grimes 
396856f23edSMike Heffner 	(void)sigemptyset(&nset);
397856f23edSMike Heffner 	(void)sigaddset(&nset, SIGCHLD);
398856f23edSMike Heffner 	(void)sigprocmask(SIG_BLOCK, &nset, &oset);
399b22a8699SPedro F. Giffuni 	if ((cp = findchild(pid, 0)) != NULL) {
4009b50d902SRodney W. Grimes 		if (cp->done)
4019b50d902SRodney W. Grimes 			delchild(cp);
4029b50d902SRodney W. Grimes 		else
4039b50d902SRodney W. Grimes 			cp->free = 1;
404b22a8699SPedro F. Giffuni 	}
405856f23edSMike Heffner 	(void)sigprocmask(SIG_SETMASK, &oset, NULL);
4069b50d902SRodney W. Grimes }
407