xref: /inferno-os/utils/mk/Nt.c (revision 5da01da38fbf2fd583ece152e95e70885d54d4d3)
1 #define INFERNO_KEEPENVIRON
2 #include	"mk.h"
3 #include	<signal.h>
4 #include	<sys/utime.h>
5 
6 #define Arc	My_Arc		/* avoid name conflicts */
7 #undef DELETE
8 
9 #include	<windows.h>
10 
11 enum {
12 	Nchild	= 100,
13 };
14 
15 char *rootdir =		ROOT;
16 char *shell =		"Nt/386/bin/rcsh.exe";	/* Path relative to root */
17 
18 typedef struct Child	Child;
19 
20 struct Child {
21 	int	pid;
22 	HANDLE	handle;
23 };
24 
25 static Child child[Nchild];
26 
27 extern char **environ;
28 
29 DWORD WINAPI writecmd(LPVOID a);
30 
31 void
32 readenv(void)
33 {
34 	char **p, *s;
35 	Word *w;
36 
37 	for(p = environ; *p; p++){
38 		s = shname(*p);
39 		if(*s == '=') {
40 			*s = 0;
41 			w = newword(s+1);
42 		} else
43 			w = newword("");
44 		if (symlook(*p, S_INTERNAL, 0))
45 			continue;
46 		s = strdup(*p);
47 		setvar(s, (void *)w);
48 		symlook(s, S_EXPORTED, (void *)"")->value = "";
49 	}
50 }
51 
52 char *
53 exportenv(Envy *e)
54 {
55 	int i, n;
56 	char *buf, *v;
57 
58 	buf = 0;
59 	n = 0;
60 	for(i = 0; e->name; e++, i++) {
61 			/* word separator is shell-dependent */
62 		if(e->values)
63 			v = wtos(e->values, IWS);
64 		else
65 			v = "";
66 		buf = Realloc(buf, n+strlen(e->name)+1+strlen(v)+1);
67 
68 		n += sprint(buf+n, "%s=%s", e->name, v);
69 		n++;	/* skip over null */
70 		if(e->values)
71 			free(v);
72 	}
73 	/* final null */
74 	buf = Realloc(buf, n+1);
75 	buf[n] = 0;
76 
77 	return buf;
78 }
79 
80 int
81 waitfor(char *msg)
82 {
83 	int pid, n, i, r, code;
84 	HANDLE tab[Nchild];
85 
86 	for(i=0,n=0; i<Nchild; i++)
87 		if(child[i].handle != 0)
88 			tab[n++] = child[i].handle;
89 
90 	if(n == 0)
91 		return -1;
92 
93 	r = WaitForMultipleObjects(n, tab, 0, INFINITE);
94 
95 	r -= WAIT_OBJECT_0;
96 	if(r<0 || r>=n) {
97 		perror("wait failed");
98 		exits("wait failed");
99 	}
100 
101 	for(i=0; i<Nchild; i++)
102 		if(child[i].handle == tab[r])
103 			break;
104 	if(i == Nchild){
105 		snprint(msg, ERRMAX, "unknown child (%lux)", tab[r]);
106 		return -1;
107 	}
108 
109 	if(msg) {
110 		*msg = 0;
111 		if(GetExitCodeProcess(child[i].handle, &code) == FALSE)
112 			snprint(msg, ERRMAX, "unknown exit code");
113 		else if(code != 0)
114 			snprint(msg, ERRMAX, "exit(%d)", code);
115 	}
116 
117 	CloseHandle(child[i].handle);
118 	child[i].handle = 0;
119 	pid = child[i].pid;
120 	child[i].pid = 0;
121 
122 	return pid;
123 }
124 
125 void
126 expunge(int pid, char *msg)
127 {
128 /*
129 	if(strcmp(msg, "interrupt"))
130 		kill(pid, SIGINT);
131 	else
132 		kill(pid, SIGHUP);
133 */
134 }
135 
136 HANDLE
137 duphandle(HANDLE h)
138 {
139 	HANDLE r;
140 
141 	if(DuplicateHandle(GetCurrentProcess(), h,
142 			GetCurrentProcess(), &r, DUPLICATE_SAME_ACCESS,
143 			1, DUPLICATE_SAME_ACCESS) == FALSE) {
144 		perror("dup handle");
145 		Exit();
146 	}
147 
148 	return r;
149 }
150 
151 void
152 childadd(HANDLE h, int pid)
153 {
154 	int i;
155 
156 	for(i=0; i<Nchild; i++) {
157 		if(child[i].handle == 0) {
158 			child[i].handle = h;
159 			child[i].pid = pid;
160 			return;
161 		}
162 	}
163 	perror("child table full");
164 	Exit();
165 }
166 
167 static DWORD WINAPI
168 spinoff(HANDLE in, HANDLE out, char *args, char *cmd, Envy *e)
169 {
170 	char args2[4096], path[MAX_PATH], *s, *eb;
171 	STARTUPINFO si;
172 	PROCESS_INFORMATION pi;
173 	Symtab *sym;
174 
175 
176 		/* set up the full path of the shell */
177 	sym = symlook("MKSH", S_VAR, 0);
178 	if(sym){
179 		strncpy(path, ((Word*)(sym->value))->s, sizeof(path));
180 		path[MAX_PATH-1] = 0;
181 	}else{
182 		sym = symlook("ROOT", S_VAR, 0);
183 		if(sym)
184 			rootdir = ((Word*)(sym->value))->s;
185 		snprint(path, sizeof(path), "%s\\%s", rootdir, shell);
186 	}
187 		/* convert to backslash notation */
188 	for(s = strchr(path,'/'); s; s = strchr(s+1, '/'))
189 			*s = '\\';
190 
191 	s = args2;
192 	s += snprint(args2, sizeof(args2)-1, "%s", path);
193 	if(shflags)
194 		s += snprint(s, args2+sizeof(args2)-s-1, " %s", shflags);
195 	if(args)
196 		s += snprint(s, args2+sizeof(args2)-s-1, " %s", args);
197 	if(cmd)
198 		s += snprint(s, args2+sizeof(args2)-s-1, " \"%s\"", cmd);
199 
200 	memset(&si, 0, sizeof(si));
201 	si.cb = sizeof(si);
202 	si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
203 	si.wShowWindow = SW_SHOW;
204 
205 	if (e)
206 		eb = exportenv(e);
207 	else
208 		eb = 0;
209 	si.hStdInput = duphandle(in);
210 	si.hStdOutput = duphandle(out);
211 	si.hStdError = duphandle(GetStdHandle(STD_ERROR_HANDLE));
212 	if(CreateProcess(path, args2, 0, 0, 1, 0, eb, 0, &si, &pi) == FALSE) {
213 		perror("can't find shell");
214 		Exit();
215 	}
216 
217 	free(eb);
218 
219 	CloseHandle(si.hStdInput);
220 	CloseHandle(si.hStdOutput);
221 	CloseHandle(si.hStdError);
222 
223 	childadd(pi.hProcess, pi.dwProcessId);
224 	return pi.dwProcessId;
225 }
226 
227 int
228 execsh(char *args, char *cmd, Bufblock *buf, Envy *e)
229 {
230 	int tot, n, tid, pid;
231 	HANDLE outin, outout, inout, inin;
232 	struct { char *cmd; HANDLE handle; } *arg;
233 
234 	if(buf == 0)
235 		outout = GetStdHandle(STD_OUTPUT_HANDLE);
236 	else
237 	if(CreatePipe(&outin, &outout, 0, 0) == FALSE){
238 		perror("pipe");
239 		Exit();
240 	}
241 
242 	if(CreatePipe(&inin, &inout, 0, 0) == FALSE){
243 		perror("pipe");
244 		Exit();
245 	}
246 
247 	arg = malloc(sizeof(*arg));
248 	arg->cmd = strdup(cmd);
249 	arg->handle = inout;
250 	if(CreateThread(0, 0, writecmd, arg, 0, &tid) == FALSE) {
251 		perror("spawn writecmd");
252 		Exit();
253 	}
254 
255 	pid = spinoff(inin, outout, args, 0, e);
256 	CloseHandle(inin);
257 
258 	if(DEBUG(D_EXEC))
259 		fprint(1, "starting: %s\n", cmd);
260 
261 	if(buf){
262 		CloseHandle(outout);
263 		tot = 0;
264 		for(;;){
265 			if (buf->current >= buf->end)
266 				growbuf(buf);
267 			if(ReadFile(outin, buf->current, buf->end-buf->current, &n, 0) == FALSE)
268 				break;
269 			buf->current += n;
270 			tot += n;
271 		}
272 		if (tot && buf->current[-1] == '\n')
273 			buf->current--;
274 		CloseHandle(outin);
275 	}
276 
277 	return pid;
278 }
279 
280 static DWORD WINAPI
281 writecmd(LPVOID a)
282 {
283 	struct {char *cmd; HANDLE handle;} *arg;
284 	char *cmd, *p;
285 	int n;
286 
287 	arg = a;
288 	cmd = arg->cmd;
289 	p = cmd+strlen(cmd);
290 	while(cmd < p){
291 		if(WriteFile(arg->handle, cmd, p-cmd, &n, 0) == FALSE)
292 			break;
293 		cmd += n;
294 	}
295 
296 	free(arg->cmd);
297 	CloseHandle(arg->handle);
298 	free(arg);
299 	ExitThread(0);
300 	return 0;
301 }
302 
303 int
304 pipecmd(char *cmd, Envy *e, int *fd)
305 {
306 	int pid;
307 	HANDLE pipein, pipeout;
308 
309 	if(fd){
310 		if(CreatePipe(&pipein, &pipeout, 0, 0) == FALSE){
311 			perror("pipe");
312 			Exit();
313 		}
314 	} else
315 		pipeout = GetStdHandle(STD_OUTPUT_HANDLE);
316 
317 
318 	pid = spinoff(GetStdHandle(STD_INPUT_HANDLE), pipeout, "-c", cmd, e);
319 
320 	if(fd){
321 		CloseHandle(pipeout);
322 		*fd = _open_osfhandle((long)pipein, 0);
323 	}
324 	return pid;
325 }
326 
327 void
328 Exit(void)
329 {
330 	while(waitfor(0) != -1)
331 		;
332 	exits("error");
333 }
334 
335 void
336 catchnotes()
337 {
338 }
339 
340 char*
341 maketmp(void)
342 {
343 	static char temp[] = "mkargsXXXXXXXXXXX";
344 
345 	mktemp(temp);
346 	return temp;
347 }
348 
349 Dir*
350 mkdirstat(char *name)
351 {
352 	int c, n;
353 	Dir *buf;
354 
355 	n = strlen(name)-1;
356 	c = name[n];
357 	if(c == '/' || c == '\\')
358 		name[n] = 0;
359 	buf = dirstat(name);
360 	name[n] = c;
361 	return buf;
362 }
363 
364 int
365 chgtime(char *name)
366 {
367 	Dir *sbuf;
368 	struct utimbuf u;
369 
370 	if((sbuf = mkdirstat(name)) != nil){
371 		u.actime = sbuf->atime;
372 		u.modtime = time(0);
373 		free(sbuf);
374 		return utime(name, &u);
375 	}
376 	return close(create(name, OWRITE, 0666));
377 }
378 
379 void
380 rcopy(char **to, Resub *match, int n)
381 {
382 	int c;
383 	char *p;
384 
385 	*to = match->s.sp;		/* stem0 matches complete target */
386 	for(to++, match++; --n > 0; to++, match++){
387 		if(match->s.sp && match->e.ep){
388 			p = match->e.ep;
389 			c = *p;
390 			*p = 0;
391 			*to = strdup(match->s.sp);
392 			*p = c;
393 		} else
394 			*to = 0;
395 	}
396 }
397 
398 ulong
399 mkmtime(char *name)
400 {
401 	Dir *buf;
402 	ulong t;
403 	int n;
404 	char *s;
405 
406 	n = strlen(name)-1;
407 	if(n >= 0 && (name[n] == '/' || name[n] == '\\')){
408 		s = strdup(name);
409 		s[n] = 0;
410 	}else
411 		s = name;
412 	buf = dirstat(s);
413 	if(buf == nil){
414 		if(s != name)
415 			free(s);
416 		return 0;
417 	}
418 	t = buf->mtime;
419 	free(buf);
420 	if(s != name)
421 		free(s);
422 	return t;
423 }
424 
425 char *stab;
426 
427 char *
428 membername(char *s, int fd, char *sz)
429 {
430 	long t;
431 
432 	if(s[0] == '/' && s[1] == '\0'){	/* long file name string table */
433 		t = atol(sz);
434 		if(t&01) t++;
435 		stab = malloc(t);
436 		read(fd, stab, t);
437 		return nil;
438 	}
439 	else if(s[0] == '/' && stab != nil)		/* index into string table */
440 		return stab+atol(s+1);
441 	else
442 		return s;
443 }
444