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 char *Signame[] = {
12 "sigexit", "sighup", "sigint", "sigquit",
13 "sigalrm", "sigkill", "sigfpe", "sigterm",
14 0
15 };
16 char *syssigname[] = {
17 "exit", /* can't happen */
18 "hangup",
19 "interrupt",
20 "quit", /* can't happen */
21 "alarm",
22 "kill",
23 "sys: fp: ",
24 "term",
25 0
26 };
27 char *Rcmain = "/rc/lib/rcmain";
28 char *Fdprefix = "/fd/";
29
30 void execfinit(void);
31 void execbind(void);
32
33 builtin Builtin[] = {
34 "cd", execcd,
35 "whatis", execwhatis,
36 "eval", execeval,
37 "exec", execexec, /* but with popword first */
38 "exit", execexit,
39 "shift", execshift,
40 "wait", execwait,
41 ".", execdot,
42 "finit", execfinit,
43 "flag", execflag,
44 0
45 };
46
47 void
Vinit(void)48 Vinit(void)
49 {
50 int dir, f, len;
51 word *val;
52 char *buf, *s;
53 Dir *ent;
54 int i, nent;
55 char envname[256];
56 dir = open("/env", OREAD);
57 if(dir<0){
58 pfmt(err, "rc: can't open /env: %r\n");
59 return;
60 }
61 ent = nil;
62 for(;;){
63 nent = dirread(dir, &ent);
64 if(nent <= 0)
65 break;
66 for(i = 0; i<nent; i++){
67 len = ent[i].length;
68 if(len && strncmp(ent[i].name, "fn#", 3)!=0){
69 snprint(envname, sizeof envname, "/env/%s", ent[i].name);
70 if((f = open(envname, 0))>=0){
71 buf = emalloc((int)len+1);
72 read(f, buf, (long)len);
73 val = 0;
74 /* Charitably add a 0 at the end if need be */
75 if(buf[len-1])
76 buf[len++]='\0';
77 s = buf+len-1;
78 for(;;){
79 while(s!=buf && s[-1]!='\0') --s;
80 val = newword(s, val);
81 if(s==buf)
82 break;
83 --s;
84 }
85 setvar(ent[i].name, val);
86 vlook(ent[i].name)->changed = 0;
87 close(f);
88 efree(buf);
89 }
90 }
91 }
92 free(ent);
93 }
94 close(dir);
95 }
96 int envdir;
97
98 void
Xrdfn(void)99 Xrdfn(void)
100 {
101 int f, len;
102 static Dir *ent, *allocent;
103 static int nent;
104 Dir *e;
105 char envname[256];
106
107 for(;;){
108 if(nent == 0){
109 free(allocent);
110 nent = dirread(envdir, &allocent);
111 ent = allocent;
112 }
113 if(nent <= 0)
114 break;
115 while(nent){
116 e = ent++;
117 nent--;
118 len = e->length;
119 if(len && strncmp(e->name, "fn#", 3)==0){
120 snprint(envname, sizeof envname, "/env/%s", e->name);
121 if((f = open(envname, 0))>=0){
122 execcmds(openfd(f));
123 return;
124 }
125 }
126 }
127 }
128 close(envdir);
129 Xreturn();
130 }
131 union code rdfns[4];
132
133 void
execfinit(void)134 execfinit(void)
135 {
136 static int first = 1;
137 if(first){
138 rdfns[0].i = 1;
139 rdfns[1].f = Xrdfn;
140 rdfns[2].f = Xjump;
141 rdfns[3].i = 1;
142 first = 0;
143 }
144 Xpopm();
145 envdir = open("/env", 0);
146 if(envdir<0){
147 pfmt(err, "rc: can't open /env: %r\n");
148 return;
149 }
150 start(rdfns, 1, runq->local);
151 }
152
153 int
Waitfor(int pid,int persist)154 Waitfor(int pid, int persist)
155 {
156 thread *p;
157 Waitmsg *w;
158 char errbuf[ERRMAX];
159
160 while((w = wait()) != nil){
161 if(w->pid==pid){
162 setstatus(w->msg);
163 free(w);
164 return 0;
165 }
166 for(p = runq->ret;p;p = p->ret)
167 if(p->pid==w->pid){
168 p->pid=-1;
169 strcpy(p->status, w->msg);
170 }
171 free(w);
172 }
173
174 errstr(errbuf, sizeof errbuf);
175 if(strcmp(errbuf, "interrupted")==0) return -1;
176 return 0;
177 }
178
179 char*
mkargv(word * a)180 *mkargv(word *a)
181 {
182 char **argv = (char **)emalloc((count(a)+2)*sizeof(char *));
183 char **argp = argv+1; /* leave one at front for runcoms */
184 for(;a;a = a->next) *argp++=a->word;
185 *argp = 0;
186 return argv;
187 }
188
189 void
addenv(var * v)190 addenv(var *v)
191 {
192 char envname[256];
193 word *w;
194 int f;
195 io *fd;
196 if(v->changed){
197 v->changed = 0;
198 snprint(envname, sizeof envname, "/env/%s", v->name);
199 if((f = Creat(envname))<0)
200 pfmt(err, "rc: can't open %s: %r\n", envname);
201 else{
202 for(w = v->val;w;w = w->next)
203 write(f, w->word, strlen(w->word)+1L);
204 close(f);
205 }
206 }
207 if(v->fnchanged){
208 v->fnchanged = 0;
209 snprint(envname, sizeof envname, "/env/fn#%s", v->name);
210 if((f = Creat(envname))<0)
211 pfmt(err, "rc: can't open %s: %r\n", envname);
212 else{
213 if(v->fn){
214 fd = openfd(f);
215 pfmt(fd, "fn %q %s\n", v->name, v->fn[v->pc-1].s);
216 closeio(fd);
217 }
218 close(f);
219 }
220 }
221 }
222
223 void
updenvlocal(var * v)224 updenvlocal(var *v)
225 {
226 if(v){
227 updenvlocal(v->next);
228 addenv(v);
229 }
230 }
231
232 void
Updenv(void)233 Updenv(void)
234 {
235 var *v, **h;
236 for(h = gvar;h!=&gvar[NVAR];h++)
237 for(v=*h;v;v = v->next)
238 addenv(v);
239 if(runq)
240 updenvlocal(runq->local);
241 }
242
243 int
ForkExecute(char * file,char ** argv,int sin,int sout,int serr)244 ForkExecute(char *file, char **argv, int sin, int sout, int serr)
245 {
246 int pid;
247
248 {int i;
249 fprint(2, "forkexec %s", file);
250 for(i = 0; argv[i]; i++)fprint(2, " %s", argv[i]);
251 fprint(2, " %d %d %d\n", sin, sout, serr);
252 }
253 if(access(file, 1) != 0)
254 return -1;
255 fprint(2, "forking\n");
256 switch(pid = fork()){
257 case -1:
258 return -1;
259 case 0:
260 if(sin >= 0)
261 dup(sin, 0);
262 else
263 close(0);
264 if(sout >= 0)
265 dup(sout, 1);
266 else
267 close(1);
268 if(serr >= 0)
269 dup(serr, 2);
270 else
271 close(2);
272 fprint(2, "execing\n");
273 exec(file, argv);
274 fprint(2, "exec: %r\n");
275 exits(file);
276 }
277 return pid;
278 }
279
280 void
Execute(word * args,word * path)281 Execute(word *args, word *path)
282 {
283 char **argv = mkargv(args);
284 char file[1024];
285 int nc;
286 Updenv();
287 for(;path;path = path->next){
288 nc = strlen(path->word);
289 if(nc<1024){
290 strcpy(file, path->word);
291 if(file[0]){
292 strcat(file, "/");
293 nc++;
294 }
295 if(nc+strlen(argv[1])<1024){
296 strcat(file, argv[1]);
297 exec(file, argv+1);
298 }
299 else werrstr("command name too long");
300 }
301 }
302 rerrstr(file, sizeof file);
303 pfmt(err, "%s: %s\n", argv[1], file);
304 efree((char *)argv);
305 }
306 #define NDIR 256 /* shoud be a better way */
307
308 int
Globsize(char * p)309 Globsize(char *p)
310 {
311 int isglob = 0, globlen = NDIR+1;
312 for(;*p;p++){
313 if(*p==GLOB){
314 p++;
315 if(*p!=GLOB)
316 isglob++;
317 globlen+=*p=='*'?NDIR:1;
318 }
319 else
320 globlen++;
321 }
322 return isglob?globlen:0;
323 }
324 #define NFD 50
325 #define NDBUF 32
326 struct{
327 Dir *dbuf;
328 int i;
329 int n;
330 }dir[NFD];
331
332 int
Opendir(char * name)333 Opendir(char *name)
334 {
335 Dir *db;
336 int f;
337 f = open(name, 0);
338 if(f==-1)
339 return f;
340 db = dirfstat(f);
341 if(db!=nil && (db->mode&DMDIR)){
342 if(f<NFD){
343 dir[f].i = 0;
344 dir[f].n = 0;
345 }
346 free(db);
347 return f;
348 }
349 free(db);
350 close(f);
351 return -1;
352 }
353
354 static int
trimdirs(Dir * d,int nd)355 trimdirs(Dir *d, int nd)
356 {
357 int r, w;
358
359 for(r=w=0; r<nd; r++)
360 if(d[r].mode&DMDIR)
361 d[w++] = d[r];
362 return w;
363 }
364
365 /*
366 * onlydirs is advisory -- it means you only
367 * need to return the directories. it's okay to
368 * return files too (e.g., on unix where you can't
369 * tell during the readdir), but that just makes
370 * the globber work harder.
371 */
372 int
Readdir(int f,void * p,int onlydirs)373 Readdir(int f, void *p, int onlydirs)
374 {
375 int n;
376
377 if(f<0 || f>=NFD)
378 return 0;
379 Again:
380 if(dir[f].i==dir[f].n){ /* read */
381 free(dir[f].dbuf);
382 dir[f].dbuf = 0;
383 n = dirread(f, &dir[f].dbuf);
384 if(n>0){
385 if(onlydirs){
386 n = trimdirs(dir[f].dbuf, n);
387 if(n == 0)
388 goto Again;
389 }
390 dir[f].n = n;
391 }else
392 dir[f].n = 0;
393 dir[f].i = 0;
394 }
395 if(dir[f].i == dir[f].n)
396 return 0;
397 strcpy(p, dir[f].dbuf[dir[f].i].name);
398 dir[f].i++;
399 return 1;
400 }
401
402 void
Closedir(int f)403 Closedir(int f)
404 {
405 if(f>=0 && f<NFD){
406 free(dir[f].dbuf);
407 dir[f].i = 0;
408 dir[f].n = 0;
409 dir[f].dbuf = 0;
410 }
411 close(f);
412 }
413 int interrupted = 0;
414 void
notifyf(void *,char * s)415 notifyf(void*, char *s)
416 {
417 int i;
418 for(i = 0;syssigname[i];i++) if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){
419 if(strncmp(s, "sys: ", 5)!=0) interrupted = 1;
420 goto Out;
421 }
422 pfmt(err, "rc: note: %s\n", s);
423 noted(NDFLT);
424 return;
425 Out:
426 if(strcmp(s, "interrupt")!=0 || trap[i]==0){
427 trap[i]++;
428 ntrap++;
429 }
430 if(ntrap>=32){ /* rc is probably in a trap loop */
431 pfmt(err, "rc: Too many traps (trap %s), aborting\n", s);
432 abort();
433 }
434 noted(NCONT);
435 }
436
437 void
Trapinit(void)438 Trapinit(void)
439 {
440 notify(notifyf);
441 }
442
443 void
Unlink(char * name)444 Unlink(char *name)
445 {
446 remove(name);
447 }
448
449 long
Write(int fd,void * buf,long cnt)450 Write(int fd, void *buf, long cnt)
451 {
452 return write(fd, buf, (long)cnt);
453 }
454
455 long
Read(int fd,void * buf,long cnt)456 Read(int fd, void *buf, long cnt)
457 {
458 return read(fd, buf, cnt);
459 }
460
461 long
Seek(int fd,long cnt,long whence)462 Seek(int fd, long cnt, long whence)
463 {
464 return seek(fd, cnt, whence);
465 }
466
467 int
Executable(char * file)468 Executable(char *file)
469 {
470 Dir *statbuf;
471 int ret;
472
473 statbuf = dirstat(file);
474 if(statbuf == nil)
475 return 0;
476 ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0);
477 free(statbuf);
478 return ret;
479 }
480
481 int
Creat(char * file)482 Creat(char *file)
483 {
484 return create(file, 1, 0666L);
485 }
486
487 int
Dup(int a,int b)488 Dup(int a, int b)
489 {
490 return dup(a, b);
491 }
492
493 int
Dup1(int)494 Dup1(int)
495 {
496 return -1;
497 }
498
499 void
Exit(char * stat)500 Exit(char *stat)
501 {
502 Updenv();
503 setstatus(stat);
504 exits(truestatus()?"":getstatus());
505 }
506
507 int
Eintr(void)508 Eintr(void)
509 {
510 return interrupted;
511 }
512
513 void
Noerror(void)514 Noerror(void)
515 {
516 interrupted = 0;
517 }
518
519 int
Isatty(int fd)520 Isatty(int fd)
521 {
522 Dir *d1, *d2;
523 int ret;
524
525 d1 = dirfstat(fd);
526 if(d1 == nil)
527 return 0;
528 if(strncmp(d1->name, "ptty", 4)==0){ /* fwd complaints to philw */
529 free(d1);
530 return 1;
531 }
532 d2 = dirstat("/dev/cons");
533 if(d2 == nil){
534 free(d1);
535 return 0;
536 }
537 ret = (d1->type==d2->type&&d1->dev==d2->dev&&d1->qid.path==d2->qid.path);
538 free(d1);
539 free(d2);
540 return ret;
541 }
542
543 void
Abort(void)544 Abort(void)
545 {
546 pfmt(err, "aborting\n");
547 flush(err);
548 Exit("aborting");
549 }
550
551 void
Memcpy(void * a,void * b,long n)552 Memcpy(void *a, void *b, long n)
553 {
554 memmove(a, b, n);
555 }
556
557 void*
Malloc(ulong n)558 Malloc(ulong n)
559 {
560 return malloc(n);
561 }
562