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