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