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