xref: /plan9/sys/src/cmd/rc/unix.c (revision 3e12c5d1bb89fc02707907988834ef147769ddaf)
1 /*
2  * Unix 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 <errno.h>
9 char Rcmain[]="/usr/lib/rcmain";
10 char Fdprefix[]="/dev/fd/";
11 int execumask(), execfinit();
12 struct builtin Builtin[]={
13 	"cd",		execcd,
14 	"whatis",	execwhatis,
15 	"eval",		execeval,
16 	"exec",		execexec,	/* but with popword first */
17 	"exit",		execexit,
18 	"shift",	execshift,
19 	"wait",		execwait,
20 	"umask",	execumask,
21 	".",		execdot,
22 	"finit",	execfinit,
23 	"flag",		execflag,
24 	0
25 };
26 #define	SEP	'\1'
27 char **environp;
28 struct word *enval(s)
29 register char *s;
30 {
31 	register char *t, c;
32 	register struct word *v;
33 	for(t=s;*t && *t!=SEP;t++);
34 	c=*t;
35 	*t='\0';
36 	v=newword(s, c=='\0'?(struct word *)0:enval(t+1));
37 	*t=c;
38 	return v;
39 }
40 Vinit(){
41 	extern char **environ;
42 	register char *s;
43 	register char **env=environ;
44 	environp=env;
45 	for(;*env;env++){
46 		for(s=*env;*s && *s!='(' && *s!='=';s++);
47 		switch(*s){
48 		case '\0':
49 			pfmt(err, "environment %q?\n", *env);
50 			break;
51 		case '=':
52 			*s='\0';
53 			setvar(*env, enval(s+1));
54 			*s='=';
55 			break;
56 		case '(':	/* ignore functions for now */
57 			break;
58 		}
59 	}
60 }
61 char **envp;
62 Xrdfn(){
63 	register char *s;
64 	register int len;
65 	for(;*envp;envp++){
66 		for(s=*envp;*s && *s!='(' && *s!='=';s++);
67 		switch(*s){
68 		case '\0':
69 			pfmt(err, "environment %q?\n", *envp);
70 			break;
71 		case '=':	/* ignore variables */
72 			break;
73 		case '(':		/* Bourne again */
74 			s=*envp+3;
75 			envp++;
76 			len=strlen(s);
77 			s[len]='\n';
78 			execcmds(opencore(s, len+1));
79 			s[len]='\0';
80 			return;
81 		}
82 	}
83 	Xreturn();
84 }
85 union code rdfns[4];
86 execfinit(){
87 	static int first=1;
88 	if(first){
89 		rdfns[0].i=1;
90 		rdfns[1].f=Xrdfn;
91 		rdfns[2].f=Xjump;
92 		rdfns[3].i=1;
93 		first=0;
94 	}
95 	Xpopm();
96 	envp=environp;
97 	start(rdfns, 1, runq->local);
98 }
99 cmpenv(a, b)
100 char **a, **b;
101 {
102 	return strcmp(*a, *b);
103 }
104 char **mkenv(){
105 	register char **env, **ep, *p, *q;
106 	register struct var **h, *v;
107 	register struct word *a;
108 	register int nvar=0, nchr=0, sep;
109 	/*
110 	 * Slightly kludgy loops look at locals then globals
111 	 */
112 	for(h=var-1;h!=&var[NVAR];h++) for(v=h>=var?*h:runq->local;v;v=v->next){
113 		if((v==vlook(v->name)) && v->val){
114 			nvar++;
115 			nchr+=strlen(v->name)+1;
116 			for(a=v->val;a;a=a->next)
117 				nchr+=strlen(a->word)+1;
118 		}
119 		if(v->fn){
120 			nvar++;
121 			nchr+=strlen(v->name)+strlen(v->fn[v->pc-1].s)+8;
122 		}
123 	}
124 	env=(char **)emalloc((nvar+1)*sizeof(char *)+nchr);
125 	ep=env;
126 	p=(char *)&env[nvar+1];
127 	for(h=var-1;h!=&var[NVAR];h++) for(v=h>=var?*h:runq->local;v;v=v->next){
128 		if((v==vlook(v->name)) && v->val){
129 			*ep++=p;
130 			q=v->name;
131 			while(*q) *p++=*q++;
132 			sep='=';
133 			for(a=v->val;a;a=a->next){
134 				*p++=sep;
135 				sep=SEP;
136 				q=a->word;
137 				while(*q) *p++=*q++;
138 			}
139 			*p++='\0';
140 		}
141 		if(v->fn){
142 			*ep++=p;
143 			*p++='#'; *p++='('; *p++=')';	/* to fool Bourne */
144 			*p++='f'; *p++='n'; *p++=' ';
145 			q=v->name;
146 			while(*q) *p++=*q++;
147 			*p++=' ';
148 			q=v->fn[v->pc-1].s;
149 			while(*q) *p++=*q++;
150 			*p++='\0';
151 		}
152 	}
153 	*ep=0;
154 	qsort((char *)env, nvar, sizeof ep[0], cmpenv);
155 	return env;
156 }
157 char *sigmsg[]={
158 /*  0 normal  */ 0,
159 /*  1 SIGHUP  */ "Hangup",
160 /*  2 SIGINT  */ 0,
161 /*  3 SIGQUIT */ "Quit",
162 /*  4 SIGILL  */ "Illegal instruction",
163 /*  5 SIGTRAP */ "Trace/BPT trap",
164 /*  6 SIGIOT  */ "abort",
165 /*  7 SIGEMT  */ "EMT trap",
166 /*  8 SIGFPE  */ "Floating exception",
167 /*  9 SIGKILL */ "Killed",
168 /* 10 SIGBUS  */ "Bus error",
169 /* 11 SIGSEGV */ "Memory fault",
170 /* 12 SIGSYS  */ "Bad system call",
171 /* 13 SIGPIPE */ 0,
172 /* 14 SIGALRM */ "Alarm call",
173 /* 15 SIGTERM */ "Terminated",
174 /* 16 unused  */ "signal 16",
175 /* 17 SIGSTOP */ "Process stopped",
176 /* 18 unused  */ "signal 18",
177 /* 19 SIGCONT */ "Process continued",
178 /* 20 SIGCHLD */ "Child death",
179 };
180 Waitfor(pid, persist){
181 	register int wpid, sig;
182 	register struct thread *p;
183 	int wstat;
184 	char wstatstr[12];
185 	for(;;){
186 		errno=0;
187 		wpid=wait(&wstat);
188 		if(errno==EINTR && persist) continue;
189 		if(wpid==-1) break;
190 		sig=wstat&0177;
191 		if(sig==0177){
192 			pfmt(err, "trace: ");
193 			sig=(wstat>>8)&0177;
194 		}
195 		if(sig>(sizeof sigmsg/sizeof sigmsg[0]) || sigmsg[sig]){
196 			if(pid!=wpid) pfmt(err, "%d: ", wpid);
197 			if(sig<=(sizeof sigmsg/sizeof sigmsg[0]))
198 				pfmt(err, "%s", sigmsg[sig]);
199 			else if(sig==0177) pfmt(err, "stopped by ptrace");
200 			else pfmt(err, "signal %d", sig);
201 			if(wstat&0200)pfmt(err, " -- core dumped");
202 			pfmt(err, "\n");
203 		}
204 		wstat=sig?sig+1000:(wstat>>8)&0xFF;
205 		if(wpid==pid){
206 			if(flag['e'] && wstat) exit(wstat);
207 			itoa(wstatstr, wstat);
208 			setstatus(wstatstr);
209 			break;
210 		}
211 		else{
212 			for(p=runq->ret;p;p=p->ret)
213 				if(p->pid==wpid){
214 					p->pid=-1;
215 					itoa(p->status, wstat);
216 					break;
217 				}
218 		}
219 	}
220 }
221 char **mkargv(a)
222 register struct word *a;
223 {
224 	char **argv=(char **)emalloc((count(a)+2)*sizeof(char *));
225 	register char **argp=argv+1;	/* leave one at front for runcoms */
226 	for(;a;a=a->next) *argp++=a->word;
227 	*argp=0;
228 	return argv;
229 }
230 Updenv(){}
231 Execute(args, path)
232 register struct word *args, *path;
233 {
234 	register char *msg="not found";
235 	register int txtbusy=0;
236 	char **env=mkenv();
237 	char **argv=mkargv(args);
238 	char file[512];
239 	for(;path;path=path->next){
240 		strcpy(file, path->word);
241 		if(file[0]) strcat(file, "/");
242 		strcat(file, argv[1]);
243 	ReExec:
244 		execve(file, argv+1, env);
245 		switch(errno){
246 		case ENOEXEC:
247 			pfmt(err, "%s: Bourne again\n", argv[1]);
248 			argv[0]="sh";
249 			argv[1]=strdup(file);
250 			execve("/bin/sh", argv, env);
251 			goto Bad;
252 		case ETXTBSY:
253 			if(++txtbusy!=5){
254 				sleep(txtbusy);
255 				goto ReExec;
256 			}
257 			msg="text busy"; goto Bad;
258 		case EACCES: msg="no access"; break;
259 		case ENOMEM: msg="not enough memory"; goto Bad;
260 		case E2BIG: msg="too big"; goto Bad;
261 		}
262 	}
263 Bad:
264 	pfmt(err, "%s: %s\n", argv[1], msg);
265 	efree((char *)env);
266 	efree((char *)argv);
267 }
268 #define	NDIR	14		/* should get this from param.h */
269 Globsize(p)
270 register char *p;
271 {
272 	int isglob=0, globlen=NDIR+1;
273 	for(;*p;p++){
274 		if(*p==GLOB){
275 			p++;
276 			if(*p!=GLOB) isglob++;
277 			globlen+=*p=='*'?NDIR:1;
278 		}
279 		else
280 			globlen++;
281 	}
282 	return isglob?globlen:0;
283 }
284 #include <sys/types.h>
285 #include <ndir.h>
286 #define	NDIRLIST	50
287 DIR *dirlist[NDIRLIST];
288 Opendir(name)
289 char *name;
290 {
291 	register DIR **dp;
292 	for(dp=dirlist;dp!=&dirlist[NDIRLIST];dp++)
293 		if(*dp==0){
294 			*dp=opendir(name);
295 			return *dp?dp-dirlist:-1;
296 		}
297 	return -1;
298 }
299 Readdir(f, p)
300 register int f;
301 register char *p;
302 {
303 	struct direct *dp=readdir(dirlist[f]);
304 	if(dp==0) return 0;
305 	strcpy(p, dp->d_name);
306 	return 1;
307 }
308 Closedir(f){
309 	closedir(dirlist[f]);
310 	dirlist[f]=0;
311 }
312 char *Signame[]={
313 	"sigexit",	"sighup",	"sigint",	"sigquit",
314 	"sigill",	"sigtrap",	"sigiot",	"sigemt",
315 	"sigfpe",	"sigkill",	"sigbus",	"sigsegv",
316 	"sigsys",	"sigpipe",	"sigalrm",	"sigterm",
317 	"sig16",	"sigstop",	"sigtstp",	"sigcont",
318 	"sigchld",	"sigttin",	"sigttou",	"sigtint",
319 	"sigxcpu",	"sigxfsz",	"sig26",	"sig27",
320 	"sig28",	"sig29",	"sig30",	"sig31",
321 	0,
322 };
323 int gettrap(sig){
324 	signal(sig, gettrap);
325 	trap[sig]++;
326 	ntrap++;
327 	if(ntrap>=NSIG){
328 		pfmt(err, "rc: Too many traps (trap %d), dumping core\n", sig);
329 		signal(SIGIOT, (int (*)())0);
330 		kill(getpid(), SIGIOT);
331 	}
332 }
333 Trapinit(){
334 	register int i;
335 	register int (*sig)();
336 	if(1 || flag['d']){	/* wrong!!! */
337 		sig=signal(SIGINT, gettrap);
338 		if(sig==SIG_IGN) signal(SIGINT, SIG_IGN);
339 	}
340 	else{
341 		for(i=1;i<=NSIG;i++) if(i!=SIGCHLD){
342 			sig=signal(i, gettrap);
343 			if(sig==SIG_IGN) signal(i, SIG_IGN);
344 		}
345 	}
346 }
347 Unlink(name)
348 char *name;
349 {
350 	return unlink(name);
351 }
352 Write(fd, buf, cnt)
353 char *buf;
354 {
355 	return write(fd, buf, cnt);
356 }
357 Read(fd, buf, cnt)
358 char *buf;
359 {
360 	return read(fd, buf, cnt);
361 }
362 Seek(fd, cnt, whence)
363 long cnt;
364 {
365 	return lseek(fd, cnt, whence);
366 }
367 Executable(file)
368 char *file;
369 {
370 	return(access(file, 01)==0);
371 }
372 Creat(file)
373 char *file;
374 {
375 	return creat(file, 0666);
376 }
377 Dup(a, b){
378 	return dup2(a, b);
379 }
380 Dup1(a){
381 	return dup(a);
382 }
383 /*
384  * Wrong:  should go through components of a|b|c and return the maximum.
385  */
386 Exit(stat)
387 register char *stat;
388 {
389 	register int n=0;
390 	while(*stat){
391 		if(*stat!='|'){
392 			if(*stat<'0' || '9'<*stat) exit(1);
393 			else n=n*10+*stat-'0';
394 		}
395 		stat++;
396 	}
397 	exit(n);
398 }
399 Eintr(){
400 	return errno==EINTR;
401 }
402 Noerror(){
403 	errno=0;
404 }
405 Isatty(fd){
406 	return isatty(fd);
407 }
408 Abort(){
409 	abort();
410 }
411 execumask(){		/* wrong -- should fork before writing */
412 	register int m;
413 	struct io out[1];
414 	switch(count(runq->argv->words)){
415 	default:
416 		pfmt(err, "Usage: umask [umask]\n");
417 		setstatus("umask usage");
418 		poplist();
419 		return;
420 	case 2: umask(octal(runq->argv->words->next->word)); break;
421 	case 1:
422 		umask(m=umask(0));
423 		out->fd=mapfd(1);
424 		out->bufp=out->buf;
425 		out->ebuf=&out->buf[NBUF];
426 		out->strp=0;
427 		pfmt(out, "%o\n", m);
428 		break;
429 	}
430 	setstatus("");
431 	poplist();
432 }
433 Memcpy(a, b, n)
434 char *a, *b;
435 {
436 	memmove(a, b, n);
437 }
438 void *Malloc(n){
439 	return (void *)malloc(n);
440 }
441