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