Review: strings.c
[s-mailx.git] / popen.c
blobed6e1bb0b5fb450e0e219bffa677af7b6499a171
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);
97 static int wait_command(int pid);
98 static struct child *findchild(int pid);
99 static void delchild(struct child *cp);
101 static int
102 scan_mode(char const *mode, int *omode)
104 static struct {
105 char const mode[4];
106 int omode;
107 } const maps[] = {
108 {"r", O_RDONLY},
109 {"w", O_WRONLY | O_CREAT | O_TRUNC},
110 {"wx", O_WRONLY | O_CREAT | O_EXCL},
111 {"a", O_WRONLY | O_APPEND | O_CREAT},
112 {"a+", O_RDWR | O_APPEND},
113 {"r+", O_RDWR},
114 {"w+", O_RDWR | O_CREAT | O_EXCL}
117 int i;
118 NYD_ENTER;
120 for (i = 0; UICMP(z, i, <, NELEM(maps)); ++i)
121 if (!strcmp(maps[i].mode, mode)) {
122 *omode = maps[i].omode;
123 i = 0;
124 goto jleave;
127 alert(tr(152, "Internal error: bad stdio open mode %s\n"), mode);
128 errno = EINVAL;
129 *omode = 0; /* (silence CC) */
130 i = -1;
131 jleave:
132 NYD_LEAVE;
133 return i;
136 static void
137 register_file(FILE *fp, int omode, int ispipe, int pid, int compressed,
138 char const *realfile, long offset)
140 struct fp *fpp;
141 NYD_ENTER;
143 fpp = smalloc(sizeof *fpp);
144 fpp->fp = fp;
145 fpp->omode = omode;
146 fpp->pipe = ispipe;
147 fpp->pid = pid;
148 fpp->link = fp_head;
149 fpp->compressed = compressed;
150 fpp->realfile = (realfile != NULL) ? sstrdup(realfile) : NULL;
151 fpp->offset = offset;
152 fp_head = fpp;
153 NYD_LEAVE;
156 static enum okay
157 _compress(struct fp *fpp)
159 char const *cmd[2];
160 int outfd;
161 enum okay rv;
162 NYD_ENTER;
164 if (fpp->omode == O_RDONLY) {
165 rv = OKAY;
166 goto jleave;
168 rv = STOP;
170 fflush(fpp->fp);
171 clearerr(fpp->fp);
172 if (fseek(fpp->fp, fpp->offset, SEEK_SET) == -1)
173 goto jleave;
175 #ifdef HAVE_IMAP
176 if ((fpp->compressed & FP_MASK) == FP_IMAP) {
177 rv = imap_append(fpp->realfile, fpp->fp);
178 goto jleave;
180 #endif
181 if ((fpp->compressed & FP_MASK) == FP_MAILDIR) {
182 rv = maildir_append(fpp->realfile, fpp->fp);
183 goto jleave;
186 outfd = open(fpp->realfile, (fpp->omode | O_CREAT) & ~O_EXCL, 0666);
187 if (outfd == -1) {
188 fprintf(stderr, "Fatal: cannot create ");
189 perror(fpp->realfile);
190 goto jleave;
192 if (!(fpp->omode & O_APPEND))
193 ftruncate(outfd, 0);
194 switch (fpp->compressed & FP_MASK) {
195 case FP_GZIP:
196 cmd[0] = "gzip"; cmd[1] = "-c"; break;
197 case FP_BZIP2:
198 cmd[0] = "bzip2"; cmd[1] = "-c"; break;
199 case FP_XZ:
200 cmd[0] = "xz"; cmd[1] = "-c"; break;
201 default:
202 cmd[0] = "cat"; cmd[1] = NULL; break;
204 if (run_command(cmd[0], 0, fileno(fpp->fp), outfd, cmd[1], NULL, NULL) >= 0)
205 rv = OKAY;
206 close(outfd);
207 jleave:
208 NYD_LEAVE;
209 return rv;
212 static int
213 _decompress(int compression, int infd, int outfd)
215 char const *cmd[2];
216 int rv;
217 NYD_ENTER;
219 switch (compression & FP_MASK) {
220 case FP_GZIP: cmd[0] = "gzip"; cmd[1] = "-cd"; break;
221 case FP_BZIP2: cmd[0] = "bzip2"; cmd[1] = "-cd"; break;
222 case FP_XZ: cmd[0] = "xz"; cmd[1] = "-cd"; break;
223 default: cmd[0] = "cat"; cmd[1] = NULL; break;
224 case FP_IMAP:
225 case FP_MAILDIR:
226 rv = 0;
227 goto jleave;
229 rv = run_command(cmd[0], 0, infd, outfd, cmd[1], NULL, NULL);
230 jleave:
231 NYD_LEAVE;
232 return rv;
235 static enum okay
236 unregister_file(FILE *fp)
238 struct fp **pp, *p;
239 enum okay rv = OKAY;
240 NYD_ENTER;
242 for (pp = &fp_head; (p = *pp) != NULL; pp = &p->link)
243 if (p->fp == fp) {
244 if ((p->compressed & FP_MASK) != FP_RAW) /* TODO ;} */
245 rv = _compress(p);
246 *pp = p->link;
247 free(p);
248 goto jleave;
250 #ifdef HAVE_DEBUG
251 panic
252 #else
253 alert
254 #endif
255 (tr(153, "Invalid file pointer"));
256 rv = STOP;
257 jleave:
258 NYD_LEAVE;
259 return rv;
262 static int
263 file_pid(FILE *fp)
265 int rv;
266 struct fp *p;
267 NYD_ENTER;
269 rv = -1;
270 for (p = fp_head; p; p = p->link)
271 if (p->fp == fp) {
272 rv = p->pid;
273 break;
275 NYD_LEAVE;
276 return rv;
279 static int
280 wait_command(int pid)
282 int rv = 0;
283 NYD_ENTER;
285 if (!wait_child(pid, NULL)) {
286 if (ok_blook(bsdcompat) || ok_blook(bsdmsgs))
287 fprintf(stderr, tr(154, "Fatal error in process.\n"));
288 rv = -1;
290 NYD_LEAVE;
291 return rv;
294 static struct child *
295 findchild(int pid)
297 struct child **cpp;
298 NYD_ENTER;
300 for (cpp = &_popen_child; *cpp != NULL && (*cpp)->pid != pid;
301 cpp = &(*cpp)->link)
303 if (*cpp == NULL) {
304 *cpp = smalloc(sizeof **cpp);
305 (*cpp)->pid = pid;
306 (*cpp)->done = (*cpp)->free = 0;
307 (*cpp)->link = NULL;
309 NYD_LEAVE;
310 return *cpp;
313 static void
314 delchild(struct child *cp)
316 struct child **cpp;
317 NYD_ENTER;
319 for (cpp = &_popen_child; *cpp != cp; cpp = &(*cpp)->link)
321 *cpp = cp->link;
322 free(cp);
323 NYD_LEAVE;
326 FL FILE *
327 safe_fopen(char const *file, char const *oflags, int *xflags)
329 int osflags, fd;
330 FILE *fp = NULL;
331 NYD_ENTER;
333 if (scan_mode(oflags, &osflags) < 0)
334 goto jleave;
335 osflags |= O_CLOEXEC;
336 if (xflags != NULL)
337 *xflags = osflags;
339 if ((fd = open(file, osflags, 0666)) == -1)
340 goto jleave;
341 _SET_CLOEXEC(fd);
343 fp = fdopen(fd, oflags);
344 jleave:
345 NYD_LEAVE;
346 return fp;
349 FL FILE *
350 Fopen(char const *file, char const *oflags)
352 FILE *fp;
353 int osflags;
354 NYD_ENTER;
356 if ((fp = safe_fopen(file, oflags, &osflags)) != NULL)
357 register_file(fp, osflags, 0, 0, FP_RAW, NULL, 0L);
358 NYD_LEAVE;
359 return fp;
362 FL FILE *
363 Fdopen(int fd, char const *oflags)
365 FILE *fp;
366 int osflags;
367 NYD_ENTER;
369 scan_mode(oflags, &osflags);
370 osflags |= O_CLOEXEC;
372 if ((fp = fdopen(fd, oflags)) != NULL)
373 register_file(fp, osflags, 0, 0, FP_RAW, NULL, 0L);
374 NYD_LEAVE;
375 return fp;
378 FL int
379 Fclose(FILE *fp)
381 int i = 0;
382 NYD_ENTER;
384 if (unregister_file(fp) == OKAY)
385 i |= 1;
386 if (fclose(fp) == 0)
387 i |= 2;
388 NYD_LEAVE;
389 return (i == 3 ? 0 : EOF);
392 FL FILE *
393 Zopen(char const *file, char const *oflags, int *compression) /* FIXME MESS! */
395 FILE *rv = NULL;
396 int _compression, osflags, mode, infd;
397 enum oflags rof;
398 long offset;
399 enum protocol p;
400 NYD_ENTER;
402 if (compression == NULL)
403 compression = &_compression;
405 if (scan_mode(oflags, &osflags) < 0)
406 goto jleave;
407 rof = OF_RDWR | OF_UNLINK;
408 if (osflags & O_APPEND)
409 rof |= OF_APPEND;
410 if (osflags == O_RDONLY) {
411 mode = R_OK;
412 *compression = FP_READONLY;
413 } else {
414 mode = R_OK | W_OK;
415 *compression = 0;
418 /* TODO ???? */
419 if ((osflags & O_APPEND) && ((p = which_protocol(file)) == PROTO_IMAP ||
420 p == PROTO_MAILDIR)) {
421 *compression |= (p == PROTO_IMAP) ? FP_IMAP : FP_MAILDIR;
422 osflags = O_RDWR | O_APPEND | O_CREAT;
423 infd = -1;
424 } else {
425 char const *ext;
427 if ((ext = strrchr(file, '.')) != NULL) {
428 if (!strcmp(ext, ".gz"))
429 *compression |= FP_GZIP;
430 else if (!strcmp(ext, ".xz"))
431 *compression |= FP_XZ;
432 else if (!strcmp(ext, ".bz2"))
433 *compression |= FP_BZIP2;
434 else
435 goto jraw;
436 } else {
437 jraw:
438 *compression |= FP_RAW;
439 rv = Fopen(file, oflags);
440 goto jleave;
442 if ((infd = open(file, (mode & W_OK) ? O_RDWR : O_RDONLY)) == -1 &&
443 (!(osflags & O_CREAT) || errno != ENOENT))
444 goto jleave;
447 if ((rv = Ftmp(NULL, "zopen", rof, 0600)) == NULL) {
448 perror(tr(167, "tmpfile"));
449 goto jerr;
451 if (infd >= 0 || (*compression & FP_MASK) == FP_IMAP ||
452 (*compression & FP_MASK) == FP_MAILDIR) {
453 if (_decompress(*compression, infd, fileno(rv)) < 0) {
454 jerr:
455 if (rv != NULL)
456 Fclose(rv);
457 rv = NULL;
458 if (infd >= 0)
459 close(infd);
460 goto jleave;
462 } else {
463 if ((infd = creat(file, 0666)) == -1) {
464 Fclose(rv);
465 rv = NULL;
466 goto jleave;
469 if (infd >= 0)
470 close(infd);
471 fflush(rv);
473 if (!(osflags & O_APPEND))
474 rewind(rv);
475 if ((offset = ftell(rv)) == -1) {
476 Fclose(rv);
477 rv = NULL;
478 goto jleave;
480 register_file(rv, osflags, 0, 0, *compression, file, offset);
481 jleave:
482 NYD_LEAVE;
483 return rv;
486 FL FILE *
487 Ftmp(char **fn, char const *prefix, enum oflags oflags, int mode)
489 FILE *fp = NULL;
490 char *cp_base, *cp;
491 int fd;
492 NYD_ENTER;
494 cp_base =
495 cp = smalloc(strlen(tempdir) + 1 + sizeof("mail") + strlen(prefix) + 7 +1);
496 cp = sstpcpy(cp, tempdir);
497 *cp++ = '/';
498 cp = sstpcpy(cp, "mail");
499 if (*prefix) {
500 *cp++ = '-';
501 cp = sstpcpy(cp, prefix);
503 /* TODO Ftmp(): unroll our own creation loop with atoi(random()) */
504 sstpcpy(cp, ".XXXXXX");
506 hold_all_sigs();
507 #ifdef HAVE_MKSTEMP
508 if ((fd = mkstemp(cp_base)) == -1)
509 goto jfree;
510 if (mode != (S_IRUSR | S_IWUSR) && fchmod(fd, mode) == -1)
511 goto jclose;
512 if (oflags & OF_APPEND) {
513 int f;
515 if ((f = fcntl(fd, F_GETFL)) == -1 ||
516 fcntl(fd, F_SETFL, f | O_APPEND) == -1) {
517 jclose:
518 close(fd);
519 goto junlink;
522 if (!(oflags & OF_REGISTER))
523 fcntl(fd, F_SETFD, FD_CLOEXEC);
524 #else
525 if (mktemp(cp_base) == NULL)
526 goto jfree;
527 if ((fd = open(cp_base, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC |
528 (oflags & OF_APPEND ? O_APPEND : 0), mode)) == -1)
529 goto junlink;
530 if (!(oflags & OF_REGISTER))
531 _SET_CLOEXEC(fd);
532 #endif
534 fp = (*((oflags & OF_REGISTER) ? &Fdopen : &fdopen))(fd,
535 (oflags & OF_RDWR ? "w+" : "w"));
536 if (fp == NULL || (oflags & OF_UNLINK)) {
537 junlink:
538 unlink(cp_base);
539 goto jfree;
542 if (fn != NULL)
543 *fn = cp_base;
544 jleave:
545 if (fp == NULL || !(oflags & OF_HOLDSIGS))
546 rele_all_sigs();
547 NYD_LEAVE;
548 return fp;
549 jfree:
550 if ((cp = cp_base) != NULL)
551 free(cp);
552 goto jleave;
555 FL void
556 Ftmp_release(char **fn)
558 char *cp;
559 NYD_ENTER;
561 cp = *fn;
562 *fn = NULL;
563 if (cp != NULL) {
564 unlink(cp);
565 rele_all_sigs();
566 free(cp);
568 NYD_LEAVE;
571 FL void
572 Ftmp_free(char **fn)
574 char *cp;
575 NYD_ENTER;
577 cp = *fn;
578 *fn = NULL;
579 if (cp != NULL)
580 free(cp);
581 NYD_LEAVE;
584 FL bool_t
585 pipe_cloexec(int fd[2])
587 bool_t rv = FAL0;
588 NYD_ENTER;
590 #ifdef HAVE_PIPE2
591 if (pipe2(fd, O_CLOEXEC) == -1)
592 goto jleave;
593 #else
594 if (pipe(fd) == -1)
595 goto jleave;
596 fcntl(fd[0], F_SETFD, FD_CLOEXEC);
597 fcntl(fd[1], F_SETFD, FD_CLOEXEC);
598 #endif
599 rv = TRU1;
600 jleave:
601 NYD_LEAVE;
602 return rv;
605 FL FILE *
606 Popen(char const *cmd, char const *mode, char const *sh, int newfd1)
608 int p[2], myside, hisside, fd0, fd1, pid;
609 char mod[2] = {'0', '\0'};
610 sigset_t nset;
611 FILE *rv = NULL;
612 NYD_ENTER;
614 if (!pipe_cloexec(p))
615 goto jleave;
617 if (*mode == 'r') {
618 myside = p[READ];
619 fd0 = -1;
620 hisside = fd1 = p[WRITE];
621 mod[0] = *mode;
622 } else if (*mode == 'W') {
623 myside = p[WRITE];
624 hisside = fd0 = p[READ];
625 fd1 = newfd1;
626 mod[0] = 'w';
627 } else {
628 myside = p[WRITE];
629 hisside = fd0 = p[READ];
630 fd1 = -1;
631 mod[0] = 'w';
633 sigemptyset(&nset);
634 if (sh == NULL) {
635 pid = start_command(cmd, &nset, fd0, fd1, NULL, NULL, NULL);
636 } else {
637 pid = start_command(sh, &nset, fd0, fd1, "-c", cmd, NULL);
639 if (pid < 0) {
640 close(p[READ]);
641 close(p[WRITE]);
642 goto jleave;
644 close(hisside);
645 if ((rv = fdopen(myside, mod)) != NULL)
646 register_file(rv, 0, 1, pid, FP_RAW, NULL, 0L);
647 jleave:
648 NYD_LEAVE;
649 return rv;
652 FL bool_t
653 Pclose(FILE *ptr, bool_t dowait)
655 sigset_t nset, oset;
656 int pid;
657 bool_t rv = FAL0;
658 NYD_ENTER;
660 pid = file_pid(ptr);
661 if (pid < 0)
662 goto jleave;
663 unregister_file(ptr);
664 fclose(ptr);
665 if (dowait) {
666 sigemptyset(&nset);
667 sigaddset(&nset, SIGINT);
668 sigaddset(&nset, SIGHUP);
669 sigprocmask(SIG_BLOCK, &nset, &oset);
670 rv = wait_child(pid, NULL);
671 sigprocmask(SIG_SETMASK, &oset, NULL);
672 } else {
673 free_child(pid);
674 rv = TRU1;
676 jleave:
677 NYD_LEAVE;
678 return rv;
681 FL void
682 close_all_files(void)
684 NYD_ENTER;
685 while (fp_head != NULL)
686 if (fp_head->pipe)
687 Pclose(fp_head->fp, TRU1);
688 else
689 Fclose(fp_head->fp);
690 NYD_LEAVE;
693 FL int
694 run_command(char const *cmd, sigset_t *mask, int infd, int outfd,
695 char const *a0, char const *a1, char const *a2)
697 int rv;
698 NYD_ENTER;
700 if ((rv = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0)
701 rv = -1;
702 else
703 rv = wait_command(rv);
704 NYD_LEAVE;
705 return rv;
708 FL int
709 start_command(char const *cmd, sigset_t *mask, int infd, int outfd,
710 char const *a0, char const *a1, char const *a2)
712 int rv;
713 NYD_ENTER;
715 if ((rv = fork()) == -1) {
716 perror("fork");
717 rv = -1;
718 } else if (rv == 0) {
719 char *argv[100];
720 int i = getrawlist(cmd, strlen(cmd), argv, NELEM(argv), 0);
722 if ((argv[i++] = UNCONST(a0)) != NULL &&
723 (argv[i++] = UNCONST(a1)) != NULL &&
724 (argv[i++] = UNCONST(a2)) != NULL)
725 argv[i] = NULL;
726 prepare_child(mask, infd, outfd);
727 execvp(argv[0], argv);
728 perror(argv[0]);
729 _exit(1);
731 NYD_LEAVE;
732 return rv;
735 FL void
736 prepare_child(sigset_t *nset, int infd, int outfd)
738 int i;
739 sigset_t fset;
740 NYD_ENTER;
742 /* All file descriptors other than 0, 1, and 2 are supposed to be cloexec */
743 if (infd >= 0)
744 dup2(infd, 0);
745 if (outfd >= 0)
746 dup2(outfd, 1);
748 if (nset) {
749 for (i = 1; i < NSIG; ++i)
750 if (sigismember(nset, i))
751 safe_signal(i, SIG_IGN);
752 if (!sigismember(nset, SIGINT))
753 safe_signal(SIGINT, SIG_DFL);
756 sigemptyset(&fset);
757 sigprocmask(SIG_SETMASK, &fset, NULL);
758 NYD_LEAVE;
761 FL void
762 sigchild(int signo)
764 int pid, status;
765 struct child *cp;
766 NYD_X; /* Signal handler */
767 UNUSED(signo);
769 for (;;) {
770 pid = waitpid(-1, &status, WNOHANG);
771 if (pid == -1) {
772 if (errno == EINTR)
773 continue;
774 break;
776 cp = findchild(pid);
777 if (cp->free)
778 delchild(cp);
779 else {
780 cp->done = 1;
781 cp->status = status;
786 FL void
787 free_child(int pid)
789 sigset_t nset, oset;
790 struct child *cp;
791 NYD_ENTER;
793 sigemptyset(&nset);
794 sigaddset(&nset, SIGCHLD);
795 sigprocmask(SIG_BLOCK, &nset, &oset);
797 cp = findchild(pid);
798 if (cp->done)
799 delchild(cp);
800 else
801 cp->free = 1;
803 sigprocmask(SIG_SETMASK, &oset, NULL);
804 NYD_LEAVE;
807 FL bool_t
808 wait_child(int pid, int *wait_status)
810 sigset_t nset, oset;
811 struct child *cp;
812 int ws;
813 bool_t rv;
814 NYD_ENTER;
816 sigemptyset(&nset);
817 sigaddset(&nset, SIGCHLD);
818 sigprocmask(SIG_BLOCK, &nset, &oset);
820 cp = findchild(pid);
821 while (!cp->done)
822 sigsuspend(&oset);
823 ws = cp->status;
824 delchild(cp);
826 sigprocmask(SIG_SETMASK, &oset, NULL);
828 if (wait_status != NULL)
829 *wait_status = ws;
830 rv = (WIFEXITED(ws) && WEXITSTATUS(ws) == 0);
831 NYD_LEAVE;
832 return rv;
835 #ifdef _OUR_CLOEXEC
836 # undef O_CLOEXEC
837 # undef _OUR_CLOEXEC
838 #endif
839 #undef _SET_CLOEXEC
841 /* vim:set fenc=utf-8:s-it-mode */