]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/rc/plan9.c
rc: simplify execfinit() / Xrdfn() using the globber to lookup /env/fn'#'*
[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                                         free(buf);
148                                 }
149                         }
150                 }
151                 free(ent);
152         }
153         close(dir);
154 }
155
156 void
157 Xrdfn(void)
158 {
159         if(runq->argv->words == 0)
160                 poplist();
161         else {
162                 int f = open(runq->argv->words->word, 0);
163                 popword();
164                 runq->pc--;
165                 if(f>=0) execcmds(openfd(f));
166         }
167 }
168 union code rdfns[8];
169
170 void
171 execfinit(void)
172 {
173         static int first = 1;
174         if(first){
175                 rdfns[0].i = 1;
176                 rdfns[1].f = Xmark;
177                 rdfns[2].f = Xglobs;
178                 rdfns[4].i = Globsize(rdfns[3].s = "/env/fn#\001*");
179                 rdfns[5].f = Xglob;
180                 rdfns[6].f = Xrdfn;
181                 rdfns[7].f = Xreturn;
182                 first = 0;
183         }
184         poplist();
185         start(rdfns, 1, runq->local);
186 }
187
188 int
189 Waitfor(int pid, int)
190 {
191         thread *p;
192         Waitmsg *w;
193         char errbuf[ERRMAX];
194
195         if(pid >= 0 && !havewaitpid(pid))
196                 return 0;
197
198         while((w = wait()) != nil){
199                 delwaitpid(w->pid);
200                 if(w->pid==pid){
201                         setstatus(w->msg);
202                         free(w);
203                         return 0;
204                 }
205                 for(p = runq->ret;p;p = p->ret)
206                         if(p->pid==w->pid){
207                                 p->pid=-1;
208                                 strcpy(p->status, w->msg);
209                         }
210                 free(w);
211         }
212
213         errstr(errbuf, sizeof errbuf);
214         if(strcmp(errbuf, "interrupted")==0) return -1;
215         return 0;
216 }
217
218 char **
219 mkargv(word *a)
220 {
221         char **argv = (char **)emalloc((count(a)+2)*sizeof(char *));
222         char **argp = argv+1;   /* leave one at front for runcoms */
223         for(;a;a = a->next) *argp++=a->word;
224         *argp = 0;
225         return argv;
226 }
227
228 void
229 addenv(var *v)
230 {
231         char envname[Maxenvname];
232         word *w;
233         int f;
234         io *fd;
235         if(v->changed){
236                 v->changed = 0;
237                 snprint(envname, sizeof envname, "/env/%s", v->name);
238                 if((f = Creat(envname))<0)
239                         pfmt(err, "rc: can't open %s: %r\n", envname);
240                 else{
241                         for(w = v->val;w;w = w->next)
242                                 write(f, w->word, strlen(w->word)+1L);
243                         close(f);
244                 }
245         }
246         if(v->fnchanged){
247                 v->fnchanged = 0;
248                 snprint(envname, sizeof envname, "/env/fn#%s", v->name);
249                 if((f = Creat(envname))<0)
250                         pfmt(err, "rc: can't open %s: %r\n", envname);
251                 else{
252                         fd = openfd(f);
253                         if(v->fn)
254                                 pfmt(fd, "fn %q %s\n", v->name, v->fn[v->pc-1].s);
255                         closeio(fd);
256                 }
257         }
258 }
259
260 void
261 updenvlocal(var *v)
262 {
263         if(v){
264                 updenvlocal(v->next);
265                 addenv(v);
266         }
267 }
268
269 void
270 Updenv(void)
271 {
272         var *v, **h;
273         for(h = gvar;h!=&gvar[NVAR];h++)
274                 for(v=*h;v;v = v->next)
275                         addenv(v);
276         if(runq)
277                 updenvlocal(runq->local);
278 }
279
280 /* not used on plan 9 */
281 int
282 ForkExecute(char *, char **, int, int, int)
283 {
284         return -1;
285 }
286
287 void
288 Execute(word *args, word *path)
289 {
290         char **argv = mkargv(args);
291         char file[1024];
292         int nc, mc;
293
294         Updenv();
295         mc = strlen(argv[1])+1;
296         for(;path;path = path->next){
297                 nc = strlen(path->word);
298                 if(nc + mc >= sizeof file - 1){ /* 1 for / */
299                         werrstr("command path name too long");
300                         continue;
301                 }
302                 if(nc > 0){
303                         memmove(file, path->word, nc);
304                         file[nc++] = '/';
305                 }
306                 memmove(file+nc, argv[1], mc);
307                 exec(file, argv+1);
308         }
309         rerrstr(file, sizeof file);
310         setstatus(file);
311         pfmt(err, "%s: %s\n", argv[1], file);
312         free(argv);
313 }
314 #define NDIR    256             /* shoud be a better way */
315
316 int
317 Globsize(char *p)
318 {
319         int isglob = 0, globlen = NDIR+1;
320         for(;*p;p++){
321                 if(*p==GLOB){
322                         p++;
323                         if(*p!=GLOB)
324                                 isglob++;
325                         globlen+=*p=='*'?NDIR:1;
326                 }
327                 else
328                         globlen++;
329         }
330         return isglob?globlen:0;
331 }
332 #define NFD     50
333
334 struct{
335         Dir     *dbuf;
336         int     i;
337         int     n;
338 }dir[NFD];
339
340 int
341 Opendir(char *name)
342 {
343         Dir *db;
344         int f;
345         f = open(name, 0);
346         if(f==-1)
347                 return f;
348         db = dirfstat(f);
349         if(db!=nil && (db->mode&DMDIR)){
350                 if(f<NFD){
351                         dir[f].i = 0;
352                         dir[f].n = 0;
353                 }
354                 free(db);
355                 return f;
356         }
357         free(db);
358         close(f);
359         return -1;
360 }
361
362 static int
363 trimdirs(Dir *d, int nd)
364 {
365         int r, w;
366
367         for(r=w=0; r<nd; r++)
368                 if(d[r].mode&DMDIR)
369                         d[w++] = d[r];
370         return w;
371 }
372
373 /*
374  * onlydirs is advisory -- it means you only
375  * need to return the directories.  it's okay to
376  * return files too (e.g., on unix where you can't
377  * tell during the readdir), but that just makes 
378  * the globber work harder.
379  */
380 int
381 Readdir(int f, void *p, int onlydirs)
382 {
383         int n;
384
385         if(f<0 || f>=NFD)
386                 return 0;
387 Again:
388         if(dir[f].i==dir[f].n){ /* read */
389                 free(dir[f].dbuf);
390                 dir[f].dbuf = 0;
391                 n = dirread(f, &dir[f].dbuf);
392                 if(n>0){
393                         if(onlydirs){
394                                 n = trimdirs(dir[f].dbuf, n);
395                                 if(n == 0)
396                                         goto Again;
397                         }       
398                         dir[f].n = n;
399                 }else
400                         dir[f].n = 0;
401                 dir[f].i = 0;
402         }
403         if(dir[f].i == dir[f].n)
404                 return 0;
405         strncpy((char*)p, dir[f].dbuf[dir[f].i].name, NDIR);
406         dir[f].i++;
407         return 1;
408 }
409
410 void
411 Closedir(int f)
412 {
413         if(f>=0 && f<NFD){
414                 free(dir[f].dbuf);
415                 dir[f].i = 0;
416                 dir[f].n = 0;
417                 dir[f].dbuf = 0;
418         }
419         close(f);
420 }
421 int interrupted = 0;
422 void
423 notifyf(void*, char *s)
424 {
425         int i;
426         for(i = 0;syssigname[i];i++) if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){
427                 if(strncmp(s, "sys: ", 5)!=0) interrupted = 1;
428                 goto Out;
429         }
430         pfmt(err, "rc: note: %s\n", s);
431         noted(NDFLT);
432         return;
433 Out:
434         if(strcmp(s, "interrupt")!=0 || trap[i]==0){
435                 trap[i]++;
436                 ntrap++;
437         }
438         if(ntrap>=32){  /* rc is probably in a trap loop */
439                 pfmt(err, "rc: Too many traps (trap %s), aborting\n", s);
440                 abort();
441         }
442         noted(NCONT);
443 }
444
445 void
446 Trapinit(void)
447 {
448         notify(notifyf);
449 }
450
451 void
452 Unlink(char *name)
453 {
454         remove(name);
455 }
456
457 long
458 Write(int fd, void *buf, long cnt)
459 {
460         return write(fd, buf, cnt);
461 }
462
463 long
464 Read(int fd, void *buf, long cnt)
465 {
466         return read(fd, buf, cnt);
467 }
468
469 long
470 Seek(int fd, long cnt, long whence)
471 {
472         return seek(fd, cnt, whence);
473 }
474
475 int
476 Executable(char *file)
477 {
478         Dir *statbuf;
479         int ret;
480
481         statbuf = dirstat(file);
482         if(statbuf == nil)
483                 return 0;
484         ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0);
485         free(statbuf);
486         return ret;
487 }
488
489 int
490 Creat(char *file)
491 {
492         return create(file, 1, 0666L);
493 }
494
495 int
496 Dup(int a, int b)
497 {
498         return dup(a, b);
499 }
500
501 int
502 Dup1(int)
503 {
504         return -1;
505 }
506
507 void
508 Exit(char *stat)
509 {
510         Updenv();
511         setstatus(stat);
512         exits(truestatus()?"":getstatus());
513 }
514
515 int
516 Eintr(void)
517 {
518         return interrupted;
519 }
520
521 void
522 Noerror(void)
523 {
524         interrupted = 0;
525 }
526
527 int
528 Isatty(int fd)
529 {
530         char buf[64];
531
532         if(fd2path(fd, buf, sizeof buf) != 0)
533                 return 0;
534
535         /* might be #c/cons during boot - fixed 22 april 2005, remove this later */
536         if(strcmp(buf, "#c/cons") == 0)
537                 return 1;
538
539         /* might be /mnt/term/dev/cons */
540         return strlen(buf) >= 9 && strcmp(buf+strlen(buf)-9, "/dev/cons") == 0;
541 }
542
543 void
544 Abort(void)
545 {
546         pfmt(err, "aborting\n");
547         flush(err);
548         Exit("aborting");
549 }
550
551 int *waitpids;
552 int nwaitpids;
553
554 void
555 addwaitpid(int pid)
556 {
557         waitpids = erealloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]);
558         waitpids[nwaitpids++] = pid;
559 }
560
561 void
562 delwaitpid(int pid)
563 {
564         int r, w;
565         
566         for(r=w=0; r<nwaitpids; r++)
567                 if(waitpids[r] != pid)
568                         waitpids[w++] = waitpids[r];
569         nwaitpids = w;
570 }
571
572 void
573 clearwaitpids(void)
574 {
575         nwaitpids = 0;
576 }
577
578 int
579 havewaitpid(int pid)
580 {
581         int i;
582
583         for(i=0; i<nwaitpids; i++)
584                 if(waitpids[i] == pid)
585                         return 1;
586         return 0;
587 }
588
589 /* avoid loading any floating-point library code */
590 int
591 _efgfmt(Fmt *)
592 {
593         return -1;
594 }