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