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