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