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