xref: /plan9-contrib/sys/src/cmd/rc/unix.c (revision a6a9e07217f318acf170f99684a55fba5200524f)
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, onlydirs)
299 register int f;
300 register char *p;
301 register int onlydirs;	/* ignored, just advisory */
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