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