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