xref: /plan9/sys/src/cmd/rc/win32.c (revision f9e1cf08d3be51592e03e639fc848a68dc31a55e)
1 /*
2  * Plan 9 versions of system-specific functions
3  *	By convention, exported routines herein have names beginning with an
4  *	upper case letter.
5  */
6 #include "rc.h"
7 #include "exec.h"
8 #include "io.h"
9 #include "fns.h"
10 #include "getflags.h"
11 char *Signame[] = {
12 	"sigexit",	"sighup",	"sigint",	"sigquit",
13 	"sigalrm",	"sigkill",	"sigfpe",	"sigterm",
14 	0
15 };
16 char *syssigname[] = {
17 	"exit",		/* can't happen */
18 	"hangup",
19 	"interrupt",
20 	"quit",		/* can't happen */
21 	"alarm",
22 	"kill",
23 	"sys: fp: ",
24 	"term",
25 	0
26 };
27 char Rcmain[]="/rc/lib/rcmain";
28 char Fdprefix[]="/fd/";
29 void execfinit(void);
30 void execbind(void);
31 
32 builtin Builtin[] = {
33 	"cd",		execcd,
34 	"whatis",	execwhatis,
35 	"eval",		execeval,
36 	"exec",		execexec,	/* but with popword first */
37 	"exit",		execexit,
38 	"shift",	execshift,
39 	"wait",		execwait,
40 	".",		execdot,
41 	"finit",	execfinit,
42 	"flag",		execflag,
43 	0
44 };
45 
46 void
47 Vinit(void)
48 {
49 	int dir, f, len;
50 	word *val;
51 	char *buf, *s;
52 	Dir *ent;
53 	int i, nent;
54 	char envname[256];
55 	dir = open("/env", OREAD);
56 	if(dir<0){
57 		pfmt(err, "rc: can't open /env: %r\n");
58 		return;
59 	}
60 	ent = nil;
61 	for(;;){
62 		nent = dirread(dir, &ent);
63 		if(nent <= 0)
64 			break;
65 		for(i = 0; i<nent; i++){
66 			len = ent[i].length;
67 			if(len && strncmp(ent[i].name, "fn#", 3)!=0){
68 				snprint(envname, sizeof envname, "/env/%s", ent[i].name);
69 				if((f = open(envname, 0))>=0){
70 					buf = emalloc((int)len+1);
71 					read(f, buf, (long)len);
72 					val = 0;
73 					/* Charitably add a 0 at the end if need be */
74 					if(buf[len-1])
75 						buf[len++]='\0';
76 					s = buf+len-1;
77 					for(;;){
78 						while(s!=buf && s[-1]!='\0') --s;
79 						val = newword(s, val);
80 						if(s==buf)
81 							break;
82 						--s;
83 					}
84 					setvar(ent[i].name, val);
85 					vlook(ent[i].name)->changed = 0;
86 					close(f);
87 					efree(buf);
88 				}
89 			}
90 		}
91 		free(ent);
92 	}
93 	close(dir);
94 }
95 int envdir;
96 
97 void
98 Xrdfn(void)
99 {
100 	int f, len;
101 	static Dir *ent, *allocent;
102 	static int nent;
103 	Dir *e;
104 	char envname[256];
105 
106 	for(;;){
107 		if(nent == 0){
108 			free(allocent);
109 			nent = dirread(envdir, &allocent);
110 			ent = allocent;
111 		}
112 		if(nent <= 0)
113 			break;
114 		while(nent){
115 			e = ent++;
116 			nent--;
117 			len = e->length;
118 			if(len && strncmp(e->name, "fn#", 3)==0){
119 				snprint(envname, sizeof envname, "/env/%s", e->name);
120 				if((f = open(envname, 0))>=0){
121 					execcmds(openfd(f));
122 					return;
123 				}
124 			}
125 		}
126 	}
127 	close(envdir);
128 	Xreturn();
129 }
130 union code rdfns[4];
131 
132 void
133 execfinit(void)
134 {
135 	static int first = 1;
136 	if(first){
137 		rdfns[0].i = 1;
138 		rdfns[1].f = Xrdfn;
139 		rdfns[2].f = Xjump;
140 		rdfns[3].i = 1;
141 		first = 0;
142 	}
143 	Xpopm();
144 	envdir = open("/env", 0);
145 	if(envdir<0){
146 		pfmt(err, "rc: can't open /env: %r\n");
147 		return;
148 	}
149 	start(rdfns, 1, runq->local);
150 }
151 
152 int
153 Waitfor(int pid, int persist)
154 {
155 	thread *p;
156 	Waitmsg *w;
157 	char errbuf[ERRMAX];
158 
159 	while((w = wait()) != nil){
160 		if(w->pid==pid){
161 			setstatus(w->msg);
162 			free(w);
163 			return 0;
164 		}
165 		for(p = runq->ret;p;p = p->ret)
166 			if(p->pid==w->pid){
167 				p->pid=-1;
168 				strcpy(p->status, w->msg);
169 			}
170 		free(w);
171 	}
172 
173 	errstr(errbuf, sizeof errbuf);
174 	if(strcmp(errbuf, "interrupted")==0) return -1;
175 	return 0;
176 }
177 
178 char*
179 *mkargv(word *a)
180 {
181 	char **argv = (char **)emalloc((count(a)+2)*sizeof(char *));
182 	char **argp = argv+1;	/* leave one at front for runcoms */
183 	for(;a;a = a->next) *argp++=a->word;
184 	*argp = 0;
185 	return argv;
186 }
187 
188 void
189 addenv(var *v)
190 {
191 	char envname[256];
192 	word *w;
193 	int f;
194 	io *fd;
195 	if(v->changed){
196 		v->changed = 0;
197 		snprint(envname, sizeof envname, "/env/%s", v->name);
198 		if((f = Creat(envname))<0)
199 			pfmt(err, "rc: can't open %s: %r\n", envname);
200 		else{
201 			for(w = v->val;w;w = w->next)
202 				write(f, w->word, strlen(w->word)+1L);
203 			close(f);
204 		}
205 	}
206 	if(v->fnchanged){
207 		v->fnchanged = 0;
208 		snprint(envname, sizeof envname, "/env/fn#%s", v->name);
209 		if((f = Creat(envname))<0)
210 			pfmt(err, "rc: can't open %s: %r\n", envname);
211 		else{
212 			if(v->fn){
213 				fd = openfd(f);
214 				pfmt(fd, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
215 				closeio(fd);
216 			}
217 			close(f);
218 		}
219 	}
220 }
221 
222 void
223 updenvlocal(var *v)
224 {
225 	if(v){
226 		updenvlocal(v->next);
227 		addenv(v);
228 	}
229 }
230 
231 void
232 Updenv(void)
233 {
234 	var *v, **h;
235 	for(h = gvar;h!=&gvar[NVAR];h++)
236 		for(v=*h;v;v = v->next)
237 			addenv(v);
238 	if(runq)
239 		updenvlocal(runq->local);
240 }
241 
242 int
243 ForkExecute(char *file, char **argv, int sin, int sout, int serr)
244 {
245 	int pid;
246 
247 {int i;
248 fprint(2, "forkexec %s", file);
249 for(i = 0; argv[i]; i++)fprint(2, " %s", argv[i]);
250 fprint(2, " %d %d %d\n", sin, sout, serr);
251 }
252 	if(access(file, 1) != 0)
253 		return -1;
254 fprint(2, "forking\n");
255 	switch(pid = fork()){
256 	case -1:
257 		return -1;
258 	case 0:
259 		if(sin >= 0)
260 			dup(sin, 0);
261 		else
262 			close(0);
263 		if(sout >= 0)
264 			dup(sout, 1);
265 		else
266 			close(1);
267 		if(serr >= 0)
268 			dup(serr, 2);
269 		else
270 			close(2);
271 fprint(2, "execing\n");
272 		exec(file, argv);
273 fprint(2, "exec: %r\n");
274 		exits(file);
275 	}
276 	return pid;
277 }
278 
279 void
280 Execute(word *args, word *path)
281 {
282 	char **argv = mkargv(args);
283 	char file[1024];
284 	int nc;
285 	Updenv();
286 	for(;path;path = path->next){
287 		nc = strlen(path->word);
288 		if(nc<1024){
289 			strcpy(file, path->word);
290 			if(file[0]){
291 				strcat(file, "/");
292 				nc++;
293 			}
294 			if(nc+strlen(argv[1])<1024){
295 				strcat(file, argv[1]);
296 				exec(file, argv+1);
297 			}
298 			else werrstr("command name too long");
299 		}
300 	}
301 	rerrstr(file, sizeof file);
302 	pfmt(err, "%s: %s\n", argv[1], file);
303 	efree((char *)argv);
304 }
305 #define	NDIR	256		/* shoud be a better way */
306 
307 int
308 Globsize(char *p)
309 {
310 	int isglob = 0, globlen = NDIR+1;
311 	for(;*p;p++){
312 		if(*p==GLOB){
313 			p++;
314 			if(*p!=GLOB)
315 				isglob++;
316 			globlen+=*p=='*'?NDIR:1;
317 		}
318 		else
319 			globlen++;
320 	}
321 	return isglob?globlen:0;
322 }
323 #define	NFD	50
324 #define	NDBUF	32
325 struct{
326 	Dir	*dbuf;
327 	int	i;
328 	int	n;
329 }dir[NFD];
330 
331 int
332 Opendir(char *name)
333 {
334 	Dir *db;
335 	int f;
336 	f = open(name, 0);
337 	if(f==-1)
338 		return f;
339 	db = dirfstat(f);
340 	if(db!=nil && (db->mode&DMDIR)){
341 		if(f<NFD){
342 			dir[f].i = 0;
343 			dir[f].n = 0;
344 		}
345 		free(db);
346 		return f;
347 	}
348 	free(db);
349 	close(f);
350 	return -1;
351 }
352 
353 static int
354 trimdirs(Dir *d, int nd)
355 {
356 	int r, w;
357 
358 	for(r=w=0; r<nd; r++)
359 		if(d[r].mode&DMDIR)
360 			d[w++] = d[r];
361 	return w;
362 }
363 
364 /*
365  * onlydirs is advisory -- it means you only
366  * need to return the directories.  it's okay to
367  * return files too (e.g., on unix where you can't
368  * tell during the readdir), but that just makes
369  * the globber work harder.
370  */
371 int
372 Readdir(int f, void *p, int onlydirs)
373 {
374 	int n;
375 
376 	if(f<0 || f>=NFD)
377 		return 0;
378 Again:
379 	if(dir[f].i==dir[f].n){	/* read */
380 		free(dir[f].dbuf);
381 		dir[f].dbuf = 0;
382 		n = dirread(f, &dir[f].dbuf);
383 		if(n>0){
384 			if(onlydirs){
385 				n = trimdirs(dir[f].dbuf, n);
386 				if(n == 0)
387 					goto Again;
388 			}
389 			dir[f].n = n;
390 		}else
391 			dir[f].n = 0;
392 		dir[f].i = 0;
393 	}
394 	if(dir[f].i == dir[f].n)
395 		return 0;
396 	strcpy(p, dir[f].dbuf[dir[f].i].name);
397 	dir[f].i++;
398 	return 1;
399 }
400 
401 void
402 Closedir(int f)
403 {
404 	if(f>=0 && f<NFD){
405 		free(dir[f].dbuf);
406 		dir[f].i = 0;
407 		dir[f].n = 0;
408 		dir[f].dbuf = 0;
409 	}
410 	close(f);
411 }
412 int interrupted = 0;
413 void
414 notifyf(void*, char *s)
415 {
416 	int i;
417 	for(i = 0;syssigname[i];i++) if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){
418 		if(strncmp(s, "sys: ", 5)!=0) interrupted = 1;
419 		goto Out;
420 	}
421 	pfmt(err, "rc: note: %s\n", s);
422 	noted(NDFLT);
423 	return;
424 Out:
425 	if(strcmp(s, "interrupt")!=0 || trap[i]==0){
426 		trap[i]++;
427 		ntrap++;
428 	}
429 	if(ntrap>=32){	/* rc is probably in a trap loop */
430 		pfmt(err, "rc: Too many traps (trap %s), aborting\n", s);
431 		abort();
432 	}
433 	noted(NCONT);
434 }
435 
436 void
437 Trapinit(void)
438 {
439 	notify(notifyf);
440 }
441 
442 void
443 Unlink(char *name)
444 {
445 	remove(name);
446 }
447 
448 long
449 Write(int fd, void *buf, long cnt)
450 {
451 	return write(fd, buf, (long)cnt);
452 }
453 
454 long
455 Read(int fd, void *buf, long cnt)
456 {
457 	return read(fd, buf, cnt);
458 }
459 
460 long
461 Seek(int fd, long cnt, long whence)
462 {
463 	return seek(fd, cnt, whence);
464 }
465 
466 int
467 Executable(char *file)
468 {
469 	Dir *statbuf;
470 	int ret;
471 
472 	statbuf = dirstat(file);
473 	if(statbuf == nil)
474 		return 0;
475 	ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0);
476 	free(statbuf);
477 	return ret;
478 }
479 
480 int
481 Creat(char *file)
482 {
483 	return create(file, 1, 0666L);
484 }
485 
486 int
487 Dup(int a, int b)
488 {
489 	return dup(a, b);
490 }
491 
492 int
493 Dup1(int)
494 {
495 	return -1;
496 }
497 
498 void
499 Exit(char *stat)
500 {
501 	Updenv();
502 	setstatus(stat);
503 	exits(truestatus()?"":getstatus());
504 }
505 
506 int
507 Eintr(void)
508 {
509 	return interrupted;
510 }
511 
512 void
513 Noerror(void)
514 {
515 	interrupted = 0;
516 }
517 
518 int
519 Isatty(int fd)
520 {
521 	Dir *d1, *d2;
522 	int ret;
523 
524 	d1 = dirfstat(fd);
525 	if(d1 == nil)
526 		return 0;
527 	if(strncmp(d1->name, "ptty", 4)==0){	/* fwd complaints to philw */
528 		free(d1);
529 		return 1;
530 	}
531 	d2 = dirstat("/dev/cons");
532 	if(d2 == nil){
533 		free(d1);
534 		return 0;
535 	}
536 	ret = (d1->type==d2->type&&d1->dev==d2->dev&&d1->qid.path==d2->qid.path);
537 	free(d1);
538 	free(d2);
539 	return ret;
540 }
541 
542 void
543 Abort(void)
544 {
545 	pfmt(err, "aborting\n");
546 	flush(err);
547 	Exit("aborting");
548 }
549 
550 void
551 Memcpy(void *a, void *b, long n)
552 {
553 	memmove(a, b, n);
554 }
555 
556 void*
557 Malloc(ulong n)
558 {
559 	return malloc(n);
560 }
561