1*5942983dSchristos /* $NetBSD: popen.c,v 1.27 2012/04/29 23:50:22 christos Exp $ */
288b833a7Schristos
361f28255Scgd /*
42cb5542fSderaadt * Copyright (c) 1980, 1993
52cb5542fSderaadt * The Regents of the University of California. All rights reserved.
661f28255Scgd *
761f28255Scgd * Redistribution and use in source and binary forms, with or without
861f28255Scgd * modification, are permitted provided that the following conditions
961f28255Scgd * are met:
1061f28255Scgd * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd * notice, this list of conditions and the following disclaimer.
1261f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd * notice, this list of conditions and the following disclaimer in the
1461f28255Scgd * documentation and/or other materials provided with the distribution.
1589aaa1bbSagc * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd * may be used to endorse or promote products derived from this software
1761f28255Scgd * without specific prior written permission.
1861f28255Scgd *
1961f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd * SUCH DAMAGE.
3061f28255Scgd */
3161f28255Scgd
327c81c8f3Slukem #include <sys/cdefs.h>
3361f28255Scgd #ifndef lint
3488b833a7Schristos #if 0
3588b833a7Schristos static char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 6/6/93";
3688b833a7Schristos #else
37*5942983dSchristos __RCSID("$NetBSD: popen.c,v 1.27 2012/04/29 23:50:22 christos Exp $");
3888b833a7Schristos #endif
3961f28255Scgd #endif /* not lint */
4061f28255Scgd
41c1587f4dSchristos #include <errno.h>
428207b28aSchristos #include <fcntl.h>
43c1587f4dSchristos #include <stdarg.h>
448207b28aSchristos #include <util.h>
458207b28aSchristos #include <sys/wait.h>
468207b28aSchristos
478207b28aSchristos #include "rcv.h"
482cb5542fSderaadt #include "extern.h"
49ca13337dSchristos #include "sig.h"
5061f28255Scgd
5161f28255Scgd #define READ 0
5261f28255Scgd #define WRITE 1
5361f28255Scgd
5461f28255Scgd struct fp {
5561f28255Scgd FILE *fp;
5661f28255Scgd int pipe;
57c1587f4dSchristos pid_t pid;
5861f28255Scgd struct fp *link;
5961f28255Scgd };
6061f28255Scgd static struct fp *fp_head;
6161f28255Scgd
622cb5542fSderaadt struct child {
63c1587f4dSchristos pid_t pid;
642cb5542fSderaadt char done;
652cb5542fSderaadt char free;
6628807559Schristos int status;
672cb5542fSderaadt struct child *link;
682cb5542fSderaadt };
69c1587f4dSchristos static struct child *child, *child_freelist = NULL;
70533d2abbSchristos static struct child *findchild(pid_t, int);
71c1587f4dSchristos
722cb5542fSderaadt
738207b28aSchristos #if 0 /* XXX - debugging stuff. This should go away eventually! */
748207b28aSchristos static void
758207b28aSchristos show_one_file(FILE *fo, struct fp *fpp)
768207b28aSchristos {
778207b28aSchristos (void)fprintf(fo, ">>> fp: %p, pipe: %d, pid: %d, link: %p\n",
788207b28aSchristos fpp->fp, fpp->pipe, fpp->pid, fpp->link);
798207b28aSchristos }
808207b28aSchristos
818207b28aSchristos void show_all_files(FILE *fo);
828207b28aSchristos __unused
83f3098750Schristos PUBLIC void
848207b28aSchristos show_all_files(FILE *fo)
858207b28aSchristos {
868207b28aSchristos struct fp *fpp;
878207b28aSchristos
888207b28aSchristos (void)fprintf(fo, ">> FILES\n");
898207b28aSchristos for (fpp = fp_head; fpp; fpp = fpp->link)
908207b28aSchristos show_one_file(fo, fpp);
918207b28aSchristos (void)fprintf(fo, ">> -------\n");
928207b28aSchristos (void)fflush(fo);
938207b28aSchristos }
94f3098750Schristos #endif /* end debugging stuff */
958207b28aSchristos
968207b28aSchristos
97f3098750Schristos static void
unregister_file(FILE * fp)98b127ccccSwiz unregister_file(FILE *fp)
9961f28255Scgd {
10061f28255Scgd struct fp **pp, *p;
10161f28255Scgd
10288b833a7Schristos for (pp = &fp_head; (p = *pp) != NULL; pp = &p->link)
10361f28255Scgd if (p->fp == fp) {
10461f28255Scgd *pp = p->link;
105c1587f4dSchristos (void)free(p);
10661f28255Scgd return;
10761f28255Scgd }
108533d2abbSchristos errx(EXIT_FAILURE, "Invalid file pointer");
1092cb5542fSderaadt }
1102cb5542fSderaadt
111f3098750Schristos PUBLIC void
register_file(FILE * fp,int pipefd,pid_t pid)112f3098750Schristos register_file(FILE *fp, int pipefd, pid_t pid)
1132cb5542fSderaadt {
114f3098750Schristos struct fp *fpp;
1152cb5542fSderaadt
1162283d346Schristos fpp = emalloc(sizeof(*fpp));
117f3098750Schristos fpp->fp = fp;
118f3098750Schristos fpp->pipe = pipefd;
119f3098750Schristos fpp->pid = pid;
120f3098750Schristos fpp->link = fp_head;
121f3098750Schristos fp_head = fpp;
122f3098750Schristos }
123f3098750Schristos
124f3098750Schristos PUBLIC FILE *
Fopen(const char * fn,const char * mode)125f3098750Schristos Fopen(const char *fn, const char *mode)
126f3098750Schristos {
127f3098750Schristos FILE *fp;
128f3098750Schristos
129*5942983dSchristos if ((fp = fopen(fn, mode)) != NULL)
130f3098750Schristos register_file(fp, 0, 0);
131f3098750Schristos return fp;
132f3098750Schristos }
133f3098750Schristos
134f3098750Schristos PUBLIC FILE *
Fdopen(int fd,const char * mode)135f3098750Schristos Fdopen(int fd, const char *mode)
136f3098750Schristos {
137f3098750Schristos FILE *fp;
138f3098750Schristos
139*5942983dSchristos if ((fp = fdopen(fd, mode)) != NULL)
140f3098750Schristos register_file(fp, 0, 0);
141f3098750Schristos return fp;
142f3098750Schristos }
143f3098750Schristos
144f3098750Schristos PUBLIC int
Fclose(FILE * fp)145f3098750Schristos Fclose(FILE *fp)
146f3098750Schristos {
147ca13337dSchristos
148ca13337dSchristos if (fp == NULL)
149ca13337dSchristos return 0;
150ca13337dSchristos
151f3098750Schristos unregister_file(fp);
152f3098750Schristos return fclose(fp);
153f3098750Schristos }
154f3098750Schristos
155f3098750Schristos PUBLIC void
prepare_child(sigset_t * nset,int infd,int outfd)156f3098750Schristos prepare_child(sigset_t *nset, int infd, int outfd)
157f3098750Schristos {
158f3098750Schristos int i;
159f3098750Schristos sigset_t eset;
160f3098750Schristos
161f3098750Schristos /*
162f3098750Schristos * All file descriptors other than 0, 1, and 2 are supposed to be
163f3098750Schristos * close-on-exec.
164f3098750Schristos */
165f3098750Schristos if (infd > 0) {
166f3098750Schristos (void)dup2(infd, 0);
167f3098750Schristos } else if (infd != 0) {
168f3098750Schristos /* we don't want the child stealing my stdin input */
169f3098750Schristos (void)close(0);
170f3098750Schristos (void)open(_PATH_DEVNULL, O_RDONLY, 0);
171f3098750Schristos }
172f3098750Schristos if (outfd >= 0 && outfd != 1)
173f3098750Schristos (void)dup2(outfd, 1);
174ca13337dSchristos
175f3098750Schristos if (nset != NULL) {
176ca13337dSchristos for (i = 1; i < NSIG; i++) {
177f3098750Schristos if (sigismember(nset, i))
178f3098750Schristos (void)signal(i, SIG_IGN);
179f3098750Schristos }
180ca13337dSchristos if (!sigismember(nset, SIGINT))
181f3098750Schristos (void)signal(SIGINT, SIG_DFL);
182f3098750Schristos (void)sigemptyset(&eset);
183f3098750Schristos (void)sigprocmask(SIG_SETMASK, &eset, NULL);
18461f28255Scgd }
185ca13337dSchristos }
18661f28255Scgd
18761f28255Scgd /*
18861f28255Scgd * Run a command without a shell, with optional arguments and splicing
189c1587f4dSchristos * of stdin (-1 means none) and stdout. The command name can be a sequence
190c1587f4dSchristos * of words.
19161f28255Scgd * Signals must be handled by the caller.
192c1587f4dSchristos * "nset" contains the signals to ignore in the new process.
193c1587f4dSchristos * SIGINT is enabled unless it's in "nset".
19461f28255Scgd */
195c1587f4dSchristos static pid_t
start_commandv(const char * cmd,sigset_t * nset,int infd,int outfd,va_list args)196ece0fd5cSchristos start_commandv(const char *cmd, sigset_t *nset, int infd, int outfd,
197ece0fd5cSchristos va_list args)
19861f28255Scgd {
199c1587f4dSchristos pid_t pid;
20061f28255Scgd
201ca13337dSchristos sig_check();
202c1587f4dSchristos if ((pid = fork()) < 0) {
203ae38aa87Swiz warn("fork");
20461f28255Scgd return -1;
20561f28255Scgd }
20661f28255Scgd if (pid == 0) {
20761f28255Scgd char *argv[100];
208ca13337dSchristos size_t i;
20961f28255Scgd
210ca13337dSchristos i = getrawlist(cmd, argv, (int)__arraycount(argv));
211ca13337dSchristos while (i < __arraycount(argv) - 1 &&
212ca13337dSchristos (argv[i++] = va_arg(args, char *)) != NULL)
213ca286310Schristos continue;
214ab850155Swiz argv[i] = NULL;
215c1587f4dSchristos prepare_child(nset, infd, outfd);
216ca286310Schristos (void)execvp(argv[0], argv);
217ae38aa87Swiz warn("%s", argv[0]);
21861f28255Scgd _exit(1);
21961f28255Scgd }
220533d2abbSchristos (void)findchild(pid, 0);
22161f28255Scgd return pid;
22261f28255Scgd }
22361f28255Scgd
224f3098750Schristos PUBLIC int
start_command(const char * cmd,sigset_t * nset,int infd,int outfd,...)225ece0fd5cSchristos start_command(const char *cmd, sigset_t *nset, int infd, int outfd, ...)
226c1587f4dSchristos {
227c1587f4dSchristos va_list args;
228c1587f4dSchristos int r;
229c1587f4dSchristos
230c1587f4dSchristos va_start(args, outfd);
231c1587f4dSchristos r = start_commandv(cmd, nset, infd, outfd, args);
232c1587f4dSchristos va_end(args);
233c1587f4dSchristos return r;
234c1587f4dSchristos }
235c1587f4dSchristos
236f3098750Schristos PUBLIC FILE *
Popen(const char * cmd,const char * mode)237f3098750Schristos Popen(const char *cmd, const char *mode)
23861f28255Scgd {
239f3098750Schristos int p[2];
240f3098750Schristos int myside, hisside, fd0, fd1;
241f3098750Schristos pid_t pid;
242f3098750Schristos sigset_t nset;
243f3098750Schristos FILE *fp;
244f3098750Schristos char *shellcmd;
24561f28255Scgd
246*5942983dSchristos if (pipe2(p, O_CLOEXEC) < 0)
247f3098750Schristos return NULL;
248f3098750Schristos if (*mode == 'r') {
249f3098750Schristos myside = p[READ];
250f3098750Schristos hisside = fd0 = fd1 = p[WRITE];
251f3098750Schristos } else {
252f3098750Schristos myside = p[WRITE];
253f3098750Schristos hisside = fd0 = p[READ];
254f3098750Schristos fd1 = -1;
255c1587f4dSchristos }
256f3098750Schristos (void)sigemptyset(&nset);
257f3098750Schristos if ((shellcmd = value(ENAME_SHELL)) == NULL)
258f3098750Schristos shellcmd = __UNCONST(_PATH_CSHELL);
259f3098750Schristos pid = start_command(shellcmd, &nset, fd0, fd1, "-c", cmd, NULL);
260f3098750Schristos if (pid < 0) {
261f3098750Schristos (void)close(p[READ]);
262f3098750Schristos (void)close(p[WRITE]);
263f3098750Schristos return NULL;
264c1587f4dSchristos }
265f3098750Schristos (void)close(hisside);
266f3098750Schristos if ((fp = fdopen(myside, mode)) != NULL)
267f3098750Schristos register_file(fp, 1, pid);
268f3098750Schristos return fp;
26961f28255Scgd }
27061f28255Scgd
2712cb5542fSderaadt static struct child *
findchild(pid_t pid,int dont_alloc)272c1587f4dSchristos findchild(pid_t pid, int dont_alloc)
27361f28255Scgd {
2747c81c8f3Slukem struct child **cpp;
27561f28255Scgd
27661f28255Scgd for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid;
27761f28255Scgd cpp = &(*cpp)->link)
2788207b28aSchristos continue;
27961f28255Scgd if (*cpp == NULL) {
280c1587f4dSchristos if (dont_alloc)
281c1587f4dSchristos return NULL;
282c1587f4dSchristos if (child_freelist) {
283c1587f4dSchristos *cpp = child_freelist;
284c1587f4dSchristos child_freelist = (*cpp)->link;
2858207b28aSchristos } else
286349d9781Schristos *cpp = emalloc(sizeof(**cpp));
2878207b28aSchristos
28861f28255Scgd (*cpp)->pid = pid;
28961f28255Scgd (*cpp)->done = (*cpp)->free = 0;
29061f28255Scgd (*cpp)->link = NULL;
29161f28255Scgd }
29261f28255Scgd return *cpp;
29361f28255Scgd }
29461f28255Scgd
2952cb5542fSderaadt static void
delchild(struct child * cp)296b127ccccSwiz delchild(struct child *cp)
29761f28255Scgd {
2987c81c8f3Slukem struct child **cpp;
29961f28255Scgd
30061f28255Scgd for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link)
3018207b28aSchristos continue;
30261f28255Scgd *cpp = cp->link;
303c1587f4dSchristos cp->link = child_freelist;
304c1587f4dSchristos child_freelist = cp;
30561f28255Scgd }
30661f28255Scgd
30761f28255Scgd /*
30861f28255Scgd * Wait for a specific child to die.
30961f28255Scgd */
310f3098750Schristos PUBLIC int
wait_child(pid_t pid)311c1587f4dSchristos wait_child(pid_t pid)
31261f28255Scgd {
31302b57cf8Sperry struct child *cp;
314c1587f4dSchristos sigset_t nset, oset;
315c1587f4dSchristos pid_t rv = 0;
316c1587f4dSchristos
317ca286310Schristos (void)sigemptyset(&nset);
318ca286310Schristos (void)sigaddset(&nset, SIGCHLD);
319ca286310Schristos (void)sigprocmask(SIG_BLOCK, &nset, &oset);
320c1587f4dSchristos /*
321c1587f4dSchristos * If we have not already waited on the pid (via sigchild)
322c1587f4dSchristos * wait on it now. Otherwise, use the wait status stashed
323c1587f4dSchristos * by sigchild.
324c1587f4dSchristos */
325c1587f4dSchristos cp = findchild(pid, 1);
326c1587f4dSchristos if (cp == NULL || !cp->done)
327c1587f4dSchristos rv = waitpid(pid, &wait_status, 0);
328c1587f4dSchristos else
32961f28255Scgd wait_status = cp->status;
330c1587f4dSchristos if (cp != NULL)
33161f28255Scgd delchild(cp);
332ca286310Schristos (void)sigprocmask(SIG_SETMASK, &oset, NULL);
333c1587f4dSchristos if (rv == -1 || (WIFEXITED(wait_status) && WEXITSTATUS(wait_status)))
334c1587f4dSchristos return -1;
335c1587f4dSchristos else
336c1587f4dSchristos return 0;
33761f28255Scgd }
33861f28255Scgd
339f3098750Schristos static pid_t
file_pid(FILE * fp)340f3098750Schristos file_pid(FILE *fp)
341f3098750Schristos {
342f3098750Schristos struct fp *p;
343f3098750Schristos
344f3098750Schristos for (p = fp_head; p; p = p->link)
345f3098750Schristos if (p->fp == fp)
346f3098750Schristos return p->pid;
347533d2abbSchristos errx(EXIT_FAILURE, "Invalid file pointer");
348f3098750Schristos /*NOTREACHED*/
349f3098750Schristos }
350f3098750Schristos
351f3098750Schristos PUBLIC int
Pclose(FILE * ptr)352f3098750Schristos Pclose(FILE *ptr)
353f3098750Schristos {
354f3098750Schristos int i;
355f3098750Schristos sigset_t nset, oset;
356f3098750Schristos
357ca13337dSchristos if (ptr == NULL)
358ca13337dSchristos return 0;
359ca13337dSchristos
360f3098750Schristos i = file_pid(ptr);
361f3098750Schristos unregister_file(ptr);
362f3098750Schristos (void)fclose(ptr);
363f3098750Schristos (void)sigemptyset(&nset);
364f3098750Schristos (void)sigaddset(&nset, SIGINT);
365f3098750Schristos (void)sigaddset(&nset, SIGHUP);
366f3098750Schristos (void)sigprocmask(SIG_BLOCK, &nset, &oset);
367f3098750Schristos i = wait_child(i);
368f3098750Schristos (void)sigprocmask(SIG_SETMASK, &oset, NULL);
369f3098750Schristos return i;
370f3098750Schristos }
371f3098750Schristos
372f3098750Schristos PUBLIC void
close_all_files(void)373f3098750Schristos close_all_files(void)
374f3098750Schristos {
375f3098750Schristos while (fp_head)
376f3098750Schristos if (fp_head->pipe)
377f3098750Schristos (void)Pclose(fp_head->fp);
378f3098750Schristos else
379f3098750Schristos (void)Fclose(fp_head->fp);
380f3098750Schristos }
381f3098750Schristos
382f3098750Schristos PUBLIC FILE *
last_registered_file(int last_pipe)383f3098750Schristos last_registered_file(int last_pipe)
384f3098750Schristos {
385f3098750Schristos struct fp *fpp;
386f3098750Schristos
387f3098750Schristos if (last_pipe == 0)
388f3098750Schristos return fp_head ? fp_head->fp : NULL;
389f3098750Schristos
390f3098750Schristos for (fpp = fp_head; fpp; fpp = fpp->link)
391f3098750Schristos if (fpp->pipe)
392f3098750Schristos return fpp->fp;
393f3098750Schristos return NULL;
394f3098750Schristos }
395f3098750Schristos
396f3098750Schristos PUBLIC void
close_top_files(FILE * fp_stop)397f3098750Schristos close_top_files(FILE *fp_stop)
398f3098750Schristos {
399f3098750Schristos while (fp_head && fp_head->fp != fp_stop)
400f3098750Schristos if (fp_head->pipe)
401f3098750Schristos (void)Pclose(fp_head->fp);
402f3098750Schristos else
403f3098750Schristos (void)Fclose(fp_head->fp);
404f3098750Schristos }
405f3098750Schristos
406f3098750Schristos #ifdef MIME_SUPPORT
407f3098750Schristos PUBLIC void
flush_files(FILE * fo,int only_pipes)408f3098750Schristos flush_files(FILE *fo, int only_pipes)
409f3098750Schristos {
410f3098750Schristos struct fp *fpp;
411f3098750Schristos
412f3098750Schristos if (fo)
413f3098750Schristos (void)fflush(fo);
414f3098750Schristos
415f3098750Schristos for (fpp = fp_head; fpp; fpp = fpp->link)
416f3098750Schristos if (!only_pipes || fpp->pipe)
417f3098750Schristos (void)fflush(fpp->fp);
418f3098750Schristos
419f3098750Schristos (void)fflush(stdout);
420f3098750Schristos }
421f3098750Schristos #endif /* MIME_SUPPORT */
422f3098750Schristos
423f3098750Schristos static int
wait_command(pid_t pid)424f3098750Schristos wait_command(pid_t pid)
425f3098750Schristos {
426f3098750Schristos
427f3098750Schristos if (wait_child(pid) < 0) {
428f3098750Schristos (void)puts("Fatal error in process.");
429f3098750Schristos return -1;
430f3098750Schristos }
431f3098750Schristos return 0;
432f3098750Schristos }
433f3098750Schristos
434f3098750Schristos PUBLIC int
run_command(const char * cmd,sigset_t * nset,int infd,int outfd,...)435f3098750Schristos run_command(const char *cmd, sigset_t *nset, int infd, int outfd, ...)
436f3098750Schristos {
437f3098750Schristos pid_t pid;
438f3098750Schristos va_list args;
439ca13337dSchristos int rval;
440f3098750Schristos
441ca13337dSchristos #ifdef BROKEN_EXEC_TTY_RESTORE
442ca13337dSchristos struct termios ttybuf;
443ca13337dSchristos int tcrval;
444ca13337dSchristos /*
445ca13337dSchristos * XXX - grab the tty settings as currently they can get
446ca13337dSchristos * trashed by emacs-21 when suspending with bash-3.2.25 as the
447ca13337dSchristos * shell.
448ca13337dSchristos *
449ca13337dSchristos * 1) from the mail editor, start "emacs -nw" (21.4)
450ca13337dSchristos * 2) suspend emacs to the shell (bash 3.2.25)
451ca13337dSchristos * 3) resume emacs
452ca13337dSchristos * 4) exit emacs back to the mail editor
453ca13337dSchristos * 5) discover the tty is screwed: the mail editor is no
454ca13337dSchristos * longer receiving characters
455ca13337dSchristos *
456ca13337dSchristos * - This occurs on both i386 and amd64.
457ca13337dSchristos * - This did _NOT_ occur before 4.99.10.
458ca13337dSchristos * - This does _NOT_ occur if the editor is vi(1) or if the shell
459ca13337dSchristos * is /bin/sh.
460ca13337dSchristos * - This _DOES_ happen with the old mail(1) from 2006-01-01 (long
461ca13337dSchristos * before my changes).
462ca13337dSchristos *
463ca13337dSchristos * This is the commit that introduced this "feature":
464ca13337dSchristos * http://mail-index.netbsd.org/source-changes/2007/02/09/0020.html
465ca13337dSchristos */
466ca13337dSchristos if ((tcrval = tcgetattr(fileno(stdin), &ttybuf)) == -1)
467ca13337dSchristos warn("tcgetattr");
468ca13337dSchristos #endif
469f3098750Schristos va_start(args, outfd);
470f3098750Schristos pid = start_commandv(cmd, nset, infd, outfd, args);
471f3098750Schristos va_end(args);
472f3098750Schristos if (pid < 0)
473f3098750Schristos return -1;
474ca13337dSchristos rval = wait_command(pid);
475ca13337dSchristos #ifdef BROKEN_EXEC_TTY_RESTORE
476ca13337dSchristos if (tcrval != -1 && tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf) == -1)
477ca13337dSchristos warn("tcsetattr");
478ca13337dSchristos #endif
479ca13337dSchristos return rval;
480ca13337dSchristos
481f3098750Schristos }
482f3098750Schristos
483f3098750Schristos /*ARGSUSED*/
484f3098750Schristos PUBLIC void
sigchild(int signo __unused)485f3098750Schristos sigchild(int signo __unused)
486f3098750Schristos {
487f3098750Schristos pid_t pid;
488f3098750Schristos int status;
489f3098750Schristos struct child *cp;
490ca13337dSchristos int save_errno;
491f3098750Schristos
492ca13337dSchristos save_errno = errno;
493ca13337dSchristos while ((pid = waitpid((pid_t)-1, &status, WNOHANG)) > 0) {
494ca13337dSchristos cp = findchild(pid, 1); /* async-signal-safe: we don't alloc */
495f3098750Schristos if (!cp)
496f3098750Schristos continue;
497f3098750Schristos if (cp->free)
498ca13337dSchristos delchild(cp); /* async-signal-safe: list changes */
499f3098750Schristos else {
500f3098750Schristos cp->done = 1;
501f3098750Schristos cp->status = status;
502f3098750Schristos }
503f3098750Schristos }
504f3098750Schristos errno = save_errno;
505f3098750Schristos }
506f3098750Schristos
50761f28255Scgd /*
50861f28255Scgd * Mark a child as don't care.
50961f28255Scgd */
510f3098750Schristos PUBLIC void
free_child(pid_t pid)511c1587f4dSchristos free_child(pid_t pid)
51261f28255Scgd {
51302b57cf8Sperry struct child *cp;
514c1587f4dSchristos sigset_t nset, oset;
515c1587f4dSchristos
516ca286310Schristos (void)sigemptyset(&nset);
517ca286310Schristos (void)sigaddset(&nset, SIGCHLD);
518ca286310Schristos (void)sigprocmask(SIG_BLOCK, &nset, &oset);
519c1587f4dSchristos if ((cp = findchild(pid, 0)) != NULL) {
52061f28255Scgd if (cp->done)
52161f28255Scgd delchild(cp);
52261f28255Scgd else
52361f28255Scgd cp->free = 1;
524c1587f4dSchristos }
525ca286310Schristos (void)sigprocmask(SIG_SETMASK, &oset, NULL);
52661f28255Scgd }
527