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