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;
20 extern char **environ;
21 struct sigaction oldchld;
23 memset(&oldchld, 0, sizeof oldchld);
25 if((flags&(RFPROC|RFFDG|RFMEM)) == (RFPROC|RFFDG)){
26 /* check other flags before we commit */
27 flags &= ~(RFPROC|RFFDG|RFENVG);
28 n = (flags & ~(RFNOTEG|RFNAMEG|RFNOWAIT|RFCENVG));
29 if(n){
30 werrstr("unknown flags %08ux in rfork", n);
31 return -1;
32 }
33 if(flags&RFNOWAIT){
34 sigaction(SIGCHLD, nil, &oldchld);
35 signal(SIGCHLD, nop);
36 if(pipe(p) < 0)
37 return -1;
38 }
39 pid = fork();
40 if(pid == -1)
41 return -1;
42 if(flags&RFNOWAIT){
43 flags &= ~RFNOWAIT;
44 if(pid){
45 /*
46 * Parent - wait for child to fork wait-free child.
47 * Then read pid from pipe. Assume pipe buffer can absorb the write.
48 */
49 close(p[1]);
50 status = 0;
51 if(wait4(pid, &status, 0, 0) < 0){
52 werrstr("pipe dance - wait4 - %r");
53 close(p[0]);
54 return -1;
55 }
56 n = readn(p[0], buf, sizeof buf-1);
57 close(p[0]);
58 if(!WIFEXITED(status) || WEXITSTATUS(status)!=0 || n <= 0){
59 if(!WIFEXITED(status))
60 werrstr("pipe dance - !exited 0x%ux", status);
61 else if(WEXITSTATUS(status) != 0)
62 werrstr("pipe dance - non-zero status 0x%ux", status);
63 else if(n < 0)
64 werrstr("pipe dance - pipe read error - %r");
65 else if(n == 0)
66 werrstr("pipe dance - pipe read eof");
67 else
68 werrstr("pipe dance - unknown failure");
69 return -1;
70 }
71 buf[n] = 0;
72 if(buf[0] == 'x'){
73 werrstr("%s", buf+2);
74 return -1;
75 }
76 pid = strtol(buf, &q, 0);
77 }else{
78 /*
79 * Child - fork a new child whose wait message can't
80 * get back to the parent because we're going to exit!
81 */
82 signal(SIGCHLD, SIG_IGN);
83 close(p[0]);
84 pid = fork();
85 if(pid){
86 /* Child parent - send status over pipe and exit. */
87 if(pid > 0)
88 fprint(p[1], "%d", pid);
89 else
90 fprint(p[1], "x %r");
91 close(p[1]);
92 _exit(0);
93 }else{
94 /* Child child - close pipe. */
95 close(p[1]);
96 }
97 }
98 sigaction(SIGCHLD, &oldchld, nil);
99 }
100 if(pid != 0)
101 return pid;
102 if(flags&RFCENVG)
103 if(environ)
104 *environ = nil;
106 if(flags&RFPROC){
107 werrstr("cannot use rfork for shared memory -- use libthread");
108 return -1;
110 if(flags&RFNAMEG){
111 /* XXX set $NAMESPACE to a new directory */
112 flags &= ~RFNAMEG;
114 if(flags&RFNOTEG){
115 setpgid(0, getpid());
116 flags &= ~RFNOTEG;
118 if(flags&RFNOWAIT){
119 werrstr("cannot use RFNOWAIT without RFPROC");
120 return -1;
122 if(flags){
123 werrstr("unknown flags %08ux in rfork", flags);
124 return -1;
126 return 0;