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 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 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 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 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 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* 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 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 %s %s\n", v->name, v->fn[v->pc-1].s); 215 closeio(fd); 216 } 217 close(f); 218 } 219 } 220 } 221 222 void 223 updenvlocal(var *v) 224 { 225 if(v){ 226 updenvlocal(v->next); 227 addenv(v); 228 } 229 } 230 231 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 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 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 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 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 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 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 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 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 437 Trapinit(void) 438 { 439 notify(notifyf); 440 } 441 442 void 443 Unlink(char *name) 444 { 445 remove(name); 446 } 447 448 long 449 Write(int fd, void *buf, long cnt) 450 { 451 return write(fd, buf, (long)cnt); 452 } 453 454 long 455 Read(int fd, void *buf, long cnt) 456 { 457 return read(fd, buf, cnt); 458 } 459 460 long 461 Seek(int fd, long cnt, long whence) 462 { 463 return seek(fd, cnt, whence); 464 } 465 466 int 467 Executable(char *file) 468 { 469 Dir *statbuf; 470 int ret; 471 472 statbuf = dirstat(file); 473 if(statbuf == nil) 474 return 0; 475 ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0); 476 free(statbuf); 477 return ret; 478 } 479 480 int 481 Creat(char *file) 482 { 483 return create(file, 1, 0666L); 484 } 485 486 int 487 Dup(int a, int b) 488 { 489 return dup(a, b); 490 } 491 492 int 493 Dup1(int) 494 { 495 return -1; 496 } 497 498 void 499 Exit(char *stat) 500 { 501 Updenv(); 502 setstatus(stat); 503 exits(truestatus()?"":getstatus()); 504 } 505 506 int 507 Eintr(void) 508 { 509 return interrupted; 510 } 511 512 void 513 Noerror(void) 514 { 515 interrupted = 0; 516 } 517 518 int 519 Isatty(int fd) 520 { 521 Dir *d1, *d2; 522 int ret; 523 524 d1 = dirfstat(fd); 525 if(d1 == nil) 526 return 0; 527 if(strncmp(d1->name, "ptty", 4)==0){ /* fwd complaints to philw */ 528 free(d1); 529 return 1; 530 } 531 d2 = dirstat("/dev/cons"); 532 if(d2 == nil){ 533 free(d1); 534 return 0; 535 } 536 ret = (d1->type==d2->type&&d1->dev==d2->dev&&d1->qid.path==d2->qid.path); 537 free(d1); 538 free(d2); 539 return ret; 540 } 541 542 void 543 Abort(void) 544 { 545 pfmt(err, "aborting\n"); 546 flush(err); 547 Exit("aborting"); 548 } 549 550 void 551 Memcpy(void *a, void *b, long n) 552 { 553 memmove(a, b, n); 554 } 555 556 void* 557 Malloc(ulong n) 558 { 559 return malloc(n); 560 } 561