skalibs

Mirror/fork of https://skarnet.org/software/skalibs/
git clone https://ccx.te2000.cz/git/skalibs
Log | Files | Refs | README | LICENSE

doublefork.c (1081B)


      1 /* ISC license. */
      2 
      3 #include <sys/wait.h>
      4 #include <unistd.h>
      5 #include <errno.h>
      6 
      7 #include <skalibs/uint64.h>
      8 #include <skalibs/allreadwrite.h>
      9 #include <skalibs/djbunix.h>
     10 #include <skalibs/posixplz.h>
     11 
     12 pid_t doublefork ()
     13 {
     14   char pack[8] ;
     15   int fd[2] ;
     16   pid_t child ;
     17   if (pipe(fd) == -1) return -1 ;
     18   child = fork() ;
     19   switch (child)
     20   {
     21     case -1:
     22     {
     23       fd_close(fd[1]) ;
     24       fd_close(fd[0]) ;
     25       return -1 ;
     26     }
     27     case 0:
     28     {
     29       pid_t pid ;
     30       fd_close(fd[0]) ;
     31       pid = fork() ;
     32       switch (pid)
     33       {
     34         case -1: _exit(errno) ;
     35         case 0: fd_close(fd[1]) ; return 0 ;
     36       }
     37       uint64_pack_big(pack, pid) ;
     38       _exit((allwrite(fd[1], pack, 8) < 8) ? errno : 0) ;
     39     }
     40   }
     41   fd_close(fd[1]) ;
     42   {
     43     uint64_t grandchild = 0 ;
     44     int wstat ;
     45     if (allread(fd[0], pack, 8) < 8) grandchild = 1 ;
     46     fd_close(fd[0]) ;
     47     wait_pid(child, &wstat) ;
     48     if (grandchild) return (errno = WIFSIGNALED(wstat) ? EINTR : WEXITSTATUS(wstat), -1) ;
     49     uint64_unpack_big(pack, &grandchild) ;
     50     return (pid_t)grandchild ;
     51   }
     52 }