1 /* 2 * Maybe `simple' is a misnomer. 3 */ 4 #include "rc.h" 5 #include "getflags.h" 6 #include "exec.h" 7 #include "io.h" 8 #include "fns.h" 9 /* 10 * Search through the following code to see if we're just going to exit. 11 */ 12 exitnext(void){ 13 union code *c=&runq->code[runq->pc]; 14 while(c->f==Xpopredir) c++; 15 return c->f==Xexit; 16 } 17 void Xsimple(void){ 18 word *a; 19 thread *p=runq; 20 var *v; 21 struct builtin *bp; 22 int pid; 23 globlist(); 24 a=runq->argv->words; 25 if(a==0){ 26 Xerror("empty argument list"); 27 return; 28 } 29 if(flag['x']) 30 pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */ 31 v=gvlook(a->word); 32 if(v->fn) 33 execfunc(v); 34 else{ 35 if(strcmp(a->word, "builtin")==0){ 36 if(count(a)==1){ 37 pfmt(err, "builtin: empty argument list\n"); 38 setstatus("empty arg list"); 39 poplist(); 40 return; 41 } 42 a=a->next; 43 popword(); 44 } 45 for(bp=Builtin;bp->name;bp++) 46 if(strcmp(a->word, bp->name)==0){ 47 (*bp->fnc)(); 48 return; 49 } 50 if(exitnext()){ 51 /* fork and wait is redundant */ 52 pushword("exec"); 53 execexec(); 54 Xexit(); 55 } 56 else{ 57 flush(err); 58 Updenv(); 59 switch(pid=fork()){ 60 case -1: 61 Xerror("try again"); 62 return; 63 case 0: 64 pushword("exec"); 65 execexec(); 66 Exit("can't exec"); 67 default: 68 poplist(); 69 /* interrupts don't get us out */ 70 while(Waitfor(pid, 1) < 0) 71 ; 72 } 73 } 74 } 75 } 76 struct word nullpath={ "", 0}; 77 void doredir(redir *rp) 78 { 79 if(rp){ 80 doredir(rp->next); 81 switch(rp->type){ 82 case ROPEN: 83 if(rp->from!=rp->to){ 84 Dup(rp->from, rp->to); 85 close(rp->from); 86 } 87 break; 88 case RDUP: Dup(rp->from, rp->to); break; 89 case RCLOSE: close(rp->from); break; 90 } 91 } 92 } 93 word *searchpath(char *w){ 94 word *path; 95 if(strncmp(w, "/", 1)==0 96 || strncmp(w, "#", 1)==0 97 || strncmp(w, "./", 2)==0 98 || strncmp(w, "../", 3)==0 99 || (path=vlook("path")->val)==0) 100 path=&nullpath; 101 return path; 102 } 103 void execexec(void){ 104 popword(); /* "exec" */ 105 if(runq->argv->words==0){ 106 Xerror("empty argument list"); 107 return; 108 } 109 doredir(runq->redir); 110 Execute(runq->argv->words, searchpath(runq->argv->words->word)); 111 poplist(); 112 } 113 void execfunc(var *func) 114 { 115 word *starval; 116 popword(); 117 starval=runq->argv->words; 118 runq->argv->words=0; 119 poplist(); 120 start(func->fn, func->pc, (struct var *)0); 121 runq->local=newvar(strdup("*"), runq->local); 122 runq->local->val=starval; 123 runq->local->changed=1; 124 } 125 int dochdir(char *word){ 126 /* report to /dev/wdir if it exists and we're interactive */ 127 static int wdirfd = -2; 128 if(chdir(word)<0) return -1; 129 if(flag['i']!=0){ 130 if(wdirfd==-2) /* try only once */ 131 wdirfd = open("/dev/wdir", OWRITE|OCEXEC); 132 if(wdirfd>=0) 133 write(wdirfd, word, strlen(word)); 134 } 135 return 1; 136 } 137 void execcd(void){ 138 word *a=runq->argv->words; 139 word *cdpath; 140 char dir[512]; 141 setstatus("can't cd"); 142 cdpath=vlook("cdpath")->val; 143 switch(count(a)){ 144 default: 145 pfmt(err, "Usage: cd [directory]\n"); 146 break; 147 case 2: 148 if(a->next->word[0]=='/' || cdpath==0) cdpath=&nullpath; 149 for(;cdpath;cdpath=cdpath->next){ 150 strcpy(dir, cdpath->word); 151 if(dir[0]) strcat(dir, "/"); 152 strcat(dir, a->next->word); 153 if(dochdir(dir)>=0){ 154 if(strlen(cdpath->word) 155 && strcmp(cdpath->word, ".")!=0) 156 pfmt(err, "%s\n", dir); 157 setstatus(""); 158 break; 159 } 160 } 161 if(cdpath==0) pfmt(err, "Can't cd %s\n", a->next->word); 162 break; 163 case 1: 164 a=vlook("home")->val; 165 if(count(a)>=1){ 166 if(dochdir(a->word)>=0) 167 setstatus(""); 168 else 169 pfmt(err, "Can't cd %s\n", a->word); 170 } 171 else 172 pfmt(err, "Can't cd -- $home empty\n"); 173 break; 174 } 175 poplist(); 176 } 177 void execexit(void){ 178 switch(count(runq->argv->words)){ 179 default: pfmt(err, "Usage: exit [status]\nExiting anyway\n"); 180 case 2: setstatus(runq->argv->words->next->word); 181 case 1: Xexit(); 182 } 183 } 184 void execshift(void){ 185 int n; 186 word *a; 187 var *star; 188 switch(count(runq->argv->words)){ 189 default: 190 pfmt(err, "Usage: shift [n]\n"); 191 setstatus("shift usage"); 192 poplist(); 193 return; 194 case 2: n=atoi(runq->argv->words->next->word); break; 195 case 1: n=1; break; 196 } 197 star=vlook("*"); 198 for(;n && star->val;--n){ 199 a=star->val->next; 200 efree(star->val->word); 201 efree((char *)star->val); 202 star->val=a; 203 star->changed=1; 204 } 205 setstatus(""); 206 poplist(); 207 } 208 int octal(char *s) 209 { 210 int n=0; 211 while(*s==' ' || *s=='\t' || *s=='\n') s++; 212 while('0'<=*s && *s<='7') n=n*8+*s++-'0'; 213 return n; 214 } 215 int mapfd(int fd) 216 { 217 redir *rp; 218 for(rp=runq->redir;rp;rp=rp->next){ 219 switch(rp->type){ 220 case RCLOSE: 221 if(rp->from==fd) fd=-1; 222 break; 223 case RDUP: 224 case ROPEN: 225 if(rp->to==fd) fd=rp->from; 226 break; 227 } 228 } 229 return fd; 230 } 231 union code rdcmds[4]; 232 void execcmds(io *f) 233 { 234 static int first=1; 235 if(first){ 236 rdcmds[0].i=1; 237 rdcmds[1].f=Xrdcmds; 238 rdcmds[2].f=Xreturn; 239 first=0; 240 } 241 start(rdcmds, 1, runq->local); 242 runq->cmdfd=f; 243 runq->iflast=0; 244 } 245 void execeval(void){ 246 char *cmdline, *s, *t; 247 int len=0; 248 word *ap; 249 if(count(runq->argv->words)<=1){ 250 Xerror("Usage: eval cmd ..."); 251 return; 252 } 253 eflagok=1; 254 for(ap=runq->argv->words->next;ap;ap=ap->next) 255 len+=1+strlen(ap->word); 256 cmdline=emalloc(len); 257 s=cmdline; 258 for(ap=runq->argv->words->next;ap;ap=ap->next){ 259 for(t=ap->word;*t;) *s++=*t++; 260 *s++=' '; 261 } 262 s[-1]='\n'; 263 poplist(); 264 execcmds(opencore(cmdline, len)); 265 efree(cmdline); 266 } 267 union code dotcmds[14]; 268 void execdot(void){ 269 int iflag=0; 270 int fd; 271 list *av; 272 thread *p=runq; 273 char *zero; 274 static int first=1; 275 char file[512]; 276 word *path; 277 if(first){ 278 dotcmds[0].i=1; 279 dotcmds[1].f=Xmark; 280 dotcmds[2].f=Xword; 281 dotcmds[3].s="0"; 282 dotcmds[4].f=Xlocal; 283 dotcmds[5].f=Xmark; 284 dotcmds[6].f=Xword; 285 dotcmds[7].s="*"; 286 dotcmds[8].f=Xlocal; 287 dotcmds[9].f=Xrdcmds; 288 dotcmds[10].f=Xunlocal; 289 dotcmds[11].f=Xunlocal; 290 dotcmds[12].f=Xreturn; 291 first=0; 292 } 293 else 294 eflagok=1; 295 popword(); 296 if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){ 297 iflag=1; 298 popword(); 299 } 300 /* get input file */ 301 if(p->argv->words==0){ 302 Xerror("Usage: . [-i] file [arg ...]"); 303 return; 304 } 305 zero=strdup(p->argv->words->word); 306 popword(); 307 fd=-1; 308 for(path=searchpath(zero);path;path=path->next){ 309 strcpy(file, path->word); 310 if(file[0]) strcat(file, "/"); 311 strcat(file, zero); 312 if((fd=open(file, 0))>=0) break; 313 if(strcmp(file, "/dev/stdin")==0){ /* for sun & ucb */ 314 fd=Dup1(0); 315 if(fd>=0) break; 316 } 317 } 318 if(fd<0){ 319 pfmt(err, "%s: ", zero); 320 setstatus("can't open"); 321 Xerror(".: can't open"); 322 return; 323 } 324 /* set up for a new command loop */ 325 start(dotcmds, 1, (struct var *)0); 326 pushredir(RCLOSE, fd, 0); 327 runq->cmdfile=zero; 328 runq->cmdfd=openfd(fd); 329 runq->iflag=iflag; 330 runq->iflast=0; 331 /* push $* value */ 332 pushlist(); 333 runq->argv->words=p->argv->words; 334 /* free caller's copy of $* */ 335 av=p->argv; 336 p->argv=av->next; 337 efree((char *)av); 338 /* push $0 value */ 339 pushlist(); 340 pushword(zero); 341 ndot++; 342 } 343 void execflag(void){ 344 char *letter, *val; 345 switch(count(runq->argv->words)){ 346 case 2: 347 setstatus(flag[runq->argv->words->next->word[0]]?"":"flag not set"); 348 break; 349 case 3: 350 letter=runq->argv->words->next->word; 351 val=runq->argv->words->next->next->word; 352 if(strlen(letter)==1){ 353 if(strcmp(val, "+")==0){ 354 flag[letter[0]]=flagset; 355 break; 356 } 357 if(strcmp(val, "-")==0){ 358 flag[letter[0]]=0; 359 break; 360 } 361 } 362 default: 363 Xerror("Usage: flag [letter] [+-]"); 364 return; 365 } 366 poplist(); 367 } 368 void execwhatis(void){ /* mildly wrong -- should fork before writing */ 369 word *a, *b, *path; 370 var *v; 371 struct builtin *bp; 372 char file[512]; 373 struct io out[1]; 374 int found, sep; 375 a=runq->argv->words->next; 376 if(a==0){ 377 Xerror("Usage: whatis name ..."); 378 return; 379 } 380 setstatus(""); 381 out->fd=mapfd(1); 382 out->bufp=out->buf; 383 out->ebuf=&out->buf[NBUF]; 384 out->strp=0; 385 for(;a;a=a->next){ 386 v=vlook(a->word); 387 if(v->val){ 388 pfmt(out, "%s=", a->word); 389 if(v->val->next==0) 390 pfmt(out, "%q\n", v->val->word); 391 else{ 392 sep='('; 393 for(b=v->val;b && b->word;b=b->next){ 394 pfmt(out, "%c%q", sep, b->word); 395 sep=' '; 396 } 397 pfmt(out, ")\n"); 398 } 399 found=1; 400 } 401 else 402 found=0; 403 v=gvlook(a->word); 404 if(v->fn) pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s); 405 else{ 406 for(bp=Builtin;bp->name;bp++) 407 if(strcmp(a->word, bp->name)==0){ 408 pfmt(out, "builtin %s\n", a->word); 409 break; 410 } 411 if(!bp->name){ 412 for(path=searchpath(a->word);path;path=path->next){ 413 strcpy(file, path->word); 414 if(file[0]) strcat(file, "/"); 415 strcat(file, a->word); 416 if(Executable(file)){ 417 pfmt(out, "%s\n", file); 418 break; 419 } 420 } 421 if(!path && !found){ 422 pfmt(err, "%s: not found\n", a->word); 423 setstatus("not found"); 424 } 425 } 426 } 427 } 428 poplist(); 429 flush(err); 430 } 431 void execwait(void){ 432 switch(count(runq->argv->words)){ 433 default: Xerror("Usage: wait [pid]"); return; 434 case 2: Waitfor(atoi(runq->argv->words->next->word), 0); break; 435 case 1: Waitfor(-1, 0); break; 436 } 437 poplist(); 438 } 439