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