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