rfork.c - 9base - revived minimalist port of Plan 9 userland to Unix
 (HTM) git clone git://git.suckless.org/9base
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       rfork.c (2824B)
       ---
            1 #include <u.h>
            2 #include <sys/wait.h>
            3 #include <signal.h>
            4 #include <libc.h>
            5 #undef rfork
            6 
            7 static void
            8 nop(int x)
            9 {
           10         USED(x);
           11 }
           12 
           13 int
           14 p9rfork(int flags)
           15 {
           16         int pid, status;
           17         int p[2];
           18         int n;
           19         char buf[128], *q;
           20         extern char **environ;
           21 
           22         if((flags&(RFPROC|RFFDG|RFMEM)) == (RFPROC|RFFDG)){
           23                 /* check other flags before we commit */
           24                 flags &= ~(RFPROC|RFFDG|RFENVG);
           25                 n = (flags & ~(RFNOTEG|RFNAMEG|RFNOWAIT|RFCENVG));
           26                 if(n){
           27                         werrstr("unknown flags %08ux in rfork", n);
           28                         return -1;
           29                 }
           30                 if(flags&RFNOWAIT){
           31                         /*
           32                          * BUG - should put the signal handler back after we
           33                          * finish, but I just don't care.  If a program calls with
           34                          * NOWAIT once, they're not likely to want child notes
           35                          * after that.
           36                          */
           37                         signal(SIGCHLD, nop);
           38                         if(pipe(p) < 0)
           39                                 return -1;
           40                 }
           41                 pid = fork();
           42                 if(pid == -1)
           43                         return -1;
           44                 if(flags&RFNOWAIT){
           45                         flags &= ~RFNOWAIT;
           46                         if(pid){
           47                                 /*
           48                                  * Parent - wait for child to fork wait-free child.
           49                                  * Then read pid from pipe.  Assume pipe buffer can absorb the write.
           50                                  */
           51                                 close(p[1]);
           52                                 status = 0;
           53                                 if(wait4(pid, &status, 0, 0) < 0){
           54                                         werrstr("pipe dance - wait4 - %r");
           55                                         close(p[0]);
           56                                         return -1;
           57                                 }
           58                                 n = readn(p[0], buf, sizeof buf-1);
           59                                 close(p[0]);
           60                                 if(!WIFEXITED(status) || WEXITSTATUS(status)!=0 || n <= 0){
           61                                         if(!WIFEXITED(status))
           62                                                 werrstr("pipe dance - !exited 0x%ux", status);
           63                                         else if(WEXITSTATUS(status) != 0)
           64                                                 werrstr("pipe dance - non-zero status 0x%ux", status);
           65                                         else if(n < 0)
           66                                                 werrstr("pipe dance - pipe read error - %r");
           67                                         else if(n == 0)
           68                                                 werrstr("pipe dance - pipe read eof");
           69                                         else
           70                                                 werrstr("pipe dance - unknown failure");
           71                                         return -1;
           72                                 }
           73                                 buf[n] = 0;
           74                                 if(buf[0] == 'x'){
           75                                         werrstr("%s", buf+2);
           76                                         return -1;
           77                                 }
           78                                 pid = strtol(buf, &q, 0);
           79                         }else{
           80                                 /*
           81                                  * Child - fork a new child whose wait message can't 
           82                                  * get back to the parent because we're going to exit!
           83                                  */
           84                                 signal(SIGCHLD, SIG_IGN);
           85                                 close(p[0]);
           86                                 pid = fork();
           87                                 if(pid){
           88                                         /* Child parent - send status over pipe and exit. */
           89                                         if(pid > 0)
           90                                                 fprint(p[1], "%d", pid);
           91                                         else
           92                                                 fprint(p[1], "x %r");
           93                                         close(p[1]);
           94                                         _exit(0);
           95                                 }else{
           96                                         /* Child child - close pipe. */
           97                                         close(p[1]);
           98                                 }
           99                         }
          100                 }
          101                 if(pid != 0)
          102                         return pid;
          103                 if(flags&RFCENVG)
          104                         if(environ)
          105                                 *environ = nil;
          106         }
          107         if(flags&RFPROC){
          108                 werrstr("cannot use rfork for shared memory -- use libthread");
          109                 return -1;
          110         }
          111         if(flags&RFNAMEG){
          112                 /* XXX set $NAMESPACE to a new directory */
          113                 flags &= ~RFNAMEG;
          114         }
          115         if(flags&RFNOTEG){
          116                 setpgid(0, getpid());
          117                 flags &= ~RFNOTEG;
          118         }
          119         if(flags&RFNOWAIT){
          120                 werrstr("cannot use RFNOWAIT without RFPROC");
          121                 return -1;
          122         }
          123         if(flags){
          124                 werrstr("unknown flags %08ux in rfork", flags);
          125                 return -1;
          126         }
          127         return 0;
          128 }