Blob


1 #include <u.h>
2 #include <sys/wait.h>
3 #include <signal.h>
4 #include <libc.h>
5 #include "9proc.h"
6 #undef rfork
8 int
9 p9rfork(int flags)
10 {
11 int pid, status;
12 int p[2];
13 int n;
14 char buf[128], *q;
16 _p9uproc(0);
17 if((flags&(RFPROC|RFFDG|RFMEM)) == (RFPROC|RFFDG)){
18 /* check other flags before we commit */
19 flags &= ~(RFPROC|RFFDG);
20 n = (flags & ~(RFNOTEG|RFNAMEG|RFNOWAIT));
21 if(n){
22 werrstr("unknown flags %08ux in rfork", n);
23 return -1;
24 }
25 if(flags&RFNOWAIT){
26 if(pipe(p) < 0)
27 return -1;
28 }
29 pid = fork();
30 if(pid == -1)
31 return -1;
32 if(flags&RFNOWAIT){
33 flags &= ~RFNOWAIT;
34 if(pid){
35 /*
36 * Parent - wait for child to fork wait-free child.
37 * Then read pid from pipe. Assume pipe buffer can absorb the write.
38 */
39 close(p[1]);
40 wait4(pid, &status, 0, 0);
41 n = readn(p[0], buf, sizeof buf-1);
42 close(p[0]);
43 if(!WIFEXITED(status) || WEXITSTATUS(status)!=0 || n <= 0){
44 werrstr("pipe dance failed in rfork");
45 return -1;
46 }
47 buf[n] = 0;
48 n = strtol(buf, &q, 0);
49 if(*q != 0){
50 werrstr("%s", q);
51 return -1;
52 }
53 pid = n;
54 }else{
55 /*
56 * Child - fork a new child whose wait message can't
57 * get back to the parent because we're going to exit!
58 */
59 signal(SIGCHLD, SIG_IGN);
60 close(p[0]);
61 pid = fork();
62 if(pid){
63 /* Child parent - send status over pipe and exit. */
64 if(pid > 0)
65 fprint(p[1], "%d", pid);
66 else
67 fprint(p[1], " %r");
68 close(p[1]);
69 _exit(0);
70 }else{
71 /* Child child - close pipe. */
72 close(p[1]);
73 }
74 }
75 }
76 _p9uproc(0);
77 if(pid != 0)
78 return pid;
79 }
80 if(flags&RFPROC){
81 werrstr("cannot use rfork for shared memory -- use ffork");
82 return -1;
83 }
84 if(flags&RFNAMEG){
85 /* XXX set $NAMESPACE to a new directory */
86 flags &= ~RFNAMEG;
87 }
88 if(flags&RFNOTEG){
89 setpgid(0, getpid());
90 flags &= ~RFNOTEG;
91 }
92 if(flags&RFNOWAIT){
93 werrstr("cannot use RFNOWAIT without RFPROC");
94 return -1;
95 }
96 if(flags){
97 werrstr("unknown flags %08ux in rfork", flags);
98 return -1;
99 }
100 return 0;