plan9ish.c (10617B)
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* 28 Rcmain(void) 29 { 30 return unsharp("#9/etc/rcmain"); 31 } 32 33 char Fdprefix[]="/dev/fd/"; 34 long readnb(int, char *, long); 35 void execfinit(void); 36 void execbind(void); 37 void execmount(void); 38 void execulimit(void); 39 void execumask(void); 40 void execrfork(void); 41 builtin Builtin[]={ 42 "cd", execcd, 43 "whatis", execwhatis, 44 "eval", execeval, 45 "exec", execexec, /* but with popword first */ 46 "exit", execexit, 47 "shift", execshift, 48 "wait", execwait, 49 ".", execdot, 50 "finit", execfinit, 51 "flag", execflag, 52 "ulimit", execulimit, 53 "umask", execumask, 54 "rfork", execrfork, 55 0 56 }; 57 58 void 59 execrfork(void) 60 { 61 int arg; 62 char *s; 63 64 switch(count(runq->argv->words)){ 65 case 1: 66 arg = RFENVG|RFNOTEG|RFNAMEG; 67 break; 68 case 2: 69 arg = 0; 70 for(s = runq->argv->words->next->word;*s;s++) switch(*s){ 71 default: 72 goto Usage; 73 case 'n': 74 arg|=RFNAMEG; break; 75 case 'N': 76 arg|=RFCNAMEG; 77 break; 78 case 'e': 79 /* arg|=RFENVG; */ break; 80 case 'E': 81 arg|=RFCENVG; break; 82 case 's': 83 arg|=RFNOTEG; break; 84 case 'f': 85 arg|=RFFDG; break; 86 case 'F': 87 arg|=RFCFDG; break; 88 } 89 break; 90 default: 91 Usage: 92 pfmt(err, "Usage: %s [nNeEsfF]\n", runq->argv->words->word); 93 setstatus("rfork usage"); 94 poplist(); 95 return; 96 } 97 if(rfork(arg)==-1){ 98 pfmt(err, "rc: %s failed\n", runq->argv->words->word); 99 setstatus("rfork failed"); 100 } 101 else 102 setstatus(""); 103 poplist(); 104 } 105 106 107 108 #define SEP '\1' 109 char **environp; 110 struct word *enval(s) 111 register char *s; 112 { 113 register char *t, c; 114 register struct word *v; 115 for(t=s;*t && *t!=SEP;t++); 116 c=*t; 117 *t='\0'; 118 v=newword(s, c=='\0'?(struct word *)0:enval(t+1)); 119 *t=c; 120 return v; 121 } 122 void Vinit(void){ 123 extern char **environ; 124 register char *s; 125 register char **env=environ; 126 environp=env; 127 for(;*env;env++){ 128 for(s=*env;*s && *s!='(' && *s!='=';s++); 129 switch(*s){ 130 case '\0': 131 /* pfmt(err, "rc: odd environment %q?\n", *env); */ 132 break; 133 case '=': 134 *s='\0'; 135 setvar(*env, enval(s+1)); 136 *s='='; 137 break; 138 case '(': /* ignore functions for now */ 139 break; 140 } 141 } 142 } 143 char **envp; 144 void Xrdfn(void){ 145 char *p; 146 register char *s; 147 register int len; 148 for(;*envp;envp++){ 149 s = *envp; 150 if(strncmp(s, "fn#", 3) == 0){ 151 p = strchr(s, '='); 152 if(p == nil) 153 continue; 154 *p = ' '; 155 s[2] = ' '; 156 len = strlen(s); 157 execcmds(opencore(s, len)); 158 s[len] = '\0'; 159 return; 160 } 161 #if 0 162 for(s=*envp;*s && *s!='(' && *s!='=';s++); 163 switch(*s){ 164 case '\0': 165 pfmt(err, "environment %q?\n", *envp); 166 break; 167 case '=': /* ignore variables */ 168 break; 169 case '(': /* Bourne again */ 170 s=*envp+3; 171 envp++; 172 len=strlen(s); 173 s[len]='\n'; 174 execcmds(opencore(s, len+1)); 175 s[len]='\0'; 176 return; 177 } 178 #endif 179 } 180 Xreturn(); 181 } 182 union code rdfns[4]; 183 void execfinit(void){ 184 static int first=1; 185 if(first){ 186 rdfns[0].i=1; 187 rdfns[1].f=Xrdfn; 188 rdfns[2].f=Xjump; 189 rdfns[3].i=1; 190 first=0; 191 } 192 Xpopm(); 193 envp=environp; 194 start(rdfns, 1, runq->local); 195 } 196 extern int mapfd(int); 197 int Waitfor(int pid, int unused0){ 198 thread *p; 199 Waitmsg *w; 200 char errbuf[ERRMAX]; 201 202 if(pid >= 0 && !havewaitpid(pid)) 203 return 0; 204 while((w = wait()) != nil){ 205 delwaitpid(w->pid); 206 if(w->pid==pid){ 207 if(strncmp(w->msg, "signal: ", 8) == 0) 208 fprint(mapfd(2), "%d: %s\n", w->pid, w->msg); 209 setstatus(w->msg); 210 free(w); 211 return 0; 212 } 213 if(runq->iflag && strncmp(w->msg, "signal: ", 8) == 0) 214 fprint(2, "%d: %s\n", w->pid, w->msg); 215 for(p=runq->ret;p;p=p->ret) 216 if(p->pid==w->pid){ 217 p->pid=-1; 218 strcpy(p->status, w->msg); 219 } 220 free(w); 221 } 222 223 rerrstr(errbuf, sizeof errbuf); 224 if(strcmp(errbuf, "interrupted")==0) return -1; 225 return 0; 226 } 227 char **mkargv(word *a) 228 { 229 char **argv=(char **)emalloc((count(a)+2)*sizeof(char *)); 230 char **argp=argv+1; /* leave one at front for runcoms */ 231 for(;a;a=a->next) *argp++=a->word; 232 *argp=0; 233 return argv; 234 } 235 /* 236 void addenv(var *v) 237 { 238 char envname[256]; 239 word *w; 240 int f; 241 io *fd; 242 if(v->changed){ 243 v->changed=0; 244 snprint(envname, sizeof envname, "/env/%s", v->name); 245 if((f=Creat(envname))<0) 246 pfmt(err, "rc: can't open %s: %r\n", envname); 247 else{ 248 for(w=v->val;w;w=w->next) 249 write(f, w->word, strlen(w->word)+1L); 250 close(f); 251 } 252 } 253 if(v->fnchanged){ 254 v->fnchanged=0; 255 snprint(envname, sizeof envname, "/env/fn#%s", v->name); 256 if((f=Creat(envname))<0) 257 pfmt(err, "rc: can't open %s: %r\n", envname); 258 else{ 259 if(v->fn){ 260 fd=openfd(f); 261 pfmt(fd, "fn %s %s\n", v->name, v->fn[v->pc-1].s); 262 closeio(fd); 263 } 264 close(f); 265 } 266 } 267 } 268 void updenvlocal(var *v) 269 { 270 if(v){ 271 updenvlocal(v->next); 272 addenv(v); 273 } 274 } 275 void Updenv(void){ 276 var *v, **h; 277 for(h=gvar;h!=&gvar[NVAR];h++) 278 for(v=*h;v;v=v->next) 279 addenv(v); 280 if(runq) updenvlocal(runq->local); 281 } 282 */ 283 int 284 cmpenv(const void *a, const void *b) 285 { 286 return strcmp(*(char**)a, *(char**)b); 287 } 288 char **mkenv(){ 289 register char **env, **ep, *p, *q; 290 register struct var **h, *v; 291 register struct word *a; 292 register int nvar=0, nchr=0, sep; 293 /* 294 * Slightly kludgy loops look at locals then globals 295 */ 296 for(h=gvar-1;h!=&gvar[NVAR];h++) for(v=h>=gvar?*h:runq->local;v;v=v->next){ 297 if((v==vlook(v->name)) && v->val){ 298 nvar++; 299 nchr+=strlen(v->name)+1; 300 for(a=v->val;a;a=a->next) 301 nchr+=strlen(a->word)+1; 302 } 303 if(v->fn){ 304 nvar++; 305 nchr+=strlen(v->name)+strlen(v->fn[v->pc-1].s)+8; 306 } 307 } 308 env=(char **)emalloc((nvar+1)*sizeof(char *)+nchr); 309 ep=env; 310 p=(char *)&env[nvar+1]; 311 for(h=gvar-1;h!=&gvar[NVAR];h++) for(v=h>=gvar?*h:runq->local;v;v=v->next){ 312 if((v==vlook(v->name)) && v->val){ 313 *ep++=p; 314 q=v->name; 315 while(*q) *p++=*q++; 316 sep='='; 317 for(a=v->val;a;a=a->next){ 318 *p++=sep; 319 sep=SEP; 320 q=a->word; 321 while(*q) *p++=*q++; 322 } 323 *p++='\0'; 324 } 325 if(v->fn){ 326 *ep++=p; 327 #if 0 328 *p++='#'; *p++='('; *p++=')'; /* to fool Bourne */ 329 *p++='f'; *p++='n'; *p++=' '; 330 q=v->name; 331 while(*q) *p++=*q++; 332 *p++=' '; 333 #endif 334 *p++='f'; *p++='n'; *p++='#'; 335 q=v->name; 336 while(*q) *p++=*q++; 337 *p++='='; 338 q=v->fn[v->pc-1].s; 339 while(*q) *p++=*q++; 340 *p++='\n'; 341 *p++='\0'; 342 } 343 } 344 *ep=0; 345 qsort((char *)env, nvar, sizeof ep[0], cmpenv); 346 return env; 347 } 348 void Updenv(void){} 349 void Execute(word *args, word *path) 350 { 351 char **argv=mkargv(args); 352 char **env=mkenv(); 353 char file[1024]; 354 int nc; 355 Updenv(); 356 for(;path;path=path->next){ 357 nc=strlen(path->word); 358 if(nc<1024){ 359 strcpy(file, path->word); 360 if(file[0]){ 361 strcat(file, "/"); 362 nc++; 363 } 364 if(nc+strlen(argv[1])<1024){ 365 strcat(file, argv[1]); 366 execve(file, argv+1, env); 367 } 368 else werrstr("command name too long"); 369 } 370 } 371 rerrstr(file, sizeof file); 372 pfmt(err, "%s: %s\n", argv[1], file); 373 efree((char *)argv); 374 } 375 #define NDIR 256 /* shoud be a better way */ 376 int Globsize(char *p) 377 { 378 ulong isglob=0, globlen=NDIR+1; 379 for(;*p;p++){ 380 if(*p==GLOB){ 381 p++; 382 if(*p!=GLOB) isglob++; 383 globlen+=*p=='*'?NDIR:1; 384 } 385 else 386 globlen++; 387 } 388 return isglob?globlen:0; 389 } 390 #define NFD 50 391 #define NDBUF 32 392 struct{ 393 Dir *dbuf; 394 int i; 395 int n; 396 }dir[NFD]; 397 int Opendir(char *name) 398 { 399 Dir *db; 400 int f; 401 f=open(name, 0); 402 if(f==-1) 403 return f; 404 db = dirfstat(f); 405 if(db!=nil && (db->mode&DMDIR)){ 406 if(f<NFD){ 407 dir[f].i=0; 408 dir[f].n=0; 409 } 410 free(db); 411 return f; 412 } 413 free(db); 414 close(f); 415 return -1; 416 } 417 int Readdir(int f, char *p, int onlydirs) 418 { 419 int n; 420 USED(onlydirs); /* only advisory */ 421 422 if(f<0 || f>=NFD) 423 return 0; 424 if(dir[f].i==dir[f].n){ /* read */ 425 free(dir[f].dbuf); 426 dir[f].dbuf=0; 427 n=dirread(f, &dir[f].dbuf); 428 if(n>=0) 429 dir[f].n=n; 430 else 431 dir[f].n=0; 432 dir[f].i=0; 433 } 434 if(dir[f].i==dir[f].n) 435 return 0; 436 strcpy(p, dir[f].dbuf[dir[f].i].name); 437 dir[f].i++; 438 return 1; 439 } 440 void Closedir(int f){ 441 if(f>=0 && f<NFD){ 442 free(dir[f].dbuf); 443 dir[f].i=0; 444 dir[f].n=0; 445 dir[f].dbuf=0; 446 } 447 close(f); 448 } 449 int interrupted = 0; 450 void 451 notifyf(void *unused0, char *s) 452 { 453 int i; 454 for(i=0;syssigname[i];i++) 455 if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){ 456 if(strncmp(s, "sys: ", 5)!=0){ 457 if(kidpid && !interrupted){ 458 interrupted=1; 459 postnote(PNGROUP, kidpid, s); 460 } 461 interrupted = 1; 462 } 463 goto Out; 464 } 465 if(strcmp(s, "sys: window size change") != 0) 466 if(strcmp(s, "sys: write on closed pipe") != 0) 467 if(strcmp(s, "sys: child") != 0) 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 void Trapinit(void){ 483 notify(notifyf); 484 } 485 void Unlink(char *name) 486 { 487 remove(name); 488 } 489 long Write(int fd, char *buf, long cnt) 490 { 491 return write(fd, buf, (long)cnt); 492 } 493 long Read(int fd, char *buf, long cnt) 494 { 495 int i; 496 497 i = readnb(fd, buf, cnt); 498 if(ntrap) dotrap(); 499 return i; 500 } 501 long Seek(int fd, long cnt, long whence) 502 { 503 return seek(fd, cnt, whence); 504 } 505 int Executable(char *file) 506 { 507 Dir *statbuf; 508 int ret; 509 510 statbuf = dirstat(file); 511 if(statbuf == nil) return 0; 512 ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0); 513 free(statbuf); 514 return ret; 515 } 516 int Creat(char *file) 517 { 518 return create(file, 1, 0666L); 519 } 520 int Dup(int a, int b){ 521 return dup(a, b); 522 } 523 int Dup1(int a){ 524 return dup(a, -1); 525 } 526 void Exit(char *stat) 527 { 528 Updenv(); 529 setstatus(stat); 530 exits(truestatus()?"":getstatus()); 531 } 532 int Eintr(void){ 533 return interrupted; 534 } 535 void Noerror(void){ 536 interrupted=0; 537 } 538 int 539 Isatty(int fd){ 540 return isatty(fd); 541 } 542 void Abort(void){ 543 pfmt(err, "aborting\n"); 544 flush(err); 545 Exit("aborting"); 546 } 547 void Memcpy(char *a, char *b, long n) 548 { 549 memmove(a, b, (long)n); 550 } 551 void *Malloc(ulong n){ 552 return malloc(n); 553 } 554 555 int 556 exitcode(char *msg) 557 { 558 int n; 559 560 n = atoi(msg); 561 if(n == 0) 562 n = 1; 563 return n; 564 } 565 566 int *waitpids; 567 int nwaitpids; 568 569 void 570 addwaitpid(int pid) 571 { 572 waitpids = realloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]); 573 if(waitpids == 0) 574 panic("Can't realloc %d waitpids", nwaitpids+1); 575 waitpids[nwaitpids++] = pid; 576 } 577 578 void 579 delwaitpid(int pid) 580 { 581 int r, w; 582 583 for(r=w=0; r<nwaitpids; r++) 584 if(waitpids[r] != pid) 585 waitpids[w++] = waitpids[r]; 586 nwaitpids = w; 587 } 588 589 void 590 clearwaitpids(void) 591 { 592 nwaitpids = 0; 593 } 594 595 int 596 havewaitpid(int pid) 597 { 598 int i; 599 600 for(i=0; i<nwaitpids; i++) 601 if(waitpids[i] == pid) 602 return 1; 603 return 0; 604 }