texec.c - plan9port - [fork] Plan 9 from user space | |
git clone git://src.adamsgaard.dk/plan9port | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
texec.c (3487B) | |
--- | |
1 #include "threadimpl.h" | |
2 | |
3 static Lock thewaitlock; | |
4 static Channel *thewaitchan; | |
5 | |
6 static void | |
7 execproc(void *v) | |
8 { | |
9 int pid; | |
10 Channel *c; | |
11 Execjob *e; | |
12 Waitmsg *w; | |
13 | |
14 e = v; | |
15 pid = _threadspawn(e->fd, e->cmd, e->argv, e->dir); | |
16 sendul(e->c, pid); | |
17 if(pid > 0){ | |
18 w = waitfor(pid); | |
19 if((c = thewaitchan) != nil) | |
20 sendp(c, w); | |
21 else | |
22 free(w); | |
23 } | |
24 threadexits(nil); | |
25 } | |
26 | |
27 int | |
28 _runthreadspawn(int *fd, char *cmd, char **argv, char *dir) | |
29 { | |
30 int pid; | |
31 Execjob e; | |
32 | |
33 e.fd = fd; | |
34 e.cmd = cmd; | |
35 e.argv = argv; | |
36 e.dir = dir; | |
37 e.c = chancreate(sizeof(void*), 0); | |
38 proccreate(execproc, &e, 65536); | |
39 pid = recvul(e.c); | |
40 chanfree(e.c); | |
41 return pid; | |
42 } | |
43 | |
44 Channel* | |
45 threadwaitchan(void) | |
46 { | |
47 if(thewaitchan) | |
48 return thewaitchan; | |
49 lock(&thewaitlock); | |
50 if(thewaitchan){ | |
51 unlock(&thewaitlock); | |
52 return thewaitchan; | |
53 } | |
54 thewaitchan = chancreate(sizeof(Waitmsg*), 4); | |
55 chansetname(thewaitchan, "threadwaitchan"); | |
56 unlock(&thewaitlock); | |
57 return thewaitchan; | |
58 } | |
59 | |
60 int | |
61 _threadspawn(int fd[3], char *cmd, char *argv[], char *dir) | |
62 { | |
63 int i, n, p[2], pid; | |
64 char exitstr[100]; | |
65 | |
66 notifyoff("sys: child"); /* do not let child note kill us… | |
67 if(pipe(p) < 0) | |
68 return -1; | |
69 if(fcntl(p[0], F_SETFD, 1) < 0 || fcntl(p[1], F_SETFD, 1) < 0){ | |
70 close(p[0]); | |
71 close(p[1]); | |
72 return -1; | |
73 } | |
74 switch(pid = fork()){ | |
75 case -1: | |
76 close(p[0]); | |
77 close(p[1]); | |
78 return -1; | |
79 case 0: | |
80 /* can't RFNOTEG - will lose tty */ | |
81 if(dir != nil ) | |
82 chdir(dir); /* best effort */ | |
83 dup2(fd[0], 0); | |
84 dup2(fd[1], 1); | |
85 dup2(fd[2], 2); | |
86 if(!isatty(0) && !isatty(1) && !isatty(2)) | |
87 rfork(RFNOTEG); | |
88 for(i=3; i<100; i++) | |
89 if(i != p[1]) | |
90 close(i); | |
91 execvp(cmd, argv); | |
92 fprint(p[1], "%d", errno); | |
93 close(p[1]); | |
94 _exit(0); | |
95 } | |
96 | |
97 close(p[1]); | |
98 n = read(p[0], exitstr, sizeof exitstr-1); | |
99 close(p[0]); | |
100 if(n > 0){ /* exec failed */ | |
101 free(waitfor(pid)); | |
102 exitstr[n] = 0; | |
103 errno = atoi(exitstr); | |
104 return -1; | |
105 } | |
106 | |
107 close(fd[0]); | |
108 if(fd[1] != fd[0]) | |
109 close(fd[1]); | |
110 if(fd[2] != fd[1] && fd[2] != fd[0]) | |
111 close(fd[2]); | |
112 return pid; | |
113 } | |
114 | |
115 int | |
116 threadspawn(int fd[3], char *cmd, char *argv[]) | |
117 { | |
118 return _runthreadspawn(fd, cmd, argv, nil); | |
119 } | |
120 | |
121 int | |
122 threadspawnd(int fd[3], char *cmd, char *argv[], char *dir) | |
123 { | |
124 return _runthreadspawn(fd, cmd, argv, dir); | |
125 } | |
126 | |
127 int | |
128 threadspawnl(int fd[3], char *cmd, ...) | |
129 { | |
130 char **argv, *s; | |
131 int n, pid; | |
132 va_list arg; | |
133 | |
134 va_start(arg, cmd); | |
135 for(n=0; va_arg(arg, char*) != nil; n++) | |
136 ; | |
137 n++; | |
138 va_end(arg); | |
139 | |
140 argv = malloc(n*sizeof(argv[0])); | |
141 if(argv == nil) | |
142 return -1; | |
143 | |
144 va_start(arg, cmd); | |
145 for(n=0; (s=va_arg(arg, char*)) != nil; n++) | |
146 argv[n] = s; | |
147 argv[n] = 0; | |
148 va_end(arg); | |
149 | |
150 pid = threadspawn(fd, cmd, argv); | |
151 free(argv); | |
152 return pid; | |
153 } | |
154 | |
155 int | |
156 _threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[]) | |
157 { | |
158 int pid; | |
159 | |
160 pid = threadspawn(fd, cmd, argv); | |
161 if(cpid){ | |
162 if(pid < 0) | |
163 chansendul(cpid, ~0); | |
164 else | |
165 chansendul(cpid, pid); | |
166 } | |
167 return pid; | |
168 } | |
169 | |
170 void | |
171 threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[]) | |
172 { | |
173 if(_threadexec(cpid, fd, cmd, argv) >= 0) | |
174 threadexits("threadexec"); | |
175 } | |
176 | |
177 void | |
178 threadexecl(Channel *cpid, int fd[3], char *cmd, ...) | |
179 { | |
180 char **argv, *s; | |
181 int n, pid; | |
182 va_list arg; | |
183 | |
184 va_start(arg, cmd); | |
185 for(n=0; va_arg(arg, char*) != nil; n++) | |
186 ; | |
187 n++; | |
188 va_end(arg); | |
189 | |
190 argv = malloc(n*sizeof(argv[0])); | |
191 if(argv == nil){ | |
192 if(cpid) | |
193 chansendul(cpid, ~0); | |
194 return; | |
195 } | |
196 | |
197 va_start(arg, cmd); | |
198 for(n=0; (s=va_arg(arg, char*)) != nil; n++) | |
199 argv[n] = s; | |
200 argv[n] = 0; | |
201 va_end(arg); | |
202 | |
203 pid = _threadexec(cpid, fd, cmd, argv); | |
204 free(argv); | |
205 | |
206 if(pid >= 0) | |
207 threadexits("threadexecl"); | |
208 } |