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 int Readdir(int f, char *p) 322 { 323 int n; 324 if(f<0 || f>=NFD) 325 return 0; 326 if(dir[f].i==dir[f].n){ /* read */ 327 free(dir[f].dbuf); 328 dir[f].dbuf=0; 329 n=dirread(f, &dir[f].dbuf); 330 if(n>=0) 331 dir[f].n=n; 332 else 333 dir[f].n=0; 334 dir[f].i=0; 335 } 336 if(dir[f].i==dir[f].n) 337 return 0; 338 strcpy(p, dir[f].dbuf[dir[f].i].name); 339 dir[f].i++; 340 return 1; 341 } 342 void Closedir(int f){ 343 if(f>=0 && f<NFD){ 344 free(dir[f].dbuf); 345 dir[f].i=0; 346 dir[f].n=0; 347 dir[f].dbuf=0; 348 } 349 close(f); 350 } 351 int interrupted = 0; 352 void 353 notifyf(void*, char *s) 354 { 355 int i; 356 for(i=0;syssigname[i];i++) if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){ 357 if(strncmp(s, "sys: ", 5)!=0) interrupted=1; 358 goto Out; 359 } 360 pfmt(err, "rc: note: %s\n", s); 361 noted(NDFLT); 362 return; 363 Out: 364 if(strcmp(s, "interrupt")!=0 || trap[i]==0){ 365 trap[i]++; 366 ntrap++; 367 } 368 if(ntrap>=32){ /* rc is probably in a trap loop */ 369 pfmt(err, "rc: Too many traps (trap %s), aborting\n", s); 370 abort(); 371 } 372 noted(NCONT); 373 } 374 void Trapinit(void){ 375 notify(notifyf); 376 } 377 void Unlink(char *name) 378 { 379 remove(name); 380 } 381 long Write(int fd, char *buf, long cnt) 382 { 383 return write(fd, buf, (long)cnt); 384 } 385 long Read(int fd, char *buf, long cnt) 386 { 387 return read(fd, buf, cnt); 388 } 389 long Seek(int fd, long cnt, long whence) 390 { 391 return seek(fd, cnt, whence); 392 } 393 int Executable(char *file) 394 { 395 Dir *statbuf; 396 int ret; 397 398 statbuf = dirstat(file); 399 if(statbuf == nil) return 0; 400 ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0); 401 free(statbuf); 402 return ret; 403 } 404 int Creat(char *file) 405 { 406 return create(file, 1, 0666L); 407 } 408 int Dup(int a, int b){ 409 return dup(a, b); 410 } 411 int Dup1(int){ 412 return -1; 413 } 414 void Exit(char *stat) 415 { 416 Updenv(); 417 setstatus(stat); 418 exits(truestatus()?"":getstatus()); 419 } 420 int Eintr(void){ 421 return interrupted; 422 } 423 void Noerror(void){ 424 interrupted=0; 425 } 426 int Isatty(int fd){ 427 Dir *d1, *d2; 428 int ret; 429 430 d1 = dirfstat(fd); 431 if(d1 == nil) return 0; 432 if(strncmp(d1->name, "ptty", 4)==0){ /* fwd complaints to philw */ 433 free(d1); 434 return 1; 435 } 436 d2 = dirstat("/dev/cons"); 437 if(d2 == nil){ 438 free(d1); 439 return 0; 440 } 441 ret = (d1->type==d2->type&&d1->dev==d2->dev&&d1->qid.path==d2->qid.path); 442 free(d1); 443 free(d2); 444 return ret; 445 } 446 void Abort(void){ 447 pfmt(err, "aborting\n"); 448 flush(err); 449 Exit("aborting"); 450 } 451 void Memcpy(char *a, char *b, long n) 452 { 453 memmove(a, b, (long)n); 454 } 455 void *Malloc(ulong n){ 456 return malloc(n); 457 } 458