rfork.c - 9base - revived minimalist port of Plan 9 userland to Unix | |
git clone git://git.suckless.org/9base | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
rfork.c (2824B) | |
--- | |
1 #include <u.h> | |
2 #include <sys/wait.h> | |
3 #include <signal.h> | |
4 #include <libc.h> | |
5 #undef rfork | |
6 | |
7 static void | |
8 nop(int x) | |
9 { | |
10 USED(x); | |
11 } | |
12 | |
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 | |
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 afte… | |
33 * finish, but I just don't care. If a program … | |
34 * NOWAIT once, they're not likely to want child… | |
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-… | |
49 * Then read pid from pipe. Assume pipe… | |
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(sta… | |
61 if(!WIFEXITED(status)) | |
62 werrstr("pipe dance - !e… | |
63 else if(WEXITSTATUS(status) != 0) | |
64 werrstr("pipe dance - no… | |
65 else if(n < 0) | |
66 werrstr("pipe dance - pi… | |
67 else if(n == 0) | |
68 werrstr("pipe dance - pi… | |
69 else | |
70 werrstr("pipe dance - un… | |
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 m… | |
82 * get back to the parent because we're … | |
83 */ | |
84 signal(SIGCHLD, SIG_IGN); | |
85 close(p[0]); | |
86 pid = fork(); | |
87 if(pid){ | |
88 /* Child parent - send status ov… | |
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 } | |
100 } | |
101 if(pid != 0) | |
102 return pid; | |
103 if(flags&RFCENVG) | |
104 if(environ) | |
105 *environ = nil; | |
106 } | |
107 if(flags&RFPROC){ | |
108 werrstr("cannot use rfork for shared memory -- use libth… | |
109 return -1; | |
110 } | |
111 if(flags&RFNAMEG){ | |
112 /* XXX set $NAMESPACE to a new directory */ | |
113 flags &= ~RFNAMEG; | |
114 } | |
115 if(flags&RFNOTEG){ | |
116 setpgid(0, getpid()); | |
117 flags &= ~RFNOTEG; | |
118 } | |
119 if(flags&RFNOWAIT){ | |
120 werrstr("cannot use RFNOWAIT without RFPROC"); | |
121 return -1; | |
122 } | |
123 if(flags){ | |
124 werrstr("unknown flags %08ux in rfork", flags); | |
125 return -1; | |
126 } | |
127 return 0; | |
128 } |