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(void)28 Rcmain(void)
29 {
30 	return unsharp("#9/etc/rcmain");
31 }
32 
33 char Fdprefix[]="/dev/fd/";
34 long readnb(int, char *, long);
35 void execfinit(void);
36 void execbind(void);
37 void execmount(void);
38 void execulimit(void);
39 void execumask(void);
40 void execrfork(void);
41 builtin Builtin[]={
42 	"cd",		execcd,
43 	"whatis",	execwhatis,
44 	"eval",		execeval,
45 	"exec",		execexec,	/* but with popword first */
46 	"exit",		execexit,
47 	"shift",	execshift,
48 	"wait",		execwait,
49 	".",		execdot,
50 	"finit",	execfinit,
51 	"flag",		execflag,
52 	"ulimit",	execulimit,
53 	"umask",	execumask,
54 	"rfork",	execrfork,
55 	0
56 };
57 
58 void
execrfork(void)59 execrfork(void)
60 {
61 	int arg;
62 	char *s;
63 
64 	switch(count(runq->argv->words)){
65 	case 1:
66 		arg = RFENVG|RFNOTEG|RFNAMEG;
67 		break;
68 	case 2:
69 		arg = 0;
70 		for(s = runq->argv->words->next->word;*s;s++) switch(*s){
71 		default:
72 			goto Usage;
73 		case 'n':
74 			arg|=RFNAMEG;  break;
75 		case 'N':
76 			arg|=RFCNAMEG;
77 			break;
78 		case 'e':
79 			/* arg|=RFENVG; */  break;
80 		case 'E':
81 			arg|=RFCENVG;  break;
82 		case 's':
83 			arg|=RFNOTEG;  break;
84 		case 'f':
85 			arg|=RFFDG;    break;
86 		case 'F':
87 			arg|=RFCFDG;   break;
88 		}
89 		break;
90 	default:
91 	Usage:
92 		pfmt(err, "Usage: %s [nNeEsfF]\n", runq->argv->words->word);
93 		setstatus("rfork usage");
94 		poplist();
95 		return;
96 	}
97 	if(rfork(arg)==-1){
98 		pfmt(err, "rc: %s failed\n", runq->argv->words->word);
99 		setstatus("rfork failed");
100 	}
101 	else
102 		setstatus("");
103 	poplist();
104 }
105 
106 
107 
108 #define	SEP	'\1'
109 char **environp;
enval(s)110 struct word *enval(s)
111 register char *s;
112 {
113 	register char *t, c;
114 	register struct word *v;
115 	for(t=s;*t && *t!=SEP;t++);
116 	c=*t;
117 	*t='\0';
118 	v=newword(s, c=='\0'?(struct word *)0:enval(t+1));
119 	*t=c;
120 	return v;
121 }
Vinit(void)122 void Vinit(void){
123 	extern char **environ;
124 	register char *s;
125 	register char **env=environ;
126 	environp=env;
127 	for(;*env;env++){
128 		for(s=*env;*s && *s!='(' && *s!='=';s++);
129 		switch(*s){
130 		case '\0':
131 		/*	pfmt(err, "rc: odd environment %q?\n", *env); */
132 			break;
133 		case '=':
134 			*s='\0';
135 			setvar(*env, enval(s+1));
136 			*s='=';
137 			break;
138 		case '(':	/* ignore functions for now */
139 			break;
140 		}
141 	}
142 }
143 char **envp;
Xrdfn(void)144 void Xrdfn(void){
145 	char *p;
146 	register char *s;
147 	register int len;
148 	for(;*envp;envp++){
149 		s = *envp;
150 		if(strncmp(s, "fn#", 3) == 0){
151 			p = strchr(s, '=');
152 			if(p == nil)
153 				continue;
154 			*p = ' ';
155 			s[2] = ' ';
156 			len = strlen(s);
157 			execcmds(opencore(s, len));
158 			s[len] = '\0';
159 			return;
160 		}
161 #if 0
162 		for(s=*envp;*s && *s!='(' && *s!='=';s++);
163 		switch(*s){
164 		case '\0':
165 			pfmt(err, "environment %q?\n", *envp);
166 			break;
167 		case '=':	/* ignore variables */
168 			break;
169 		case '(':		/* Bourne again */
170 			s=*envp+3;
171 			envp++;
172 			len=strlen(s);
173 			s[len]='\n';
174 			execcmds(opencore(s, len+1));
175 			s[len]='\0';
176 			return;
177 		}
178 #endif
179 	}
180 	Xreturn();
181 }
182 union code rdfns[4];
execfinit(void)183 void execfinit(void){
184 	static int first=1;
185 	if(first){
186 		rdfns[0].i=1;
187 		rdfns[1].f=Xrdfn;
188 		rdfns[2].f=Xjump;
189 		rdfns[3].i=1;
190 		first=0;
191 	}
192 	Xpopm();
193 	envp=environp;
194 	start(rdfns, 1, runq->local);
195 }
196 extern int mapfd(int);
Waitfor(int pid,int unused0)197 int Waitfor(int pid, int unused0){
198 	thread *p;
199 	Waitmsg *w;
200 	char errbuf[ERRMAX];
201 
202 	if(pid >= 0 && !havewaitpid(pid))
203 		return 0;
204 	while((w = wait()) != nil){
205 		delwaitpid(w->pid);
206 		if(w->pid==pid){
207 			if(strncmp(w->msg, "signal: ", 8) == 0)
208 				fprint(mapfd(2), "%d: %s\n", w->pid, w->msg);
209 			setstatus(w->msg);
210 			free(w);
211 			return 0;
212 		}
213 		if(runq->iflag && strncmp(w->msg, "signal: ", 8) == 0)
214 			fprint(2, "%d: %s\n", w->pid, w->msg);
215 		for(p=runq->ret;p;p=p->ret)
216 			if(p->pid==w->pid){
217 				p->pid=-1;
218 				strcpy(p->status, w->msg);
219 			}
220 		free(w);
221 	}
222 
223 	rerrstr(errbuf, sizeof errbuf);
224 	if(strcmp(errbuf, "interrupted")==0) return -1;
225 	return 0;
226 }
mkargv(word * a)227 char **mkargv(word *a)
228 {
229 	char **argv=(char **)emalloc((count(a)+2)*sizeof(char *));
230 	char **argp=argv+1;	/* leave one at front for runcoms */
231 	for(;a;a=a->next) *argp++=a->word;
232 	*argp=0;
233 	return argv;
234 }
235 /*
236 void addenv(var *v)
237 {
238 	char envname[256];
239 	word *w;
240 	int f;
241 	io *fd;
242 	if(v->changed){
243 		v->changed=0;
244 		snprint(envname, sizeof envname, "/env/%s", v->name);
245 		if((f=Creat(envname))<0)
246 			pfmt(err, "rc: can't open %s: %r\n", envname);
247 		else{
248 			for(w=v->val;w;w=w->next)
249 				write(f, w->word, strlen(w->word)+1L);
250 			close(f);
251 		}
252 	}
253 	if(v->fnchanged){
254 		v->fnchanged=0;
255 		snprint(envname, sizeof envname, "/env/fn#%s", v->name);
256 		if((f=Creat(envname))<0)
257 			pfmt(err, "rc: can't open %s: %r\n", envname);
258 		else{
259 			if(v->fn){
260 				fd=openfd(f);
261 				pfmt(fd, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
262 				closeio(fd);
263 			}
264 			close(f);
265 		}
266 	}
267 }
268 void updenvlocal(var *v)
269 {
270 	if(v){
271 		updenvlocal(v->next);
272 		addenv(v);
273 	}
274 }
275 void Updenv(void){
276 	var *v, **h;
277 	for(h=gvar;h!=&gvar[NVAR];h++)
278 		for(v=*h;v;v=v->next)
279 			addenv(v);
280 	if(runq) updenvlocal(runq->local);
281 }
282 */
283 int
cmpenv(const void * a,const void * b)284 cmpenv(const void *a, const void *b)
285 {
286 	return strcmp(*(char**)a, *(char**)b);
287 }
mkenv()288 char **mkenv(){
289 	register char **env, **ep, *p, *q;
290 	register struct var **h, *v;
291 	register struct word *a;
292 	register int nvar=0, nchr=0, sep;
293 	/*
294 	 * Slightly kludgy loops look at locals then globals
295 	 */
296 	for(h=gvar-1;h!=&gvar[NVAR];h++) for(v=h>=gvar?*h:runq->local;v;v=v->next){
297 		if((v==vlook(v->name)) && v->val){
298 			nvar++;
299 			nchr+=strlen(v->name)+1;
300 			for(a=v->val;a;a=a->next)
301 				nchr+=strlen(a->word)+1;
302 		}
303 		if(v->fn){
304 			nvar++;
305 			nchr+=strlen(v->name)+strlen(v->fn[v->pc-1].s)+8;
306 		}
307 	}
308 	env=(char **)emalloc((nvar+1)*sizeof(char *)+nchr);
309 	ep=env;
310 	p=(char *)&env[nvar+1];
311 	for(h=gvar-1;h!=&gvar[NVAR];h++) for(v=h>=gvar?*h:runq->local;v;v=v->next){
312 		if((v==vlook(v->name)) && v->val){
313 			*ep++=p;
314 			q=v->name;
315 			while(*q) *p++=*q++;
316 			sep='=';
317 			for(a=v->val;a;a=a->next){
318 				*p++=sep;
319 				sep=SEP;
320 				q=a->word;
321 				while(*q) *p++=*q++;
322 			}
323 			*p++='\0';
324 		}
325 		if(v->fn){
326 			*ep++=p;
327 #if 0
328 			*p++='#'; *p++='('; *p++=')';	/* to fool Bourne */
329 			*p++='f'; *p++='n'; *p++=' ';
330 			q=v->name;
331 			while(*q) *p++=*q++;
332 			*p++=' ';
333 #endif
334 			*p++='f'; *p++='n'; *p++='#';
335 			q=v->name;
336 			while(*q) *p++=*q++;
337 			*p++='=';
338 			q=v->fn[v->pc-1].s;
339 			while(*q) *p++=*q++;
340 			*p++='\n';
341 			*p++='\0';
342 		}
343 	}
344 	*ep=0;
345 	qsort((char *)env, nvar, sizeof ep[0], cmpenv);
346 	return env;
347 }
Updenv(void)348 void Updenv(void){}
Execute(word * args,word * path)349 void Execute(word *args, word *path)
350 {
351 	char **argv=mkargv(args);
352 	char **env=mkenv();
353 	char file[1024];
354 	int nc;
355 	Updenv();
356 	for(;path;path=path->next){
357 		nc=strlen(path->word);
358 		if(nc<1024){
359 			strcpy(file, path->word);
360 			if(file[0]){
361 				strcat(file, "/");
362 				nc++;
363 			}
364 			if(nc+strlen(argv[1])<1024){
365 				strcat(file, argv[1]);
366 				execve(file, argv+1, env);
367 			}
368 			else werrstr("command name too long");
369 		}
370 	}
371 	rerrstr(file, sizeof file);
372 	pfmt(err, "%s: %s\n", argv[1], file);
373 	efree((char *)argv);
374 }
375 #define	NDIR	256		/* shoud be a better way */
Globsize(char * p)376 int Globsize(char *p)
377 {
378 	ulong isglob=0, globlen=NDIR+1;
379 	for(;*p;p++){
380 		if(*p==GLOB){
381 			p++;
382 			if(*p!=GLOB) isglob++;
383 			globlen+=*p=='*'?NDIR:1;
384 		}
385 		else
386 			globlen++;
387 	}
388 	return isglob?globlen:0;
389 }
390 #define	NFD	50
391 #define	NDBUF	32
392 struct{
393 	Dir	*dbuf;
394 	int	i;
395 	int	n;
396 }dir[NFD];
Opendir(char * name)397 int Opendir(char *name)
398 {
399 	Dir *db;
400 	int f;
401 	f=open(name, 0);
402 	if(f==-1)
403 		return f;
404 	db = dirfstat(f);
405 	if(db!=nil && (db->mode&DMDIR)){
406 		if(f<NFD){
407 			dir[f].i=0;
408 			dir[f].n=0;
409 		}
410 		free(db);
411 		return f;
412 	}
413 	free(db);
414 	close(f);
415 	return -1;
416 }
Readdir(int f,char * p,int onlydirs)417 int Readdir(int f, char *p, int onlydirs)
418 {
419 	int n;
420 	USED(onlydirs);	/* only advisory */
421 
422 	if(f<0 || f>=NFD)
423 		return 0;
424 	if(dir[f].i==dir[f].n){	/* read */
425 		free(dir[f].dbuf);
426 		dir[f].dbuf=0;
427 		n=dirread(f, &dir[f].dbuf);
428 		if(n>=0)
429 			dir[f].n=n;
430 		else
431 			dir[f].n=0;
432 		dir[f].i=0;
433 	}
434 	if(dir[f].i==dir[f].n)
435 		return 0;
436 	strcpy(p, dir[f].dbuf[dir[f].i].name);
437 	dir[f].i++;
438 	return 1;
439 }
Closedir(int f)440 void Closedir(int f){
441 	if(f>=0 && f<NFD){
442 		free(dir[f].dbuf);
443 		dir[f].i=0;
444 		dir[f].n=0;
445 		dir[f].dbuf=0;
446 	}
447 	close(f);
448 }
449 int interrupted = 0;
450 void
notifyf(void * unused0,char * s)451 notifyf(void *unused0, char *s)
452 {
453 	int i;
454 	for(i=0;syssigname[i];i++)
455 		if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){
456 			if(strncmp(s, "sys: ", 5)!=0){
457 				if(kidpid && !interrupted){
458 					interrupted=1;
459 					postnote(PNGROUP, kidpid, s);
460 				}
461 				interrupted = 1;
462 			}
463 			goto Out;
464 		}
465 	if(strcmp(s, "sys: window size change") != 0)
466 	if(strcmp(s, "sys: write on closed pipe") != 0)
467 	if(strcmp(s, "sys: child") != 0)
468 		pfmt(err, "rc: note: %s\n", s);
469 	noted(NDFLT);
470 	return;
471 Out:
472 	if(strcmp(s, "interrupt")!=0 || trap[i]==0){
473 		trap[i]++;
474 		ntrap++;
475 	}
476 	if(ntrap>=32){	/* rc is probably in a trap loop */
477 		pfmt(err, "rc: Too many traps (trap %s), aborting\n", s);
478 		abort();
479 	}
480 	noted(NCONT);
481 }
Trapinit(void)482 void Trapinit(void){
483 	notify(notifyf);
484 }
Unlink(char * name)485 void Unlink(char *name)
486 {
487 	remove(name);
488 }
Write(int fd,char * buf,long cnt)489 long Write(int fd, char *buf, long cnt)
490 {
491 	return write(fd, buf, (long)cnt);
492 }
Read(int fd,char * buf,long cnt)493 long Read(int fd, char *buf, long cnt)
494 {
495 	int i;
496 
497 	i = readnb(fd, buf, cnt);
498 	if(ntrap) dotrap();
499 	return i;
500 }
Seek(int fd,long cnt,long whence)501 long Seek(int fd, long cnt, long whence)
502 {
503 	return seek(fd, cnt, whence);
504 }
Executable(char * file)505 int Executable(char *file)
506 {
507 	Dir *statbuf;
508 	int ret;
509 
510 	statbuf = dirstat(file);
511 	if(statbuf == nil) return 0;
512 	ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0);
513 	free(statbuf);
514 	return ret;
515 }
Creat(char * file)516 int Creat(char *file)
517 {
518 	return create(file, 1, 0666L);
519 }
Dup(int a,int b)520 int Dup(int a, int b){
521 	return dup(a, b);
522 }
Dup1(int a)523 int Dup1(int a){
524 	return dup(a, -1);
525 }
Exit(char * stat)526 void Exit(char *stat)
527 {
528 	Updenv();
529 	setstatus(stat);
530 	exits(truestatus()?"":getstatus());
531 }
Eintr(void)532 int Eintr(void){
533 	return interrupted;
534 }
Noerror(void)535 void Noerror(void){
536 	interrupted=0;
537 }
538 int
Isatty(int fd)539 Isatty(int fd){
540 	return isatty(fd);
541 }
Abort(void)542 void Abort(void){
543 	pfmt(err, "aborting\n");
544 	flush(err);
545 	Exit("aborting");
546 }
Memcpy(char * a,char * b,long n)547 void Memcpy(char *a, char *b, long n)
548 {
549 	memmove(a, b, (long)n);
550 }
Malloc(ulong n)551 void *Malloc(ulong n){
552 	return malloc(n);
553 }
554 
555 int
exitcode(char * msg)556 exitcode(char *msg)
557 {
558 	int n;
559 
560 	n = atoi(msg);
561 	if(n == 0)
562 		n = 1;
563 	return n;
564 }
565 
566 int *waitpids;
567 int nwaitpids;
568 
569 void
addwaitpid(int pid)570 addwaitpid(int pid)
571 {
572 	waitpids = realloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]);
573 	if(waitpids == 0)
574 		panic("Can't realloc %d waitpids", nwaitpids+1);
575 	waitpids[nwaitpids++] = pid;
576 }
577 
578 void
delwaitpid(int pid)579 delwaitpid(int pid)
580 {
581 	int r, w;
582 
583 	for(r=w=0; r<nwaitpids; r++)
584 		if(waitpids[r] != pid)
585 			waitpids[w++] = waitpids[r];
586 	nwaitpids = w;
587 }
588 
589 void
clearwaitpids(void)590 clearwaitpids(void)
591 {
592 	nwaitpids = 0;
593 }
594 
595 int
havewaitpid(int pid)596 havewaitpid(int pid)
597 {
598 	int i;
599 
600 	for(i=0; i<nwaitpids; i++)
601 		if(waitpids[i] == pid)
602 			return 1;
603 	return 0;
604 }
605