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