Blob


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