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;
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 }
101 if(pid != 0)
102 return pid;
103 if(flags&RFCENVG)
104 if(environ)
105 *environ = nil;
107 if(flags&RFPROC){
108 werrstr("cannot use rfork for shared memory -- use libthread");
109 return -1;
111 if(flags&RFNAMEG){
112 /* XXX set $NAMESPACE to a new directory */
113 flags &= ~RFNAMEG;
115 if(flags&RFNOTEG){
116 setpgid(0, getpid());
117 flags &= ~RFNOTEG;
119 if(flags&RFNOWAIT){
120 werrstr("cannot use RFNOWAIT without RFPROC");
121 return -1;
123 if(flags){
124 werrstr("unknown flags %08ux in rfork", flags);
125 return -1;
127 return 0;