1 /*
2 * Plan 9 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 "io.h"
9 #include "fns.h"
10 #include "getflags.h"
11
12 enum {
13 Maxenvname = 256, /* undocumented limit */
14 };
15
16 char *Signame[] = {
17 "sigexit", "sighup", "sigint", "sigquit",
18 "sigalrm", "sigkill", "sigfpe", "sigterm",
19 0
20 };
21 char *syssigname[] = {
22 "exit", /* can't happen */
23 "hangup",
24 "interrupt",
25 "quit", /* can't happen */
26 "alarm",
27 "kill",
28 "sys: fp: ",
29 "term",
30 0
31 };
32 char *Rcmain = "/rc/lib/rcmain";
33 char *Fdprefix = "/fd/";
34
35 void execfinit(void);
36 void execbind(void);
37 void execmount(void);
38 void execnewpgrp(void);
39
40 builtin Builtin[] = {
41 "cd", execcd,
42 "whatis", execwhatis,
43 "eval", execeval,
44 "exec", execexec, /* but with popword first */
45 "exit", execexit,
46 "shift", execshift,
47 "wait", execwait,
48 ".", execdot,
49 "finit", execfinit,
50 "flag", execflag,
51 "rfork", execnewpgrp,
52 0
53 };
54
55 void
execnewpgrp(void)56 execnewpgrp(void)
57 {
58 int arg;
59 char *s;
60 switch(count(runq->argv->words)){
61 case 1:
62 arg = RFENVG|RFNAMEG|RFNOTEG;
63 break;
64 case 2:
65 arg = 0;
66 for(s = runq->argv->words->next->word;*s;s++) switch(*s){
67 default:
68 goto Usage;
69 case 'n':
70 arg|=RFNAMEG; break;
71 case 'N':
72 arg|=RFCNAMEG;
73 break;
74 case 'm':
75 arg|=RFNOMNT; break;
76 case 'e':
77 arg|=RFENVG; break;
78 case 'E':
79 arg|=RFCENVG; break;
80 case 's':
81 arg|=RFNOTEG; break;
82 case 'f':
83 arg|=RFFDG; break;
84 case 'F':
85 arg|=RFCFDG; break;
86 }
87 break;
88 default:
89 Usage:
90 pfmt(err, "Usage: %s [fnesFNEm]\n", runq->argv->words->word);
91 setstatus("rfork usage");
92 poplist();
93 return;
94 }
95 if(rfork(arg)==-1){
96 pfmt(err, "rc: %s failed\n", runq->argv->words->word);
97 setstatus("rfork failed");
98 }
99 else
100 setstatus("");
101 poplist();
102 }
103
104 void
Vinit(void)105 Vinit(void)
106 {
107 int dir, f, len, i, n, nent;
108 char *buf, *s;
109 char envname[Maxenvname];
110 word *val;
111 Dir *ent;
112
113 dir = open("/env", OREAD);
114 if(dir<0){
115 pfmt(err, "rc: can't open /env: %r\n");
116 return;
117 }
118 ent = nil;
119 for(;;){
120 nent = dirread(dir, &ent);
121 if(nent <= 0)
122 break;
123 for(i = 0; i<nent; i++){
124 len = ent[i].length;
125 if(len && strncmp(ent[i].name, "fn#", 3)!=0){
126 snprint(envname, sizeof envname, "/env/%s", ent[i].name);
127 if((f = open(envname, 0))>=0){
128 buf = emalloc(len+1);
129 n = readn(f, buf, len);
130 if (n <= 0)
131 buf[0] = '\0';
132 else
133 buf[n] = '\0';
134 val = 0;
135 /* Charitably add a 0 at the end if need be */
136 if(buf[len-1])
137 buf[len++]='\0';
138 s = buf+len-1;
139 for(;;){
140 while(s!=buf && s[-1]!='\0') --s;
141 val = newword(s, val);
142 if(s==buf)
143 break;
144 --s;
145 }
146 setvar(ent[i].name, val);
147 vlook(ent[i].name)->changed = 0;
148 close(f);
149 efree(buf);
150 }
151 }
152 }
153 free(ent);
154 }
155 close(dir);
156 }
157 int envdir;
158
159 void
Xrdfn(void)160 Xrdfn(void)
161 {
162 int f, len;
163 Dir *e;
164 char envname[Maxenvname];
165 static Dir *ent, *allocent;
166 static int nent;
167
168 for(;;){
169 if(nent == 0){
170 free(allocent);
171 nent = dirread(envdir, &allocent);
172 ent = allocent;
173 }
174 if(nent <= 0)
175 break;
176 while(nent){
177 e = ent++;
178 nent--;
179 len = e->length;
180 if(len && strncmp(e->name, "fn#", 3)==0){
181 snprint(envname, sizeof envname, "/env/%s", e->name);
182 if((f = open(envname, 0))>=0){
183 execcmds(openfd(f));
184 return;
185 }
186 }
187 }
188 }
189 close(envdir);
190 Xreturn();
191 }
192 union code rdfns[4];
193
194 void
execfinit(void)195 execfinit(void)
196 {
197 static int first = 1;
198 if(first){
199 rdfns[0].i = 1;
200 rdfns[1].f = Xrdfn;
201 rdfns[2].f = Xjump;
202 rdfns[3].i = 1;
203 first = 0;
204 }
205 Xpopm();
206 envdir = open("/env", 0);
207 if(envdir<0){
208 pfmt(err, "rc: can't open /env: %r\n");
209 return;
210 }
211 start(rdfns, 1, runq->local);
212 }
213
214 int
Waitfor(int pid,int)215 Waitfor(int pid, int)
216 {
217 thread *p;
218 Waitmsg *w;
219 char errbuf[ERRMAX];
220
221 if(pid >= 0 && !havewaitpid(pid))
222 return 0;
223
224 while((w = wait()) != nil){
225 delwaitpid(w->pid);
226 if(w->pid==pid){
227 setstatus(w->msg);
228 free(w);
229 return 0;
230 }
231 for(p = runq->ret;p;p = p->ret)
232 if(p->pid==w->pid){
233 p->pid=-1;
234 strcpy(p->status, w->msg);
235 }
236 free(w);
237 }
238
239 errstr(errbuf, sizeof errbuf);
240 if(strcmp(errbuf, "interrupted")==0) return -1;
241 return 0;
242 }
243
244 char **
mkargv(word * a)245 mkargv(word *a)
246 {
247 char **argv = (char **)emalloc((count(a)+2)*sizeof(char *));
248 char **argp = argv+1; /* leave one at front for runcoms */
249 for(;a;a = a->next) *argp++=a->word;
250 *argp = 0;
251 return argv;
252 }
253
254 void
addenv(var * v)255 addenv(var *v)
256 {
257 char envname[Maxenvname];
258 word *w;
259 int f;
260 io *fd;
261 if(v->changed){
262 v->changed = 0;
263 snprint(envname, sizeof envname, "/env/%s", v->name);
264 if((f = Creat(envname))<0)
265 pfmt(err, "rc: can't open %s: %r\n", envname);
266 else{
267 for(w = v->val;w;w = w->next)
268 write(f, w->word, strlen(w->word)+1L);
269 close(f);
270 }
271 }
272 if(v->fnchanged){
273 v->fnchanged = 0;
274 snprint(envname, sizeof envname, "/env/fn#%s", v->name);
275 if((f = Creat(envname))<0)
276 pfmt(err, "rc: can't open %s: %r\n", envname);
277 else{
278 if(v->fn){
279 fd = openfd(f);
280 pfmt(fd, "fn %q %s\n", v->name, v->fn[v->pc-1].s);
281 closeio(fd);
282 }
283 close(f);
284 }
285 }
286 }
287
288 void
updenvlocal(var * v)289 updenvlocal(var *v)
290 {
291 if(v){
292 updenvlocal(v->next);
293 addenv(v);
294 }
295 }
296
297 void
Updenv(void)298 Updenv(void)
299 {
300 var *v, **h;
301 for(h = gvar;h!=&gvar[NVAR];h++)
302 for(v=*h;v;v = v->next)
303 addenv(v);
304 if(runq)
305 updenvlocal(runq->local);
306 }
307
308 /* not used on plan 9 */
309 int
ForkExecute(char * file,char ** argv,int sin,int sout,int serr)310 ForkExecute(char *file, char **argv, int sin, int sout, int serr)
311 {
312 int pid;
313
314 if(access(file, 1) != 0)
315 return -1;
316 switch(pid = fork()){
317 case -1:
318 return -1;
319 case 0:
320 if(sin >= 0)
321 dup(sin, 0);
322 else
323 close(0);
324 if(sout >= 0)
325 dup(sout, 1);
326 else
327 close(1);
328 if(serr >= 0)
329 dup(serr, 2);
330 else
331 close(2);
332 exec(file, argv);
333 exits(file);
334 }
335 return pid;
336 }
337
338 void
Execute(word * args,word * path)339 Execute(word *args, word *path)
340 {
341 char **argv = mkargv(args);
342 char file[1024], errstr[1024];
343 int nc;
344
345 Updenv();
346 errstr[0] = '\0';
347 for(;path;path = path->next){
348 nc = strlen(path->word);
349 if(nc < sizeof file - 1){ /* 1 for / */
350 strcpy(file, path->word);
351 if(file[0]){
352 strcat(file, "/");
353 nc++;
354 }
355 if(nc + strlen(argv[1]) < sizeof file){
356 strcat(file, argv[1]);
357 exec(file, argv+1);
358 rerrstr(errstr, sizeof errstr);
359 /*
360 * if file exists and is executable, exec should
361 * have worked, unless it's a directory or an
362 * executable for another architecture. in
363 * particular, if it failed due to lack of
364 * swap/vm (e.g., arg. list too long) or other
365 * allocation failure, stop searching and print
366 * the reason for failure.
367 */
368 if (strstr(errstr, " allocat") != nil ||
369 strstr(errstr, " full") != nil)
370 break;
371 }
372 else werrstr("command name too long");
373 }
374 }
375 pfmt(err, "%s: %s\n", argv[1], errstr);
376 efree((char *)argv);
377 }
378 #define NDIR 256 /* shoud be a better way */
379
380 int
Globsize(char * p)381 Globsize(char *p)
382 {
383 int isglob = 0, globlen = NDIR+1;
384 for(;*p;p++){
385 if(*p==GLOB){
386 p++;
387 if(*p!=GLOB)
388 isglob++;
389 globlen+=*p=='*'?NDIR:1;
390 }
391 else
392 globlen++;
393 }
394 return isglob?globlen:0;
395 }
396 #define NFD 50
397
398 struct{
399 Dir *dbuf;
400 int i;
401 int n;
402 }dir[NFD];
403
404 int
Opendir(char * name)405 Opendir(char *name)
406 {
407 Dir *db;
408 int f;
409 f = open(name, 0);
410 if(f==-1)
411 return f;
412 db = dirfstat(f);
413 if(db!=nil && (db->mode&DMDIR)){
414 if(f<NFD){
415 dir[f].i = 0;
416 dir[f].n = 0;
417 }
418 free(db);
419 return f;
420 }
421 free(db);
422 close(f);
423 return -1;
424 }
425
426 static int
trimdirs(Dir * d,int nd)427 trimdirs(Dir *d, int nd)
428 {
429 int r, w;
430
431 for(r=w=0; r<nd; r++)
432 if(d[r].mode&DMDIR)
433 d[w++] = d[r];
434 return w;
435 }
436
437 /*
438 * onlydirs is advisory -- it means you only
439 * need to return the directories. it's okay to
440 * return files too (e.g., on unix where you can't
441 * tell during the readdir), but that just makes
442 * the globber work harder.
443 */
444 int
Readdir(int f,void * p,int onlydirs)445 Readdir(int f, void *p, int onlydirs)
446 {
447 int n;
448
449 if(f<0 || f>=NFD)
450 return 0;
451 Again:
452 if(dir[f].i==dir[f].n){ /* read */
453 free(dir[f].dbuf);
454 dir[f].dbuf = 0;
455 n = dirread(f, &dir[f].dbuf);
456 if(n>0){
457 if(onlydirs){
458 n = trimdirs(dir[f].dbuf, n);
459 if(n == 0)
460 goto Again;
461 }
462 dir[f].n = n;
463 }else
464 dir[f].n = 0;
465 dir[f].i = 0;
466 }
467 if(dir[f].i == dir[f].n)
468 return 0;
469 strcpy(p, dir[f].dbuf[dir[f].i].name);
470 dir[f].i++;
471 return 1;
472 }
473
474 void
Closedir(int f)475 Closedir(int f)
476 {
477 if(f>=0 && f<NFD){
478 free(dir[f].dbuf);
479 dir[f].i = 0;
480 dir[f].n = 0;
481 dir[f].dbuf = 0;
482 }
483 close(f);
484 }
485 int interrupted = 0;
486 void
notifyf(void *,char * s)487 notifyf(void*, char *s)
488 {
489 int i;
490 for(i = 0;syssigname[i];i++) if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){
491 if(strncmp(s, "sys: ", 5)!=0) interrupted = 1;
492 goto Out;
493 }
494 pfmt(err, "rc: note: %s\n", s);
495 noted(NDFLT);
496 return;
497 Out:
498 if(strcmp(s, "interrupt")!=0 || trap[i]==0){
499 trap[i]++;
500 ntrap++;
501 }
502 if(ntrap>=32){ /* rc is probably in a trap loop */
503 pfmt(err, "rc: Too many traps (trap %s), aborting\n", s);
504 abort();
505 }
506 noted(NCONT);
507 }
508
509 void
Trapinit(void)510 Trapinit(void)
511 {
512 notify(notifyf);
513 }
514
515 void
Unlink(char * name)516 Unlink(char *name)
517 {
518 remove(name);
519 }
520
521 long
Write(int fd,void * buf,long cnt)522 Write(int fd, void *buf, long cnt)
523 {
524 return write(fd, buf, cnt);
525 }
526
527 long
Read(int fd,void * buf,long cnt)528 Read(int fd, void *buf, long cnt)
529 {
530 return read(fd, buf, cnt);
531 }
532
533 long
Seek(int fd,long cnt,long whence)534 Seek(int fd, long cnt, long whence)
535 {
536 return seek(fd, cnt, whence);
537 }
538
539 int
Executable(char * file)540 Executable(char *file)
541 {
542 Dir *statbuf;
543 int ret;
544
545 statbuf = dirstat(file);
546 if(statbuf == nil)
547 return 0;
548 ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0);
549 free(statbuf);
550 return ret;
551 }
552
553 int
Creat(char * file)554 Creat(char *file)
555 {
556 return create(file, 1, 0666L);
557 }
558
559 int
Dup(int a,int b)560 Dup(int a, int b)
561 {
562 return dup(a, b);
563 }
564
565 int
Dup1(int)566 Dup1(int)
567 {
568 return -1;
569 }
570
571 void
Exit(char * stat)572 Exit(char *stat)
573 {
574 Updenv();
575 setstatus(stat);
576 exits(truestatus()?"":getstatus());
577 }
578
579 int
Eintr(void)580 Eintr(void)
581 {
582 return interrupted;
583 }
584
585 void
Noerror(void)586 Noerror(void)
587 {
588 interrupted = 0;
589 }
590
591 int
Isatty(int fd)592 Isatty(int fd)
593 {
594 char buf[64];
595
596 if(fd2path(fd, buf, sizeof buf) != 0)
597 return 0;
598
599 /* might be #c/cons during boot - fixed 22 april 2005, remove this later */
600 if(strcmp(buf, "#c/cons") == 0)
601 return 1;
602
603 /* might be /mnt/term/dev/cons */
604 return strlen(buf) >= 9 && strcmp(buf+strlen(buf)-9, "/dev/cons") == 0;
605 }
606
607 void
Abort(void)608 Abort(void)
609 {
610 pfmt(err, "aborting\n");
611 flush(err);
612 Exit("aborting");
613 }
614
615 void
Memcpy(void * a,void * b,long n)616 Memcpy(void *a, void *b, long n)
617 {
618 memmove(a, b, n);
619 }
620
621 void*
Malloc(ulong n)622 Malloc(ulong n)
623 {
624 return mallocz(n, 1);
625 }
626
627 int *waitpids;
628 int nwaitpids;
629
630 void
addwaitpid(int pid)631 addwaitpid(int pid)
632 {
633 waitpids = realloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]);
634 if(waitpids == 0)
635 panic("Can't realloc %d waitpids", nwaitpids+1);
636 waitpids[nwaitpids++] = pid;
637 }
638
639 void
delwaitpid(int pid)640 delwaitpid(int pid)
641 {
642 int r, w;
643
644 for(r=w=0; r<nwaitpids; r++)
645 if(waitpids[r] != pid)
646 waitpids[w++] = waitpids[r];
647 nwaitpids = w;
648 }
649
650 void
clearwaitpids(void)651 clearwaitpids(void)
652 {
653 nwaitpids = 0;
654 }
655
656 int
havewaitpid(int pid)657 havewaitpid(int pid)
658 {
659 int i;
660
661 for(i=0; i<nwaitpids; i++)
662 if(waitpids[i] == pid)
663 return 1;
664 return 0;
665 }
666
667 /* avoid loading any floating-point library code */
668 int
_efgfmt(Fmt *)669 _efgfmt(Fmt *)
670 {
671 return -1;
672 }
673