| plan9ish.c - 9base - revived minimalist port of Plan 9 userland to Unix | |
| git clone git://git.suckless.org/9base | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| plan9ish.c (10617B) | |
| --- | |
| 1 /* | |
| 2 * Plan 9 versions of system-specific functions | |
| 3 * By convention, exported routines herein have names beginning w… | |
| 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 firs… | |
| 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->wo… | |
| 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->… | |
| 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-… | |
| 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;… | |
| 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;… | |
| 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 … | |
| 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 } |