NEWS: update to correct false STD I/O statement
[s-mailx.git] / popen.c
blob3d48f20a32f220e2f879a07a9600642aee641e9d
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Handling of pipes, child processes, temporary files, file enwrapping.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2014 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
6 */
7 /*
8 * Copyright (c) 1980, 1993
9 * The Regents of the University of California. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
40 #ifndef HAVE_AMALGAMATION
41 # include "nail.h"
42 #endif
44 #include <sys/wait.h>
46 #include <fcntl.h>
48 #define READ 0
49 #define WRITE 1
51 #ifndef O_CLOEXEC
52 # define _OUR_CLOEXEC
53 # define O_CLOEXEC 0
54 # define _SET_CLOEXEC(FD) do fcntl((FD), F_SETFD, FD_CLOEXEC); while (0)
55 #else
56 # define _SET_CLOEXEC(FD) do {} while (0)
57 #endif
59 struct fp {
60 FILE *fp;
61 struct fp *link;
62 char *realfile;
63 long offset;
64 int omode;
65 int pipe;
66 int pid;
67 enum {
68 FP_RAW = 0,
69 FP_GZIP = 1<<0,
70 FP_XZ = 1<<1,
71 FP_BZIP2 = 1<<2,
72 FP_IMAP = 1<<3,
73 FP_MAILDIR = 1<<4,
74 FP_MASK = (1<<5) - 1,
75 FP_READONLY = 1<<5
76 } compressed;
79 struct child {
80 int pid;
81 char done;
82 char free;
83 int status;
84 struct child *link;
87 static struct fp *fp_head;
88 static struct child *_popen_child;
90 static int scan_mode(char const *mode, int *omode);
91 static void register_file(FILE *fp, int omode, int ispipe, int pid,
92 int compressed, char const *realfile, long offset);
93 static enum okay _compress(struct fp *fpp);
94 static int _decompress(int compression, int infd, int outfd);
95 static enum okay unregister_file(FILE *fp);
96 static int file_pid(FILE *fp);
98 /* Handle SIGCHLD */
99 static void _sigchld(int signo);
101 static int wait_command(int pid);
102 static struct child *findchild(int pid);
103 static void delchild(struct child *cp);
105 static int
106 scan_mode(char const *mode, int *omode)
108 static struct {
109 char const mode[4];
110 int omode;
111 } const maps[] = {
112 {"r", O_RDONLY},
113 {"w", O_WRONLY | O_CREAT | O_TRUNC},
114 {"wx", O_WRONLY | O_CREAT | O_EXCL},
115 {"a", O_WRONLY | O_APPEND | O_CREAT},
116 {"a+", O_RDWR | O_APPEND},
117 {"r+", O_RDWR},
118 {"w+", O_RDWR | O_CREAT | O_EXCL}
121 int i;
122 NYD_ENTER;
124 for (i = 0; UICMP(z, i, <, NELEM(maps)); ++i)
125 if (!strcmp(maps[i].mode, mode)) {
126 *omode = maps[i].omode;
127 i = 0;
128 goto jleave;
131 alert(tr(152, "Internal error: bad stdio open mode %s\n"), mode);
132 errno = EINVAL;
133 *omode = 0; /* (silence CC) */
134 i = -1;
135 jleave:
136 NYD_LEAVE;
137 return i;
140 static void
141 register_file(FILE *fp, int omode, int ispipe, int pid, int compressed,
142 char const *realfile, long offset)
144 struct fp *fpp;
145 NYD_ENTER;
147 fpp = smalloc(sizeof *fpp);
148 fpp->fp = fp;
149 fpp->omode = omode;
150 fpp->pipe = ispipe;
151 fpp->pid = pid;
152 fpp->link = fp_head;
153 fpp->compressed = compressed;
154 fpp->realfile = (realfile != NULL) ? sstrdup(realfile) : NULL;
155 fpp->offset = offset;
156 fp_head = fpp;
157 NYD_LEAVE;
160 static enum okay
161 _compress(struct fp *fpp)
163 char const *cmd[2];
164 int outfd;
165 enum okay rv;
166 NYD_ENTER;
168 if (fpp->omode == O_RDONLY) {
169 rv = OKAY;
170 goto jleave;
172 rv = STOP;
174 fflush(fpp->fp);
175 clearerr(fpp->fp);
176 if (fseek(fpp->fp, fpp->offset, SEEK_SET) == -1)
177 goto jleave;
179 #ifdef HAVE_IMAP
180 if ((fpp->compressed & FP_MASK) == FP_IMAP) {
181 rv = imap_append(fpp->realfile, fpp->fp);
182 goto jleave;
184 #endif
185 if ((fpp->compressed & FP_MASK) == FP_MAILDIR) {
186 rv = maildir_append(fpp->realfile, fpp->fp);
187 goto jleave;
190 outfd = open(fpp->realfile, (fpp->omode | O_CREAT) & ~O_EXCL, 0666);
191 if (outfd == -1) {
192 fprintf(stderr, "Fatal: cannot create ");
193 perror(fpp->realfile);
194 goto jleave;
196 if (!(fpp->omode & O_APPEND))
197 ftruncate(outfd, 0);
198 switch (fpp->compressed & FP_MASK) {
199 case FP_GZIP:
200 cmd[0] = "gzip"; cmd[1] = "-c"; break;
201 case FP_BZIP2:
202 cmd[0] = "bzip2"; cmd[1] = "-c"; break;
203 case FP_XZ:
204 cmd[0] = "xz"; cmd[1] = "-c"; break;
205 default:
206 cmd[0] = "cat"; cmd[1] = NULL; break;
208 if (run_command(cmd[0], 0, fileno(fpp->fp), outfd, cmd[1], NULL, NULL) >= 0)
209 rv = OKAY;
210 close(outfd);
211 jleave:
212 NYD_LEAVE;
213 return rv;
216 static int
217 _decompress(int compression, int infd, int outfd)
219 char const *cmd[2];
220 int rv;
221 NYD_ENTER;
223 switch (compression & FP_MASK) {
224 case FP_GZIP: cmd[0] = "gzip"; cmd[1] = "-cd"; break;
225 case FP_BZIP2: cmd[0] = "bzip2"; cmd[1] = "-cd"; break;
226 case FP_XZ: cmd[0] = "xz"; cmd[1] = "-cd"; break;
227 default: cmd[0] = "cat"; cmd[1] = NULL; break;
228 case FP_IMAP:
229 case FP_MAILDIR:
230 rv = 0;
231 goto jleave;
233 rv = run_command(cmd[0], 0, infd, outfd, cmd[1], NULL, NULL);
234 jleave:
235 NYD_LEAVE;
236 return rv;
239 static enum okay
240 unregister_file(FILE *fp)
242 struct fp **pp, *p;
243 enum okay rv = OKAY;
244 NYD_ENTER;
246 for (pp = &fp_head; (p = *pp) != NULL; pp = &p->link)
247 if (p->fp == fp) {
248 if ((p->compressed & FP_MASK) != FP_RAW) /* TODO ;} */
249 rv = _compress(p);
250 *pp = p->link;
251 free(p);
252 goto jleave;
254 #ifdef HAVE_DEBUG
255 panic
256 #else
257 alert
258 #endif
259 (tr(153, "Invalid file pointer"));
260 rv = STOP;
261 jleave:
262 NYD_LEAVE;
263 return rv;
266 static int
267 file_pid(FILE *fp)
269 int rv;
270 struct fp *p;
271 NYD_ENTER;
273 rv = -1;
274 for (p = fp_head; p; p = p->link)
275 if (p->fp == fp) {
276 rv = p->pid;
277 break;
279 NYD_LEAVE;
280 return rv;
283 static void
284 _sigchld(int signo)
286 int pid, status;
287 struct child *cp;
288 NYD_X; /* Signal handler */
289 UNUSED(signo);
291 for (;;) {
292 pid = (int)waitpid((pid_t)-1, &status, WNOHANG);
293 if (pid <= 0) {
294 if (pid == -1 && errno == EINTR)
295 continue;
296 break;
298 cp = findchild(pid);
299 if (cp->free)
300 delchild(cp);
301 else {
302 cp->done = 1;
303 cp->status = status;
308 static int
309 wait_command(int pid)
311 int rv = 0;
312 NYD_ENTER;
314 if (!wait_child(pid, NULL)) {
315 if (ok_blook(bsdcompat) || ok_blook(bsdmsgs))
316 fprintf(stderr, tr(154, "Fatal error in process.\n"));
317 rv = -1;
319 NYD_LEAVE;
320 return rv;
323 static struct child *
324 findchild(int pid)
326 struct child **cpp;
327 NYD_ENTER;
329 for (cpp = &_popen_child; *cpp != NULL && (*cpp)->pid != pid;
330 cpp = &(*cpp)->link)
332 if (*cpp == NULL) {
333 *cpp = smalloc(sizeof **cpp);
334 (*cpp)->pid = pid;
335 (*cpp)->done = (*cpp)->free = 0;
336 (*cpp)->link = NULL;
338 NYD_LEAVE;
339 return *cpp;
342 static void
343 delchild(struct child *cp)
345 struct child **cpp;
346 NYD_ENTER;
348 for (cpp = &_popen_child; *cpp != cp; cpp = &(*cpp)->link)
350 *cpp = cp->link;
351 free(cp);
352 NYD_LEAVE;
355 FL void
356 command_manager_start(void)
358 struct sigaction nact, oact;
359 NYD_ENTER;
361 nact.sa_handler = &_sigchld;
362 sigemptyset(&nact.sa_mask);
363 nact.sa_flags = 0
364 #ifdef SA_RESTART
365 | SA_RESTART
366 #endif
367 #ifdef SA_NOCLDSTOP
368 | SA_NOCLDSTOP
369 #endif
371 if (sigaction(SIGCHLD, &nact, &oact) != 0)
372 panic("Cannot install signal handler for child process management");
373 NYD_LEAVE;
376 FL FILE *
377 safe_fopen(char const *file, char const *oflags, int *xflags)
379 int osflags, fd;
380 FILE *fp = NULL;
381 NYD_ENTER;
383 if (scan_mode(oflags, &osflags) < 0)
384 goto jleave;
385 osflags |= O_CLOEXEC;
386 if (xflags != NULL)
387 *xflags = osflags;
389 if ((fd = open(file, osflags, 0666)) == -1)
390 goto jleave;
391 _SET_CLOEXEC(fd);
393 fp = fdopen(fd, oflags);
394 jleave:
395 NYD_LEAVE;
396 return fp;
399 FL FILE *
400 Fopen(char const *file, char const *oflags)
402 FILE *fp;
403 int osflags;
404 NYD_ENTER;
406 if ((fp = safe_fopen(file, oflags, &osflags)) != NULL)
407 register_file(fp, osflags, 0, 0, FP_RAW, NULL, 0L);
408 NYD_LEAVE;
409 return fp;
412 FL FILE *
413 Fdopen(int fd, char const *oflags)
415 FILE *fp;
416 int osflags;
417 NYD_ENTER;
419 scan_mode(oflags, &osflags);
420 osflags |= O_CLOEXEC;
422 if ((fp = fdopen(fd, oflags)) != NULL)
423 register_file(fp, osflags, 0, 0, FP_RAW, NULL, 0L);
424 NYD_LEAVE;
425 return fp;
428 FL int
429 Fclose(FILE *fp)
431 int i = 0;
432 NYD_ENTER;
434 if (unregister_file(fp) == OKAY)
435 i |= 1;
436 if (fclose(fp) == 0)
437 i |= 2;
438 NYD_LEAVE;
439 return (i == 3 ? 0 : EOF);
442 FL FILE *
443 Zopen(char const *file, char const *oflags, int *compression) /* FIXME MESS! */
445 FILE *rv = NULL;
446 int _compression, osflags, mode, infd;
447 enum oflags rof;
448 long offset;
449 enum protocol p;
450 NYD_ENTER;
452 if (compression == NULL)
453 compression = &_compression;
455 if (scan_mode(oflags, &osflags) < 0)
456 goto jleave;
457 rof = OF_RDWR | OF_UNLINK;
458 if (osflags & O_APPEND)
459 rof |= OF_APPEND;
460 if (osflags == O_RDONLY) {
461 mode = R_OK;
462 *compression = FP_READONLY;
463 } else {
464 mode = R_OK | W_OK;
465 *compression = 0;
468 /* TODO ???? */
469 if ((osflags & O_APPEND) && ((p = which_protocol(file)) == PROTO_IMAP ||
470 p == PROTO_MAILDIR)) {
471 *compression |= (p == PROTO_IMAP) ? FP_IMAP : FP_MAILDIR;
472 osflags = O_RDWR | O_APPEND | O_CREAT;
473 infd = -1;
474 } else {
475 char const *ext;
477 if ((ext = strrchr(file, '.')) != NULL) {
478 if (!strcmp(ext, ".gz"))
479 *compression |= FP_GZIP;
480 else if (!strcmp(ext, ".xz"))
481 *compression |= FP_XZ;
482 else if (!strcmp(ext, ".bz2"))
483 *compression |= FP_BZIP2;
484 else
485 goto jraw;
486 } else {
487 jraw:
488 *compression |= FP_RAW;
489 rv = Fopen(file, oflags);
490 goto jleave;
492 if ((infd = open(file, (mode & W_OK) ? O_RDWR : O_RDONLY)) == -1 &&
493 (!(osflags & O_CREAT) || errno != ENOENT))
494 goto jleave;
497 if ((rv = Ftmp(NULL, "zopen", rof, 0600)) == NULL) {
498 perror(tr(167, "tmpfile"));
499 goto jerr;
501 if (infd >= 0 || (*compression & FP_MASK) == FP_IMAP ||
502 (*compression & FP_MASK) == FP_MAILDIR) {
503 if (_decompress(*compression, infd, fileno(rv)) < 0) {
504 jerr:
505 if (rv != NULL)
506 Fclose(rv);
507 rv = NULL;
508 if (infd >= 0)
509 close(infd);
510 goto jleave;
512 } else {
513 if ((infd = creat(file, 0666)) == -1) {
514 Fclose(rv);
515 rv = NULL;
516 goto jleave;
519 if (infd >= 0)
520 close(infd);
521 fflush(rv);
523 if (!(osflags & O_APPEND))
524 rewind(rv);
525 if ((offset = ftell(rv)) == -1) {
526 Fclose(rv);
527 rv = NULL;
528 goto jleave;
530 register_file(rv, osflags, 0, 0, *compression, file, offset);
531 jleave:
532 NYD_LEAVE;
533 return rv;
536 FL FILE *
537 Ftmp(char **fn, char const *prefix, enum oflags oflags, int mode)
539 FILE *fp = NULL;
540 char *cp_base, *cp;
541 int fd;
542 NYD_ENTER;
544 cp_base =
545 cp = smalloc(strlen(tempdir) + 1 + sizeof("mail") + strlen(prefix) + 7 +1);
546 cp = sstpcpy(cp, tempdir);
547 *cp++ = '/';
548 cp = sstpcpy(cp, "mail");
549 if (*prefix) {
550 *cp++ = '-';
551 cp = sstpcpy(cp, prefix);
553 /* TODO Ftmp(): unroll our own creation loop with atoi(random()) */
554 sstpcpy(cp, ".XXXXXX");
556 hold_all_sigs();
557 #ifdef HAVE_MKSTEMP
558 if ((fd = mkstemp(cp_base)) == -1)
559 goto jfree;
560 if (mode != (S_IRUSR | S_IWUSR) && fchmod(fd, mode) == -1)
561 goto jclose;
562 if (oflags & OF_APPEND) {
563 int f;
565 if ((f = fcntl(fd, F_GETFL)) == -1 ||
566 fcntl(fd, F_SETFL, f | O_APPEND) == -1) {
567 jclose:
568 close(fd);
569 goto junlink;
572 if (!(oflags & OF_REGISTER))
573 fcntl(fd, F_SETFD, FD_CLOEXEC);
574 #else
575 if (mktemp(cp_base) == NULL)
576 goto jfree;
577 if ((fd = open(cp_base, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC |
578 (oflags & OF_APPEND ? O_APPEND : 0), mode)) == -1)
579 goto junlink;
580 if (!(oflags & OF_REGISTER))
581 _SET_CLOEXEC(fd);
582 #endif
584 fp = (*((oflags & OF_REGISTER) ? &Fdopen : &fdopen))(fd,
585 (oflags & OF_RDWR ? "w+" : "w"));
586 if (fp == NULL || (oflags & OF_UNLINK)) {
587 junlink:
588 unlink(cp_base);
589 goto jfree;
592 if (fn != NULL)
593 *fn = cp_base;
594 jleave:
595 if (fp == NULL || !(oflags & OF_HOLDSIGS))
596 rele_all_sigs();
597 NYD_LEAVE;
598 return fp;
599 jfree:
600 if ((cp = cp_base) != NULL)
601 free(cp);
602 goto jleave;
605 FL void
606 Ftmp_release(char **fn)
608 char *cp;
609 NYD_ENTER;
611 cp = *fn;
612 *fn = NULL;
613 if (cp != NULL) {
614 unlink(cp);
615 rele_all_sigs();
616 free(cp);
618 NYD_LEAVE;
621 FL void
622 Ftmp_free(char **fn)
624 char *cp;
625 NYD_ENTER;
627 cp = *fn;
628 *fn = NULL;
629 if (cp != NULL)
630 free(cp);
631 NYD_LEAVE;
634 FL bool_t
635 pipe_cloexec(int fd[2])
637 bool_t rv = FAL0;
638 NYD_ENTER;
640 #ifdef HAVE_PIPE2
641 if (pipe2(fd, O_CLOEXEC) == -1)
642 goto jleave;
643 #else
644 if (pipe(fd) == -1)
645 goto jleave;
646 fcntl(fd[0], F_SETFD, FD_CLOEXEC);
647 fcntl(fd[1], F_SETFD, FD_CLOEXEC);
648 #endif
649 rv = TRU1;
650 jleave:
651 NYD_LEAVE;
652 return rv;
655 FL FILE *
656 Popen(char const *cmd, char const *mode, char const *sh, int newfd1)
658 int p[2], myside, hisside, fd0, fd1, pid;
659 char mod[2] = {'0', '\0'};
660 sigset_t nset;
661 FILE *rv = NULL;
662 NYD_ENTER;
664 if (!pipe_cloexec(p))
665 goto jleave;
667 if (*mode == 'r') {
668 myside = p[READ];
669 fd0 = -1;
670 hisside = fd1 = p[WRITE];
671 mod[0] = *mode;
672 } else if (*mode == 'W') {
673 myside = p[WRITE];
674 hisside = fd0 = p[READ];
675 fd1 = newfd1;
676 mod[0] = 'w';
677 } else {
678 myside = p[WRITE];
679 hisside = fd0 = p[READ];
680 fd1 = -1;
681 mod[0] = 'w';
683 sigemptyset(&nset);
684 if (sh == NULL) {
685 pid = start_command(cmd, &nset, fd0, fd1, NULL, NULL, NULL);
686 } else {
687 pid = start_command(sh, &nset, fd0, fd1, "-c", cmd, NULL);
689 if (pid < 0) {
690 close(p[READ]);
691 close(p[WRITE]);
692 goto jleave;
694 close(hisside);
695 if ((rv = fdopen(myside, mod)) != NULL)
696 register_file(rv, 0, 1, pid, FP_RAW, NULL, 0L);
697 jleave:
698 NYD_LEAVE;
699 return rv;
702 FL bool_t
703 Pclose(FILE *ptr, bool_t dowait)
705 sigset_t nset, oset;
706 int pid;
707 bool_t rv = FAL0;
708 NYD_ENTER;
710 pid = file_pid(ptr);
711 if (pid < 0)
712 goto jleave;
713 unregister_file(ptr);
714 fclose(ptr);
715 if (dowait) {
716 sigemptyset(&nset);
717 sigaddset(&nset, SIGINT);
718 sigaddset(&nset, SIGHUP);
719 sigprocmask(SIG_BLOCK, &nset, &oset);
720 rv = wait_child(pid, NULL);
721 sigprocmask(SIG_SETMASK, &oset, NULL);
722 } else {
723 free_child(pid);
724 rv = TRU1;
726 jleave:
727 NYD_LEAVE;
728 return rv;
731 FL void
732 close_all_files(void)
734 NYD_ENTER;
735 while (fp_head != NULL)
736 if (fp_head->pipe)
737 Pclose(fp_head->fp, TRU1);
738 else
739 Fclose(fp_head->fp);
740 NYD_LEAVE;
743 FL int
744 run_command(char const *cmd, sigset_t *mask, int infd, int outfd,
745 char const *a0, char const *a1, char const *a2)
747 int rv;
748 NYD_ENTER;
750 if ((rv = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0)
751 rv = -1;
752 else
753 rv = wait_command(rv);
754 NYD_LEAVE;
755 return rv;
758 FL int
759 start_command(char const *cmd, sigset_t *mask, int infd, int outfd,
760 char const *a0, char const *a1, char const *a2)
762 int rv;
763 NYD_ENTER;
765 if ((rv = fork()) == -1) {
766 perror("fork");
767 rv = -1;
768 } else if (rv == 0) {
769 char *argv[100];
770 int i = getrawlist(cmd, strlen(cmd), argv, NELEM(argv), 0);
772 if ((argv[i++] = UNCONST(a0)) != NULL &&
773 (argv[i++] = UNCONST(a1)) != NULL &&
774 (argv[i++] = UNCONST(a2)) != NULL)
775 argv[i] = NULL;
776 prepare_child(mask, infd, outfd);
777 execvp(argv[0], argv);
778 perror(argv[0]);
779 _exit(1);
781 NYD_LEAVE;
782 return rv;
785 FL void
786 prepare_child(sigset_t *nset, int infd, int outfd)
788 int i;
789 sigset_t fset;
790 NYD_ENTER;
792 /* All file descriptors other than 0, 1, and 2 are supposed to be cloexec */
793 if (infd >= 0)
794 dup2(infd, 0);
795 if (outfd >= 0)
796 dup2(outfd, 1);
798 if (nset) {
799 for (i = 1; i < NSIG; ++i)
800 if (sigismember(nset, i))
801 safe_signal(i, SIG_IGN);
802 if (!sigismember(nset, SIGINT))
803 safe_signal(SIGINT, SIG_DFL);
806 sigemptyset(&fset);
807 sigprocmask(SIG_SETMASK, &fset, NULL);
808 NYD_LEAVE;
811 FL void
812 free_child(int pid)
814 sigset_t nset, oset;
815 struct child *cp;
816 NYD_ENTER;
818 sigemptyset(&nset);
819 sigaddset(&nset, SIGCHLD);
820 sigprocmask(SIG_BLOCK, &nset, &oset);
822 cp = findchild(pid);
823 if (cp->done)
824 delchild(cp);
825 else
826 cp->free = 1;
828 sigprocmask(SIG_SETMASK, &oset, NULL);
829 NYD_LEAVE;
832 FL bool_t
833 wait_child(int pid, int *wait_status)
835 sigset_t nset, oset;
836 struct child *cp;
837 int ws;
838 bool_t rv;
839 NYD_ENTER;
841 sigemptyset(&nset);
842 sigaddset(&nset, SIGCHLD);
843 sigprocmask(SIG_BLOCK, &nset, &oset);
845 cp = findchild(pid);
846 while (!cp->done)
847 sigsuspend(&oset);
848 ws = cp->status;
849 delchild(cp);
851 sigprocmask(SIG_SETMASK, &oset, NULL);
853 if (wait_status != NULL)
854 *wait_status = ws;
855 rv = (WIFEXITED(ws) && WEXITSTATUS(ws) == 0);
856 NYD_LEAVE;
857 return rv;
860 #ifdef _OUR_CLOEXEC
861 # undef O_CLOEXEC
862 # undef _OUR_CLOEXEC
863 #endif
864 #undef _SET_CLOEXEC
866 /* vim:set fenc=utf-8:s-it-mode */