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 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 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 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 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* 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 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 224 updenvlocal(var *v) 225 { 226 if(v){ 227 updenvlocal(v->next); 228 addenv(v); 229 } 230 } 231 232 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 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 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 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 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 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 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 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 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 438 Trapinit(void) 439 { 440 notify(notifyf); 441 } 442 443 void 444 Unlink(char *name) 445 { 446 remove(name); 447 } 448 449 long 450 Write(int fd, void *buf, long cnt) 451 { 452 return write(fd, buf, (long)cnt); 453 } 454 455 long 456 Read(int fd, void *buf, long cnt) 457 { 458 return read(fd, buf, cnt); 459 } 460 461 long 462 Seek(int fd, long cnt, long whence) 463 { 464 return seek(fd, cnt, whence); 465 } 466 467 int 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 482 Creat(char *file) 483 { 484 return create(file, 1, 0666L); 485 } 486 487 int 488 Dup(int a, int b) 489 { 490 return dup(a, b); 491 } 492 493 int 494 Dup1(int) 495 { 496 return -1; 497 } 498 499 void 500 Exit(char *stat) 501 { 502 Updenv(); 503 setstatus(stat); 504 exits(truestatus()?"":getstatus()); 505 } 506 507 int 508 Eintr(void) 509 { 510 return interrupted; 511 } 512 513 void 514 Noerror(void) 515 { 516 interrupted = 0; 517 } 518 519 int 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 544 Abort(void) 545 { 546 pfmt(err, "aborting\n"); 547 flush(err); 548 Exit("aborting"); 549 } 550 551 void 552 Memcpy(void *a, void *b, long n) 553 { 554 memmove(a, b, n); 555 } 556 557 void* 558 Malloc(ulong n) 559 { 560 return malloc(n); 561 } 562