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