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