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