xref: /plan9/sys/src/cmd/rc/unix.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
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 			itoa(wstatstr, wstat);
207 			setstatus(wstatstr);
208 			break;
209 		}
210 		else{
211 			for(p=runq->ret;p;p=p->ret)
212 				if(p->pid==wpid){
213 					p->pid=-1;
214 					itoa(p->status, wstat);
215 					break;
216 				}
217 		}
218 	}
219 }
220 char **mkargv(a)
221 register struct word *a;
222 {
223 	char **argv=(char **)emalloc((count(a)+2)*sizeof(char *));
224 	register char **argp=argv+1;	/* leave one at front for runcoms */
225 	for(;a;a=a->next) *argp++=a->word;
226 	*argp=0;
227 	return argv;
228 }
229 Updenv(){}
230 Execute(args, path)
231 register struct word *args, *path;
232 {
233 	register char *msg="not found";
234 	register int txtbusy=0;
235 	char **env=mkenv();
236 	char **argv=mkargv(args);
237 	char file[512];
238 	for(;path;path=path->next){
239 		strcpy(file, path->word);
240 		if(file[0]) strcat(file, "/");
241 		strcat(file, argv[1]);
242 	ReExec:
243 		execve(file, argv+1, env);
244 		switch(errno){
245 		case ENOEXEC:
246 			pfmt(err, "%s: Bourne again\n", argv[1]);
247 			argv[0]="sh";
248 			argv[1]=strdup(file);
249 			execve("/bin/sh", argv, env);
250 			goto Bad;
251 		case ETXTBSY:
252 			if(++txtbusy!=5){
253 				sleep(txtbusy);
254 				goto ReExec;
255 			}
256 			msg="text busy"; goto Bad;
257 		case EACCES: msg="no access"; break;
258 		case ENOMEM: msg="not enough memory"; goto Bad;
259 		case E2BIG: msg="too big"; goto Bad;
260 		}
261 	}
262 Bad:
263 	pfmt(err, "%s: %s\n", argv[1], msg);
264 	efree((char *)env);
265 	efree((char *)argv);
266 }
267 #define	NDIR	14		/* should get this from param.h */
268 Globsize(p)
269 register char *p;
270 {
271 	int isglob=0, globlen=NDIR+1;
272 	for(;*p;p++){
273 		if(*p==GLOB){
274 			p++;
275 			if(*p!=GLOB) isglob++;
276 			globlen+=*p=='*'?NDIR:1;
277 		}
278 		else
279 			globlen++;
280 	}
281 	return isglob?globlen:0;
282 }
283 #include <sys/types.h>
284 #include <ndir.h>
285 #define	NDIRLIST	50
286 DIR *dirlist[NDIRLIST];
287 Opendir(name)
288 char *name;
289 {
290 	register DIR **dp;
291 	for(dp=dirlist;dp!=&dirlist[NDIRLIST];dp++)
292 		if(*dp==0){
293 			*dp=opendir(name);
294 			return *dp?dp-dirlist:-1;
295 		}
296 	return -1;
297 }
298 Readdir(f, p)
299 register int f;
300 register char *p;
301 {
302 	struct direct *dp=readdir(dirlist[f]);
303 	if(dp==0) return 0;
304 	strcpy(p, dp->d_name);
305 	return 1;
306 }
307 Closedir(f){
308 	closedir(dirlist[f]);
309 	dirlist[f]=0;
310 }
311 char *Signame[]={
312 	"sigexit",	"sighup",	"sigint",	"sigquit",
313 	"sigill",	"sigtrap",	"sigiot",	"sigemt",
314 	"sigfpe",	"sigkill",	"sigbus",	"sigsegv",
315 	"sigsys",	"sigpipe",	"sigalrm",	"sigterm",
316 	"sig16",	"sigstop",	"sigtstp",	"sigcont",
317 	"sigchld",	"sigttin",	"sigttou",	"sigtint",
318 	"sigxcpu",	"sigxfsz",	"sig26",	"sig27",
319 	"sig28",	"sig29",	"sig30",	"sig31",
320 	0,
321 };
322 int gettrap(sig){
323 	signal(sig, gettrap);
324 	trap[sig]++;
325 	ntrap++;
326 	if(ntrap>=NSIG){
327 		pfmt(err, "rc: Too many traps (trap %d), dumping core\n", sig);
328 		signal(SIGIOT, (int (*)())0);
329 		kill(getpid(), SIGIOT);
330 	}
331 }
332 Trapinit(){
333 	register int i;
334 	register int (*sig)();
335 	if(1 || flag['d']){	/* wrong!!! */
336 		sig=signal(SIGINT, gettrap);
337 		if(sig==SIG_IGN) signal(SIGINT, SIG_IGN);
338 	}
339 	else{
340 		for(i=1;i<=NSIG;i++) if(i!=SIGCHLD){
341 			sig=signal(i, gettrap);
342 			if(sig==SIG_IGN) signal(i, SIG_IGN);
343 		}
344 	}
345 }
346 Unlink(name)
347 char *name;
348 {
349 	return unlink(name);
350 }
351 Write(fd, buf, cnt)
352 char *buf;
353 {
354 	return write(fd, buf, cnt);
355 }
356 Read(fd, buf, cnt)
357 char *buf;
358 {
359 	return read(fd, buf, cnt);
360 }
361 Seek(fd, cnt, whence)
362 long cnt;
363 {
364 	return lseek(fd, cnt, whence);
365 }
366 Executable(file)
367 char *file;
368 {
369 	return(access(file, 01)==0);
370 }
371 Creat(file)
372 char *file;
373 {
374 	return creat(file, 0666);
375 }
376 Dup(a, b){
377 	return dup2(a, b);
378 }
379 Dup1(a){
380 	return dup(a);
381 }
382 /*
383  * Wrong:  should go through components of a|b|c and return the maximum.
384  */
385 Exit(stat)
386 register char *stat;
387 {
388 	register int n=0;
389 	while(*stat){
390 		if(*stat!='|'){
391 			if(*stat<'0' || '9'<*stat) exit(1);
392 			else n=n*10+*stat-'0';
393 		}
394 		stat++;
395 	}
396 	exit(n);
397 }
398 Eintr(){
399 	return errno==EINTR;
400 }
401 Noerror(){
402 	errno=0;
403 }
404 Isatty(fd){
405 	return isatty(fd);
406 }
407 Abort(){
408 	abort();
409 }
410 execumask(){		/* wrong -- should fork before writing */
411 	register int m;
412 	struct io out[1];
413 	switch(count(runq->argv->words)){
414 	default:
415 		pfmt(err, "Usage: umask [umask]\n");
416 		setstatus("umask usage");
417 		poplist();
418 		return;
419 	case 2: umask(octal(runq->argv->words->next->word)); break;
420 	case 1:
421 		umask(m=umask(0));
422 		out->fd=mapfd(1);
423 		out->bufp=out->buf;
424 		out->ebuf=&out->buf[NBUF];
425 		out->strp=0;
426 		pfmt(out, "%o\n", m);
427 		break;
428 	}
429 	setstatus("");
430 	poplist();
431 }
432 Memcpy(a, b, n)
433 char *a, *b;
434 {
435 	memmove(a, b, n);
436 }
437 void *Malloc(n){
438 	return (void *)malloc(n);
439 }
440