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 if(pid >= 0 && !havewaitpid(pid)) 211 return 0; 212 213 while((w = wait()) != nil){ 214 delwaitpid(w->pid); 215 if(w->pid==pid){ 216 setstatus(w->msg); 217 free(w); 218 return 0; 219 } 220 for(p = runq->ret;p;p = p->ret) 221 if(p->pid==w->pid){ 222 p->pid=-1; 223 strcpy(p->status, w->msg); 224 } 225 free(w); 226 } 227 228 errstr(errbuf, sizeof errbuf); 229 if(strcmp(errbuf, "interrupted")==0) return -1; 230 return 0; 231 } 232 233 char* 234 *mkargv(word *a) 235 { 236 char **argv = (char **)emalloc((count(a)+2)*sizeof(char *)); 237 char **argp = argv+1; /* leave one at front for runcoms */ 238 for(;a;a = a->next) *argp++=a->word; 239 *argp = 0; 240 return argv; 241 } 242 243 void 244 addenv(var *v) 245 { 246 char envname[256]; 247 word *w; 248 int f; 249 io *fd; 250 if(v->changed){ 251 v->changed = 0; 252 snprint(envname, sizeof envname, "/env/%s", v->name); 253 if((f = Creat(envname))<0) 254 pfmt(err, "rc: can't open %s: %r\n", envname); 255 else{ 256 for(w = v->val;w;w = w->next) 257 write(f, w->word, strlen(w->word)+1L); 258 close(f); 259 } 260 } 261 if(v->fnchanged){ 262 v->fnchanged = 0; 263 snprint(envname, sizeof envname, "/env/fn#%s", v->name); 264 if((f = Creat(envname))<0) 265 pfmt(err, "rc: can't open %s: %r\n", envname); 266 else{ 267 if(v->fn){ 268 fd = openfd(f); 269 pfmt(fd, "fn %s %s\n", v->name, v->fn[v->pc-1].s); 270 closeio(fd); 271 } 272 close(f); 273 } 274 } 275 } 276 277 void 278 updenvlocal(var *v) 279 { 280 if(v){ 281 updenvlocal(v->next); 282 addenv(v); 283 } 284 } 285 286 void 287 Updenv(void) 288 { 289 var *v, **h; 290 for(h = gvar;h!=&gvar[NVAR];h++) 291 for(v=*h;v;v = v->next) 292 addenv(v); 293 if(runq) 294 updenvlocal(runq->local); 295 } 296 297 int 298 ForkExecute(char *file, char **argv, int sin, int sout, int serr) 299 { 300 int pid; 301 302 if(access(file, 1) != 0) 303 return -1; 304 switch(pid = fork()){ 305 case -1: 306 return -1; 307 case 0: 308 if(sin >= 0) 309 dup(sin, 0); 310 else 311 close(0); 312 if(sout >= 0) 313 dup(sout, 1); 314 else 315 close(1); 316 if(serr >= 0) 317 dup(serr, 2); 318 else 319 close(2); 320 exec(file, argv); 321 exits(file); 322 } 323 return pid; 324 } 325 326 void 327 Execute(word *args, word *path) 328 { 329 char **argv = mkargv(args); 330 char file[1024]; 331 int nc; 332 Updenv(); 333 for(;path;path = path->next){ 334 nc = strlen(path->word); 335 if(nc<1024){ 336 strcpy(file, path->word); 337 if(file[0]){ 338 strcat(file, "/"); 339 nc++; 340 } 341 if(nc+strlen(argv[1])<1024){ 342 strcat(file, argv[1]); 343 exec(file, argv+1); 344 } 345 else werrstr("command name too long"); 346 } 347 } 348 rerrstr(file, sizeof file); 349 pfmt(err, "%s: %s\n", argv[1], file); 350 efree((char *)argv); 351 } 352 #define NDIR 256 /* shoud be a better way */ 353 354 int 355 Globsize(char *p) 356 { 357 int isglob = 0, globlen = NDIR+1; 358 for(;*p;p++){ 359 if(*p==GLOB){ 360 p++; 361 if(*p!=GLOB) 362 isglob++; 363 globlen+=*p=='*'?NDIR:1; 364 } 365 else 366 globlen++; 367 } 368 return isglob?globlen:0; 369 } 370 #define NFD 50 371 #define NDBUF 32 372 struct{ 373 Dir *dbuf; 374 int i; 375 int n; 376 }dir[NFD]; 377 378 int 379 Opendir(char *name) 380 { 381 Dir *db; 382 int f; 383 f = open(name, 0); 384 if(f==-1) 385 return f; 386 db = dirfstat(f); 387 if(db!=nil && (db->mode&DMDIR)){ 388 if(f<NFD){ 389 dir[f].i = 0; 390 dir[f].n = 0; 391 } 392 free(db); 393 return f; 394 } 395 free(db); 396 close(f); 397 return -1; 398 } 399 400 static int 401 trimdirs(Dir *d, int nd) 402 { 403 int r, w; 404 405 for(r=w=0; r<nd; r++) 406 if(d[r].mode&DMDIR) 407 d[w++] = d[r]; 408 return w; 409 } 410 411 /* 412 * onlydirs is advisory -- it means you only 413 * need to return the directories. it's okay to 414 * return files too (e.g., on unix where you can't 415 * tell during the readdir), but that just makes 416 * the globber work harder. 417 */ 418 int 419 Readdir(int f, char *p, int onlydirs) 420 { 421 int n; 422 423 if(f<0 || f>=NFD) 424 return 0; 425 Again: 426 if(dir[f].i==dir[f].n){ /* read */ 427 free(dir[f].dbuf); 428 dir[f].dbuf = 0; 429 n = dirread(f, &dir[f].dbuf); 430 if(n>0){ 431 if(onlydirs){ 432 n = trimdirs(dir[f].dbuf, n); 433 if(n == 0) 434 goto Again; 435 } 436 dir[f].n = n; 437 }else 438 dir[f].n = 0; 439 dir[f].i = 0; 440 } 441 if(dir[f].i == dir[f].n) 442 return 0; 443 strcpy(p, dir[f].dbuf[dir[f].i].name); 444 dir[f].i++; 445 return 1; 446 } 447 448 void 449 Closedir(int f) 450 { 451 if(f>=0 && f<NFD){ 452 free(dir[f].dbuf); 453 dir[f].i = 0; 454 dir[f].n = 0; 455 dir[f].dbuf = 0; 456 } 457 close(f); 458 } 459 int interrupted = 0; 460 void 461 notifyf(void*, char *s) 462 { 463 int i; 464 for(i = 0;syssigname[i];i++) if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){ 465 if(strncmp(s, "sys: ", 5)!=0) interrupted = 1; 466 goto Out; 467 } 468 pfmt(err, "rc: note: %s\n", s); 469 noted(NDFLT); 470 return; 471 Out: 472 if(strcmp(s, "interrupt")!=0 || trap[i]==0){ 473 trap[i]++; 474 ntrap++; 475 } 476 if(ntrap>=32){ /* rc is probably in a trap loop */ 477 pfmt(err, "rc: Too many traps (trap %s), aborting\n", s); 478 abort(); 479 } 480 noted(NCONT); 481 } 482 483 void 484 Trapinit(void) 485 { 486 notify(notifyf); 487 } 488 489 void 490 Unlink(char *name) 491 { 492 remove(name); 493 } 494 495 long 496 Write(int fd, char *buf, long cnt) 497 { 498 return write(fd, buf, (long)cnt); 499 } 500 501 long 502 Read(int fd, char *buf, long cnt) 503 { 504 return read(fd, buf, cnt); 505 } 506 507 long 508 Seek(int fd, long cnt, long whence) 509 { 510 return seek(fd, cnt, whence); 511 } 512 513 int 514 Executable(char *file) 515 { 516 Dir *statbuf; 517 int ret; 518 519 statbuf = dirstat(file); 520 if(statbuf == nil) 521 return 0; 522 ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0); 523 free(statbuf); 524 return ret; 525 } 526 527 int 528 Creat(char *file) 529 { 530 return create(file, 1, 0666L); 531 } 532 533 int 534 Dup(int a, int b) 535 { 536 return dup(a, b); 537 } 538 539 int 540 Dup1(int) 541 { 542 return -1; 543 } 544 545 void 546 Exit(char *stat) 547 { 548 Updenv(); 549 setstatus(stat); 550 exits(truestatus()?"":getstatus()); 551 } 552 553 int 554 Eintr(void) 555 { 556 return interrupted; 557 } 558 559 void 560 Noerror(void) 561 { 562 interrupted = 0; 563 } 564 565 int 566 Isatty(int fd) 567 { 568 char buf[64]; 569 570 if(fd2path(fd, buf, sizeof buf) != 0) 571 return 0; 572 573 /* might be #c/cons during boot - fixed 22 april 2005, remove this later */ 574 if(strcmp(buf, "#c/cons") == 0) 575 return 1; 576 577 /* might be /mnt/term/dev/cons */ 578 return strlen(buf) >= 9 && strcmp(buf+strlen(buf)-9, "/dev/cons") == 0; 579 } 580 581 void 582 Abort(void) 583 { 584 pfmt(err, "aborting\n"); 585 flush(err); 586 Exit("aborting"); 587 } 588 589 void 590 Memcpy(char *a, char *b, long n) 591 { 592 memmove(a, b, (long)n); 593 } 594 595 void* 596 Malloc(ulong n) 597 { 598 return malloc(n); 599 } 600 601 int *waitpids; 602 int nwaitpids; 603 604 void 605 addwaitpid(int pid) 606 { 607 waitpids = realloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]); 608 if(waitpids == 0) 609 panic("Can't realloc %d waitpids", nwaitpids+1); 610 waitpids[nwaitpids++] = pid; 611 } 612 613 void 614 delwaitpid(int pid) 615 { 616 int r, w; 617 618 for(r=w=0; r<nwaitpids; r++) 619 if(waitpids[r] != pid) 620 waitpids[w++] = waitpids[r]; 621 nwaitpids = w; 622 } 623 624 void 625 clearwaitpids(void) 626 { 627 nwaitpids = 0; 628 } 629 630 int 631 havewaitpid(int pid) 632 { 633 int i; 634 635 for(i=0; i<nwaitpids; i++) 636 if(waitpids[i] == pid) 637 return 1; 638 return 0; 639 } 640