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