Blob


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