xref: /plan9/sys/src/cmd/rc/plan9.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
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 void execmount(void);
32 void execnewpgrp(void);
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 	"rfork",	execnewpgrp,
45 	0
46 };
47 void execnewpgrp(void){
48 	int arg;
49 	char *s;
50 	switch(count(runq->argv->words)){
51 	case 1: arg=RFENVG|RFNAMEG|RFNOTEG; break;
52 	case 2:
53 		arg=0;
54 		for(s=runq->argv->words->next->word;*s;s++) switch(*s){
55 		default:
56 			goto Usage;
57 		case 'n': arg|=RFNAMEG;  break;
58 		case 'N': arg|=RFCNAMEG; break;
59 		case 'e': arg|=RFENVG;   break;
60 		case 'E': arg|=RFCENVG;  break;
61 		case 's': arg|=RFNOTEG;  break;
62 		case 'f': arg|=RFFDG;    break;
63 		case 'F': arg|=RFCFDG;   break;
64 		}
65 		break;
66 	default:
67 	Usage:
68 		pfmt(err, "Usage: %s [fnesFNE]\n", runq->argv->words->word);
69 		setstatus("rfork usage");
70 		poplist();
71 		return;
72 	}
73 	if(rfork(arg)==-1){
74 		pfmt(err, "rc: %s failed\n", runq->argv->words->word);
75 		setstatus("rfork failed");
76 	}
77 	else
78 		setstatus("");
79 	poplist();
80 }
81 void Vinit(void){
82 	int dir=open("#e", 0), f, len;
83 	word *val;
84 	char *buf, *s;
85 	Dir ent;
86 	char envname[NAMELEN+6];
87 	if(dir<0){
88 		pfmt(err, "rc: can't open #e\n");
89 		return;
90 	}
91 	while(dirread(dir, &ent, sizeof ent)==sizeof ent){
92 		len=ent.length;
93 		if(len && strncmp(ent.name, "fn#", 3)!=0){
94 			strcpy(envname, "#e/");
95 			strcat(envname, ent.name);
96 			if((f=open(envname, 0))>=0){
97 				buf=emalloc((int)len+1);
98 				read(f, buf, (long)len);
99 				val=0;
100 				/* Charitably add a 0 at the end if need be */
101 				if(buf[len-1]) buf[len++]='\0';
102 				s=buf+len-1;
103 				for(;;){
104 					while(s!=buf && s[-1]!='\0') --s;
105 					val=newword(s, val);
106 					if(s==buf) break;
107 					--s;
108 				}
109 				setvar(ent.name, val);
110 				vlook(ent.name)->changed=0;
111 				close(f);
112 				efree(buf);
113 			}
114 		}
115 	}
116 	close(dir);
117 }
118 #ifdef old_execfinit
119 void Xrdfn(void){}
120 void execfinit(void){
121 	Xpopm();
122 }
123 #else
124 int envdir;
125 void Xrdfn(void){
126 	int f, len;
127 	Dir ent;
128 	char envname[NAMELEN+6];
129 	while(dirread(envdir, &ent, sizeof ent)==sizeof ent){
130 		len=ent.length;
131 		if(len && strncmp(ent.name, "fn#", 3)==0){
132 			strcpy(envname, "#e/");
133 			strcat(envname, ent.name);
134 			if((f=open(envname, 0))>=0){
135 				execcmds(openfd(f));
136 				return;
137 			}
138 		}
139 	}
140 	close(envdir);
141 	Xreturn();
142 }
143 union code rdfns[4];
144 void execfinit(void){
145 	static int first=1;
146 	if(first){
147 		rdfns[0].i=1;
148 		rdfns[1].f=Xrdfn;
149 		rdfns[2].f=Xjump;
150 		rdfns[3].i=1;
151 		first=0;
152 	}
153 	Xpopm();
154 	envdir=open("#e", 0);
155 	if(envdir<0){
156 		pfmt(err, "rc: can't open #e\n");
157 		return;
158 	}
159 	start(rdfns, 1, runq->local);
160 }
161 #endif
162 int Waitfor(int pid, int persist){
163 	thread *p;
164 	Waitmsg w;
165 	int cpid;
166 	char errbuf[ERRLEN];
167 	while((cpid=wait(&w))>=0){
168 		if(pid==cpid){
169 			setstatus(w.msg);
170 			return 0;
171 		}
172 		for(p=runq->ret;p;p=p->ret)
173 			if(p->pid==cpid){
174 				p->pid=-1;
175 				strcpy(p->status, w.msg);
176 			}
177 	}
178 	errstr(errbuf);
179 	if(strcmp(errbuf, "interrupted")==0) return -1;
180 	return 0;
181 }
182 char **mkargv(word *a)
183 {
184 	char **argv=(char **)emalloc((count(a)+2)*sizeof(char *));
185 	char **argp=argv+1;	/* leave one at front for runcoms */
186 	for(;a;a=a->next) *argp++=a->word;
187 	*argp=0;
188 	return argv;
189 }
190 void addenv(var *v)
191 {
192 	char envname[NAMELEN+9];
193 	word *w;
194 	int f;
195 	io *fd;
196 	if(v->changed){
197 		v->changed=0;
198 		strcpy(envname, "#e/");
199 		strcat(envname, v->name);
200 		if((f=Creat(envname))<0)
201 			pfmt(err, "rc: can't open %s\n", envname);
202 		else{
203 			for(w=v->val;w;w=w->next)
204 				write(f, w->word, strlen(w->word)+1L);
205 			close(f);
206 		}
207 	}
208 	if(v->fnchanged){
209 		v->fnchanged=0;
210 		strcpy(envname, "#e/fn#");
211 		strcat(envname, v->name);
212 		if((f=Creat(envname))<0)
213 			pfmt(err, "rc: can't open %s\n", envname);
214 		else{
215 			if(v->fn){
216 				fd=openfd(f);
217 				pfmt(fd, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
218 				closeio(fd);
219 			}
220 			close(f);
221 		}
222 	}
223 }
224 void updenvlocal(var *v)
225 {
226 	if(v){
227 		updenvlocal(v->next);
228 		addenv(v);
229 	}
230 }
231 void Updenv(void){
232 	var *v, **h;
233 	for(h=gvar;h!=&gvar[NVAR];h++)
234 		for(v=*h;v;v=v->next)
235 			addenv(v);
236 	if(runq) updenvlocal(runq->local);
237 }
238 void Execute(word *args, word *path)
239 {
240 	char **argv=mkargv(args);
241 	char file[1024];
242 	int nc;
243 	Updenv();
244 	for(;path;path=path->next){
245 		nc=strlen(path->word);
246 		if(nc<1024){
247 			strcpy(file, path->word);
248 			if(file[0]){
249 				strcat(file, "/");
250 				nc++;
251 			}
252 			if(nc+strlen(argv[1])<1024){
253 				strcat(file, argv[1]);
254 				exec(file, argv+1);
255 			}
256 			else werrstr("command name too long");
257 		}
258 	}
259 	errstr(file);
260 	pfmt(err, "%s: %s\n", argv[1], file);
261 	efree((char *)argv);
262 }
263 int Globsize(char *p)
264 {
265 	ulong isglob=0, globlen=NAMELEN+1;
266 	for(;*p;p++){
267 		if(*p==GLOB){
268 			p++;
269 			if(*p!=GLOB) isglob++;
270 			globlen+=*p=='*'?NAMELEN:1;
271 		}
272 		else
273 			globlen++;
274 	}
275 	return isglob?globlen:0;
276 }
277 #define NFD	50
278 #define	NDBUF	32
279 struct{
280 	char	*buf;
281 	int	n;
282 }dir[NFD];
283 int Opendir(char *name)
284 {
285 	Dir db;
286 	int f;
287 	f=open(name, 0);
288 	if(f==-1)
289 		return f;
290 	if(dirfstat(f, &db)!=-1 && (db.mode&0x80000000)){
291 		if(f<NFD && dir[f].buf){
292 			free(dir[f].buf);
293 			dir[f].buf=0;
294 		}
295 		return f;
296 	}
297 	close(f);
298 	return -1;
299 }
300 int Readdir(int f, char *p)
301 {
302 	char dirent[DIRLEN];
303 	int n;
304 	if(f<0 || f>=NFD){
305    slow:
306 		while(read(f, dirent, sizeof dirent)==sizeof dirent){
307 			strcpy(p, dirent);
308 			return 1;
309 		}
310 		return 0;
311 	}
312 	if(dir[f].buf==0){	/* allocate */
313 		dir[f].buf=malloc(NDBUF*DIRLEN);
314 		if(dir[f].buf==0)
315 			goto slow;
316 		dir[f].n=0;
317 	}
318 	if(dir[f].n==0){	/* read */
319 		memset(dir[f].buf, 0, NDBUF*DIRLEN);
320 		n = read(f, dir[f].buf, NDBUF*DIRLEN);
321 		if(n>0 && n<NDBUF*DIRLEN){
322 			memmove(dir[f].buf+NDBUF*DIRLEN-n, dir[f].buf, n);
323 			dir[f].n=NDBUF-n/DIRLEN;
324 		}else
325 			dir[f].n=0;
326 	}
327 	if(dir[f].buf[dir[f].n*DIRLEN]==0)
328 		return 0;
329 	strcpy(p, &dir[f].buf[dir[f].n*DIRLEN]);
330 	dir[f].n++;
331 	if(dir[f].n==NDBUF)
332 		dir[f].n=0;
333 	return 1;
334 }
335 void Closedir(int f){
336 	if(f>=0 && f<NFD && dir[f].buf){
337 		free(dir[f].buf);
338 		dir[f].buf=0;
339 	}
340 	close(f);
341 }
342 int interrupted = 0;
343 void
344 notifyf(void *a, char *s)
345 {
346 	int i;
347 	for(i=0;syssigname[i];i++) if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){
348 		if(strncmp(s, "sys: ", 5)!=0) interrupted=1;
349 		goto Out;
350 	}
351 	pfmt(err, "rc: note: %s\n", s);
352 	noted(NDFLT);
353 	return;
354 Out:
355 	if(strcmp(s, "interrupt")!=0 || trap[i]==0){
356 		trap[i]++;
357 		ntrap++;
358 	}
359 	if(ntrap>=32){	/* rc is probably in a trap loop */
360 		pfmt(err, "rc: Too many traps (trap %s), aborting\n", s);
361 		abort();
362 	}
363 	noted(NCONT);
364 }
365 void Trapinit(void){
366 	notify(notifyf);
367 }
368 void Unlink(char *name)
369 {
370 	remove(name);
371 }
372 long Write(int fd, char *buf, long cnt)
373 {
374 	return write(fd, buf, (long)cnt);
375 }
376 long Read(int fd, char *buf, long cnt)
377 {
378 	int n;
379 
380 	return read(fd, buf, cnt);
381 }
382 long Seek(int fd, long cnt, int whence)
383 {
384 	return seek(fd, cnt, whence);
385 }
386 int Executable(char *file)
387 {
388 	Dir statbuf;
389 
390 	return dirstat(file, &statbuf)!=-1 && (statbuf.mode&0111)!=0 && (statbuf.mode&CHDIR)==0;
391 }
392 int Creat(char *file)
393 {
394 	return create(file, 1, 0666L);
395 }
396 int Dup(int a, int b){
397 	return dup(a, b);
398 }
399 int Dup1(int a){
400 	return -1;
401 }
402 void Exit(char *stat)
403 {
404 	Updenv();
405 	setstatus(stat);
406 	exits(truestatus()?"":getstatus());
407 }
408 int Eintr(void){
409 	return interrupted;
410 }
411 void Noerror(void){
412 	interrupted=0;
413 }
414 int Isatty(int fd){
415 	Dir d1, d2;
416 
417 	if(dirfstat(0, &d1)==-1) return 0;
418 	if(strncmp(d1.name, "ptty", 4)==0) return 1;	/* fwd complaints to philw */
419 	if(dirstat("/dev/cons", &d2)==-1) return 0;
420 	return d1.type==d2.type&&d1.dev==d2.dev&&d1.qid.path==d2.qid.path;
421 }
422 void Abort(void){
423 	pfmt(err, "aborting\n");
424 	flush(err);
425 	Exit("aborting");
426 }
427 void Memcpy(char *a, char *b, long n)
428 {
429 	memmove(a, b, (long)n);
430 }
431 void *Malloc(ulong n){
432 	return malloc(n);
433 }
434 char *Geterrstr(void){
435 	static char error[ERRLEN];
436 	error[0]='\0';
437 	errstr(error);
438 	return error;
439 }
440