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