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