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