xref: /freebsd/usr.bin/mail/popen.c (revision 8a16b7a18f5d0b031f09832fd7752fba717e2a97)
1*8a16b7a1SPedro F. Giffuni /*-
2*8a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
3*8a16b7a1SPedro 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 #ifndef lint
330c3a8314SMike Heffner #if 0
349b50d902SRodney W. Grimes static char sccsid[] = "@(#)popen.c	8.1 (Berkeley) 6/6/93";
350c3a8314SMike Heffner #endif
369b50d902SRodney W. Grimes #endif /* not lint */
37e026a48cSDavid E. O'Brien #include <sys/cdefs.h>
38e026a48cSDavid E. O'Brien __FBSDID("$FreeBSD$");
399b50d902SRodney W. Grimes 
409b50d902SRodney W. Grimes #include "rcv.h"
419b50d902SRodney W. Grimes #include <sys/wait.h>
429b50d902SRodney W. Grimes #include <fcntl.h>
43b22a8699SPedro F. Giffuni #include <errno.h>
44b22a8699SPedro F. Giffuni #include <stdarg.h>
459b50d902SRodney W. Grimes #include "extern.h"
469b50d902SRodney W. Grimes 
479b50d902SRodney W. Grimes #define READ 0
489b50d902SRodney W. Grimes #define WRITE 1
499b50d902SRodney W. Grimes 
509b50d902SRodney W. Grimes struct fp {
519b50d902SRodney W. Grimes 	FILE	*fp;
529b50d902SRodney W. Grimes 	int	pipe;
53b22a8699SPedro F. Giffuni 	pid_t	pid;
549b50d902SRodney W. Grimes 	struct	fp *link;
559b50d902SRodney W. Grimes };
569b50d902SRodney W. Grimes static struct fp *fp_head;
579b50d902SRodney W. Grimes 
589b50d902SRodney W. Grimes struct child {
59b22a8699SPedro F. Giffuni 	pid_t	pid;
609b50d902SRodney W. Grimes 	char	done;
619b50d902SRodney W. Grimes 	char	free;
620c3a8314SMike Heffner 	int	status;
639b50d902SRodney W. Grimes 	struct	child *link;
649b50d902SRodney W. Grimes };
65b22a8699SPedro F. Giffuni static struct child *child, *child_freelist = NULL;
66b22a8699SPedro F. Giffuni 
67d3cb5dedSWarner Losh static void delchild(struct child *);
68b22a8699SPedro F. Giffuni static pid_t file_pid(FILE *);
69b22a8699SPedro F. Giffuni static pid_t start_commandv(char *, sigset_t *, int, int, va_list);
709b50d902SRodney W. Grimes 
719b50d902SRodney W. Grimes FILE *
726d8484b0SPhilippe Charnier Fopen(const char *path, const char *mode)
739b50d902SRodney W. Grimes {
749b50d902SRodney W. Grimes 	FILE *fp;
759b50d902SRodney W. Grimes 
769ce73e90SMike Heffner 	if ((fp = fopen(path, mode)) != NULL) {
779b50d902SRodney W. Grimes 		register_file(fp, 0, 0);
789b50d902SRodney W. Grimes 		(void)fcntl(fileno(fp), F_SETFD, 1);
799b50d902SRodney W. Grimes 	}
809ce73e90SMike Heffner 	return (fp);
819b50d902SRodney W. Grimes }
829b50d902SRodney W. Grimes 
839b50d902SRodney W. Grimes FILE *
846d8484b0SPhilippe Charnier Fdopen(int fd, const char *mode)
859b50d902SRodney W. Grimes {
869b50d902SRodney W. Grimes 	FILE *fp;
879b50d902SRodney W. Grimes 
889b50d902SRodney W. Grimes 	if ((fp = fdopen(fd, mode)) != NULL) {
899b50d902SRodney W. Grimes 		register_file(fp, 0, 0);
909b50d902SRodney W. Grimes 		(void)fcntl(fileno(fp), F_SETFD, 1);
919b50d902SRodney W. Grimes 	}
929ce73e90SMike Heffner 	return (fp);
939b50d902SRodney W. Grimes }
949b50d902SRodney W. Grimes 
959b50d902SRodney W. Grimes int
966d8484b0SPhilippe Charnier Fclose(FILE *fp)
979b50d902SRodney W. Grimes {
98b22a8699SPedro F. Giffuni 
999b50d902SRodney W. Grimes 	unregister_file(fp);
1009ce73e90SMike Heffner 	return (fclose(fp));
1019b50d902SRodney W. Grimes }
1029b50d902SRodney W. Grimes 
1039b50d902SRodney W. Grimes FILE *
1046d8484b0SPhilippe Charnier Popen(char *cmd, const char *mode)
1059b50d902SRodney W. Grimes {
1069b50d902SRodney W. Grimes 	int p[2];
1079b50d902SRodney W. Grimes 	int myside, hisside, fd0, fd1;
108b22a8699SPedro F. Giffuni 	pid_t pid;
109856f23edSMike Heffner 	sigset_t nset;
1109b50d902SRodney W. Grimes 	FILE *fp;
1119b50d902SRodney W. Grimes 
1129b50d902SRodney W. Grimes 	if (pipe(p) < 0)
1139ce73e90SMike Heffner 		return (NULL);
1149b50d902SRodney W. Grimes 	(void)fcntl(p[READ], F_SETFD, 1);
1159b50d902SRodney W. Grimes 	(void)fcntl(p[WRITE], F_SETFD, 1);
1169b50d902SRodney W. Grimes 	if (*mode == 'r') {
1179b50d902SRodney W. Grimes 		myside = p[READ];
118b22a8699SPedro F. Giffuni 		hisside = fd0 = fd1 = p[WRITE];
1199b50d902SRodney W. Grimes 	} else {
1209b50d902SRodney W. Grimes 		myside = p[WRITE];
1219b50d902SRodney W. Grimes 		hisside = fd0 = p[READ];
1229b50d902SRodney W. Grimes 		fd1 = -1;
1239b50d902SRodney W. Grimes 	}
124856f23edSMike Heffner 	(void)sigemptyset(&nset);
125b22a8699SPedro F. Giffuni 	pid = start_command(value("SHELL"), &nset, fd0, fd1, "-c", cmd, NULL);
126b22a8699SPedro F. Giffuni 	if (pid < 0) {
1279ce73e90SMike Heffner 		(void)close(p[READ]);
1289ce73e90SMike Heffner 		(void)close(p[WRITE]);
1299ce73e90SMike Heffner 		return (NULL);
1309b50d902SRodney W. Grimes 	}
1319b50d902SRodney W. Grimes 	(void)close(hisside);
1329b50d902SRodney W. Grimes 	if ((fp = fdopen(myside, mode)) != NULL)
1339b50d902SRodney W. Grimes 		register_file(fp, 1, pid);
1349ce73e90SMike Heffner 	return (fp);
1359b50d902SRodney W. Grimes }
1369b50d902SRodney W. Grimes 
1379b50d902SRodney W. Grimes int
1386d8484b0SPhilippe Charnier Pclose(FILE *ptr)
1399b50d902SRodney W. Grimes {
1409b50d902SRodney W. Grimes 	int i;
141856f23edSMike Heffner 	sigset_t nset, oset;
1429b50d902SRodney W. Grimes 
1439b50d902SRodney W. Grimes 	i = file_pid(ptr);
1449b50d902SRodney W. Grimes 	unregister_file(ptr);
1459b50d902SRodney W. Grimes 	(void)fclose(ptr);
146856f23edSMike Heffner 	(void)sigemptyset(&nset);
147856f23edSMike Heffner 	(void)sigaddset(&nset, SIGINT);
148856f23edSMike Heffner 	(void)sigaddset(&nset, SIGHUP);
149856f23edSMike Heffner 	(void)sigprocmask(SIG_BLOCK, &nset, &oset);
1509b50d902SRodney W. Grimes 	i = wait_child(i);
151856f23edSMike Heffner 	(void)sigprocmask(SIG_SETMASK, &oset, NULL);
1529ce73e90SMike Heffner 	return (i);
1539b50d902SRodney W. Grimes }
1549b50d902SRodney W. Grimes 
1559b50d902SRodney W. Grimes void
1566d8484b0SPhilippe Charnier close_all_files(void)
1579b50d902SRodney W. Grimes {
1589b50d902SRodney W. Grimes 
1599ce73e90SMike Heffner 	while (fp_head != NULL)
1609b50d902SRodney W. Grimes 		if (fp_head->pipe)
1619b50d902SRodney W. Grimes 			(void)Pclose(fp_head->fp);
1629b50d902SRodney W. Grimes 		else
1639b50d902SRodney W. Grimes 			(void)Fclose(fp_head->fp);
1649b50d902SRodney W. Grimes }
1659b50d902SRodney W. Grimes 
1669b50d902SRodney W. Grimes void
167b22a8699SPedro F. Giffuni register_file(FILE *fp, int pipe, pid_t pid)
1689b50d902SRodney W. Grimes {
1699b50d902SRodney W. Grimes 	struct fp *fpp;
1709b50d902SRodney W. Grimes 
1719ce73e90SMike Heffner 	if ((fpp = malloc(sizeof(*fpp))) == NULL)
1720c3a8314SMike Heffner 		err(1, "Out of memory");
1739b50d902SRodney W. Grimes 	fpp->fp = fp;
1749b50d902SRodney W. Grimes 	fpp->pipe = pipe;
1759b50d902SRodney W. Grimes 	fpp->pid = pid;
1769b50d902SRodney W. Grimes 	fpp->link = fp_head;
1779b50d902SRodney W. Grimes 	fp_head = fpp;
1789b50d902SRodney W. Grimes }
1799b50d902SRodney W. Grimes 
1809b50d902SRodney W. Grimes void
1816d8484b0SPhilippe Charnier unregister_file(FILE *fp)
1829b50d902SRodney W. Grimes {
1839b50d902SRodney W. Grimes 	struct fp **pp, *p;
1849b50d902SRodney W. Grimes 
1859ce73e90SMike Heffner 	for (pp = &fp_head; (p = *pp) != NULL; pp = &p->link)
1869b50d902SRodney W. Grimes 		if (p->fp == fp) {
1879b50d902SRodney W. Grimes 			*pp = p->link;
1889ce73e90SMike Heffner 			(void)free(p);
1899b50d902SRodney W. Grimes 			return;
1909b50d902SRodney W. Grimes 		}
1910c3a8314SMike Heffner 	errx(1, "Invalid file pointer");
1920c3a8314SMike Heffner 	/*NOTREACHED*/
1939b50d902SRodney W. Grimes }
1949b50d902SRodney W. Grimes 
195b22a8699SPedro F. Giffuni pid_t
1966d8484b0SPhilippe Charnier file_pid(FILE *fp)
1979b50d902SRodney W. Grimes {
1989b50d902SRodney W. Grimes 	struct fp *p;
1999b50d902SRodney W. Grimes 
2009ce73e90SMike Heffner 	for (p = fp_head; p != NULL; p = p->link)
2019b50d902SRodney W. Grimes 		if (p->fp == fp)
2029b50d902SRodney W. Grimes 			return (p->pid);
2030c3a8314SMike Heffner 	errx(1, "Invalid file pointer");
2049b50d902SRodney W. Grimes 	/*NOTREACHED*/
2059b50d902SRodney W. Grimes }
2069b50d902SRodney W. Grimes 
2079b50d902SRodney W. Grimes /*
2089b50d902SRodney W. Grimes  * Run a command without a shell, with optional arguments and splicing
209b22a8699SPedro F. Giffuni  * of stdin (-1 means none) and stdout.  The command name can be a sequence
210b22a8699SPedro F. Giffuni  * of words.
2119b50d902SRodney W. Grimes  * Signals must be handled by the caller.
212b22a8699SPedro F. Giffuni  * "nset" contains the signals to ignore in the new process.
213b22a8699SPedro F. Giffuni  * SIGINT is enabled unless it's in "nset".
2149b50d902SRodney W. Grimes  */
215b22a8699SPedro F. Giffuni static pid_t
216b22a8699SPedro F. Giffuni start_commandv(char *cmd, sigset_t *nset, int infd, int outfd, va_list args)
2179b50d902SRodney W. Grimes {
218b22a8699SPedro F. Giffuni 	pid_t pid;
2199b50d902SRodney W. Grimes 
220db6b6910SBruce Evans 	if ((pid = fork()) < 0) {
2210c3a8314SMike Heffner 		warn("fork");
2229ce73e90SMike Heffner 		return (-1);
2239b50d902SRodney W. Grimes 	}
2249b50d902SRodney W. Grimes 	if (pid == 0) {
2259b50d902SRodney W. Grimes 		char *argv[100];
2269ce73e90SMike Heffner 		int i = getrawlist(cmd, argv, sizeof(argv) / sizeof(*argv));
2279b50d902SRodney W. Grimes 
228b22a8699SPedro F. Giffuni 		while ((argv[i++] = va_arg(args, char *)))
229b22a8699SPedro F. Giffuni 			;
2309ce73e90SMike Heffner 		argv[i] = NULL;
231b22a8699SPedro F. Giffuni 		prepare_child(nset, infd, outfd);
2329b50d902SRodney W. Grimes 		execvp(argv[0], argv);
2330c3a8314SMike Heffner 		warn("%s", argv[0]);
2349b50d902SRodney W. Grimes 		_exit(1);
2359b50d902SRodney W. Grimes 	}
2369ce73e90SMike Heffner 	return (pid);
2379b50d902SRodney W. Grimes }
2389b50d902SRodney W. Grimes 
239b22a8699SPedro F. Giffuni int
240b22a8699SPedro F. Giffuni run_command(char *cmd, sigset_t *nset, int infd, int outfd, ...)
241b22a8699SPedro F. Giffuni {
242b22a8699SPedro F. Giffuni 	pid_t pid;
243b22a8699SPedro F. Giffuni 	va_list args;
244b22a8699SPedro F. Giffuni 
245b22a8699SPedro F. Giffuni 	va_start(args, outfd);
246b22a8699SPedro F. Giffuni 	pid = start_commandv(cmd, nset, infd, outfd, args);
247b22a8699SPedro F. Giffuni 	va_end(args);
248b22a8699SPedro F. Giffuni 	if (pid < 0)
249b22a8699SPedro F. Giffuni 		return -1;
250b22a8699SPedro F. Giffuni 	return wait_command(pid);
251b22a8699SPedro F. Giffuni }
252b22a8699SPedro F. Giffuni 
253b22a8699SPedro F. Giffuni int
254b22a8699SPedro F. Giffuni start_command(char *cmd, sigset_t *nset, int infd, int outfd, ...)
255b22a8699SPedro F. Giffuni {
256b22a8699SPedro F. Giffuni 	va_list args;
257b22a8699SPedro F. Giffuni 	int r;
258b22a8699SPedro F. Giffuni 
259b22a8699SPedro F. Giffuni 	va_start(args, outfd);
260b22a8699SPedro F. Giffuni 	r = start_commandv(cmd, nset, infd, outfd, args);
261b22a8699SPedro F. Giffuni 	va_end(args);
262b22a8699SPedro F. Giffuni 	return r;
263b22a8699SPedro F. Giffuni }
264b22a8699SPedro F. Giffuni 
2659b50d902SRodney W. Grimes void
2666d8484b0SPhilippe Charnier prepare_child(sigset_t *nset, int infd, int outfd)
2679b50d902SRodney W. Grimes {
2689b50d902SRodney W. Grimes 	int i;
269856f23edSMike Heffner 	sigset_t eset;
2709b50d902SRodney W. Grimes 
2719b50d902SRodney W. Grimes 	/*
2729b50d902SRodney W. Grimes 	 * All file descriptors other than 0, 1, and 2 are supposed to be
2739b50d902SRodney W. Grimes 	 * close-on-exec.
2749b50d902SRodney W. Grimes 	 */
2759b50d902SRodney W. Grimes 	if (infd >= 0)
2769b50d902SRodney W. Grimes 		dup2(infd, 0);
2779b50d902SRodney W. Grimes 	if (outfd >= 0)
2789b50d902SRodney W. Grimes 		dup2(outfd, 1);
279856f23edSMike Heffner 	for (i = 1; i < NSIG; i++)
280856f23edSMike Heffner 		if (nset != NULL && sigismember(nset, i))
2819b50d902SRodney W. Grimes 			(void)signal(i, SIG_IGN);
282856f23edSMike Heffner 	if (nset == NULL || !sigismember(nset, SIGINT))
2839b50d902SRodney W. Grimes 		(void)signal(SIGINT, SIG_DFL);
284856f23edSMike Heffner 	(void)sigemptyset(&eset);
285856f23edSMike Heffner 	(void)sigprocmask(SIG_SETMASK, &eset, NULL);
2869b50d902SRodney W. Grimes }
2879b50d902SRodney W. Grimes 
2889b50d902SRodney W. Grimes int
289b22a8699SPedro F. Giffuni wait_command(pid_t pid)
2909b50d902SRodney W. Grimes {
2919b50d902SRodney W. Grimes 
2929b50d902SRodney W. Grimes 	if (wait_child(pid) < 0) {
2939b50d902SRodney W. Grimes 		printf("Fatal error in process.\n");
2949ce73e90SMike Heffner 		return (-1);
2959b50d902SRodney W. Grimes 	}
2969ce73e90SMike Heffner 	return (0);
2979b50d902SRodney W. Grimes }
2989b50d902SRodney W. Grimes 
2999b50d902SRodney W. Grimes static struct child *
300b22a8699SPedro F. Giffuni findchild(pid_t pid, int dont_alloc)
3019b50d902SRodney W. Grimes {
3029ce73e90SMike Heffner 	struct child **cpp;
3039b50d902SRodney W. Grimes 
3049b50d902SRodney W. Grimes 	for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid;
3059b50d902SRodney W. Grimes 	    cpp = &(*cpp)->link)
3069b50d902SRodney W. Grimes 			;
3079b50d902SRodney W. Grimes 	if (*cpp == NULL) {
308b22a8699SPedro F. Giffuni 		if (dont_alloc)
309b22a8699SPedro F. Giffuni 			return(NULL);
310b22a8699SPedro F. Giffuni 		if (child_freelist) {
311b22a8699SPedro F. Giffuni 			*cpp = child_freelist;
312b22a8699SPedro F. Giffuni 			child_freelist = (*cpp)->link;
313b22a8699SPedro F. Giffuni 		} else {
3149ce73e90SMike Heffner 			*cpp = malloc(sizeof(struct child));
3150c3a8314SMike Heffner 			if (*cpp == NULL)
316b22a8699SPedro F. Giffuni 				err(1, "malloc");
317b22a8699SPedro F. Giffuni 		}
3189b50d902SRodney W. Grimes 		(*cpp)->pid = pid;
3199b50d902SRodney W. Grimes 		(*cpp)->done = (*cpp)->free = 0;
3209b50d902SRodney W. Grimes 		(*cpp)->link = NULL;
3219b50d902SRodney W. Grimes 	}
3229ce73e90SMike Heffner 	return (*cpp);
3239b50d902SRodney W. Grimes }
3249b50d902SRodney W. Grimes 
3259b50d902SRodney W. Grimes static void
3266d8484b0SPhilippe Charnier delchild(struct child *cp)
3279b50d902SRodney W. Grimes {
3289ce73e90SMike Heffner 	struct child **cpp;
3299b50d902SRodney W. Grimes 
3309b50d902SRodney W. Grimes 	for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link)
3319b50d902SRodney W. Grimes 		;
3329b50d902SRodney W. Grimes 	*cpp = cp->link;
333b22a8699SPedro F. Giffuni 	cp->link = child_freelist;
334b22a8699SPedro F. Giffuni 	child_freelist = cp;
3359b50d902SRodney W. Grimes }
3369b50d902SRodney W. Grimes 
3379ce73e90SMike Heffner /*ARGSUSED*/
3389b50d902SRodney W. Grimes void
3396d8484b0SPhilippe Charnier sigchild(int signo __unused)
3409b50d902SRodney W. Grimes {
341b22a8699SPedro F. Giffuni 	pid_t pid;
3420c3a8314SMike Heffner 	int status;
3439ce73e90SMike Heffner 	struct child *cp;
344b22a8699SPedro F. Giffuni 	int save_errno;
3459b50d902SRodney W. Grimes 
346b22a8699SPedro F. Giffuni 	save_errno = errno;
347ed74b69cSKevin Lo 	while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
348b22a8699SPedro F. Giffuni 		cp = findchild(pid, 1);
3491d1e1f63SXin LI 		if (cp == NULL)
3501d1e1f63SXin LI 			continue;
3519b50d902SRodney W. Grimes 		if (cp->free)
3529b50d902SRodney W. Grimes 			delchild(cp);
3539b50d902SRodney W. Grimes 		else {
3549b50d902SRodney W. Grimes 			cp->done = 1;
3559b50d902SRodney W. Grimes 			cp->status = status;
3569b50d902SRodney W. Grimes 		}
3579b50d902SRodney W. Grimes 	}
358b22a8699SPedro F. Giffuni 	errno = save_errno;
3599b50d902SRodney W. Grimes }
3609b50d902SRodney W. Grimes 
3610c3a8314SMike Heffner int wait_status;
3629b50d902SRodney W. Grimes 
3639b50d902SRodney W. Grimes /*
3649b50d902SRodney W. Grimes  * Wait for a specific child to die.
3659b50d902SRodney W. Grimes  */
3669b50d902SRodney W. Grimes int
367b22a8699SPedro F. Giffuni wait_child(pid_t pid)
3689b50d902SRodney W. Grimes {
36935f8ab70SEitan Adler 	struct child *cp;
37092fa728bSPedro F. Giffuni 	sigset_t nset, oset;
37192fa728bSPedro F. Giffuni 	pid_t rv = 0;
3729b50d902SRodney W. Grimes 
373856f23edSMike Heffner 	(void)sigemptyset(&nset);
374856f23edSMike Heffner 	(void)sigaddset(&nset, SIGCHLD);
375856f23edSMike Heffner 	(void)sigprocmask(SIG_BLOCK, &nset, &oset);
37692fa728bSPedro F. Giffuni 	/*
37792fa728bSPedro F. Giffuni 	 * If we have not already waited on the pid (via sigchild)
37892fa728bSPedro F. Giffuni 	 * wait on it now.  Otherwise, use the wait status stashed
37992fa728bSPedro F. Giffuni 	 * by sigchild.
38092fa728bSPedro F. Giffuni 	 */
381b22a8699SPedro F. Giffuni 	cp = findchild(pid, 1);
38292fa728bSPedro F. Giffuni 	if (cp == NULL || !cp->done)
38392fa728bSPedro F. Giffuni 		rv = waitpid(pid, &wait_status, 0);
38492fa728bSPedro F. Giffuni 	else
3859b50d902SRodney W. Grimes 		wait_status = cp->status;
38692fa728bSPedro F. Giffuni 	if (cp != NULL)
3879b50d902SRodney W. Grimes 		delchild(cp);
388856f23edSMike Heffner 	(void)sigprocmask(SIG_SETMASK, &oset, NULL);
38992fa728bSPedro F. Giffuni 	if (rv == -1 || (WIFEXITED(wait_status) && WEXITSTATUS(wait_status)))
39092fa728bSPedro F. Giffuni 		return -1;
39192fa728bSPedro F. Giffuni 	else
39292fa728bSPedro F. Giffuni 		return 0;
3939b50d902SRodney W. Grimes }
3949b50d902SRodney W. Grimes 
3959b50d902SRodney W. Grimes /*
3969b50d902SRodney W. Grimes  * Mark a child as don't care.
3979b50d902SRodney W. Grimes  */
3989b50d902SRodney W. Grimes void
399b22a8699SPedro F. Giffuni free_child(pid_t pid)
4009b50d902SRodney W. Grimes {
401b22a8699SPedro F. Giffuni 	struct child *cp;
402856f23edSMike Heffner 	sigset_t nset, oset;
4039b50d902SRodney W. Grimes 
404856f23edSMike Heffner 	(void)sigemptyset(&nset);
405856f23edSMike Heffner 	(void)sigaddset(&nset, SIGCHLD);
406856f23edSMike Heffner 	(void)sigprocmask(SIG_BLOCK, &nset, &oset);
407b22a8699SPedro F. Giffuni 	if ((cp = findchild(pid, 0)) != NULL) {
4089b50d902SRodney W. Grimes 		if (cp->done)
4099b50d902SRodney W. Grimes 			delchild(cp);
4109b50d902SRodney W. Grimes 		else
4119b50d902SRodney W. Grimes 			cp->free = 1;
412b22a8699SPedro F. Giffuni 	}
413856f23edSMike Heffner 	(void)sigprocmask(SIG_SETMASK, &oset, NULL);
4149b50d902SRodney W. Grimes }
415