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, runq->local); 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 fcntl(wdirfd, F_SETFD, FD_CLOEXEC); 150 write(wdirfd, word, strlen(word)); 151 } 152 } 153 return 1; 154 } 155 156 static char * 157 appfile(char *dir, char *comp) 158 { 159 int dirlen, complen; 160 char *s, *p; 161 162 dirlen = strlen(dir); 163 complen = strlen(comp); 164 s = emalloc(dirlen + 1 + complen + 1); 165 memmove(s, dir, dirlen); 166 p = s + dirlen; 167 *p++ = '/'; 168 memmove(p, comp, complen); 169 p[complen] = '\0'; 170 return s; 171 } 172 173 void 174 execcd(void) 175 { 176 word *a = runq->argv->words; 177 word *cdpath; 178 char *dir; 179 180 setstatus("can't cd"); 181 cdpath = vlook("cdpath")->val; 182 switch(count(a)){ 183 default: 184 pfmt(err, "Usage: cd [directory]\n"); 185 break; 186 case 2: 187 if(a->next->word[0]=='/' || cdpath==0) 188 cdpath = &nullpath; 189 for(; cdpath; cdpath = cdpath->next){ 190 if(cdpath->word[0] != '\0') 191 dir = appfile(cdpath->word, a->next->word); 192 else 193 dir = strdup(a->next->word); 194 195 if(dochdir(dir) >= 0){ 196 if(cdpath->word[0] != '\0' && 197 strcmp(cdpath->word, ".") != 0) 198 pfmt(err, "%s\n", dir); 199 free(dir); 200 setstatus(""); 201 break; 202 } 203 free(dir); 204 } 205 if(cdpath==0) 206 pfmt(err, "Can't cd %s: %r\n", a->next->word); 207 break; 208 case 1: 209 a = vlook("home")->val; 210 if(count(a)>=1){ 211 if(dochdir(a->word)>=0) 212 setstatus(""); 213 else 214 pfmt(err, "Can't cd %s: %r\n", a->word); 215 } 216 else 217 pfmt(err, "Can't cd -- $home empty\n"); 218 break; 219 } 220 poplist(); 221 } 222 223 void 224 execexit(void) 225 { 226 switch(count(runq->argv->words)){ 227 default: 228 pfmt(err, "Usage: exit [status]\nExiting anyway\n"); 229 case 2: 230 setstatus(runq->argv->words->next->word); 231 case 1: Xexit(); 232 } 233 } 234 235 void 236 execshift(void) 237 { 238 int n; 239 word *a; 240 var *star; 241 switch(count(runq->argv->words)){ 242 default: 243 pfmt(err, "Usage: shift [n]\n"); 244 setstatus("shift usage"); 245 poplist(); 246 return; 247 case 2: 248 n = atoi(runq->argv->words->next->word); 249 break; 250 case 1: 251 n = 1; 252 break; 253 } 254 star = vlook("*"); 255 for(;n && star->val;--n){ 256 a = star->val->next; 257 efree(star->val->word); 258 efree((char *)star->val); 259 star->val = a; 260 star->changed = 1; 261 } 262 setstatus(""); 263 poplist(); 264 } 265 266 int 267 octal(char *s) 268 { 269 int n = 0; 270 while(*s==' ' || *s=='\t' || *s=='\n') s++; 271 while('0'<=*s && *s<='7') n = n*8+*s++-'0'; 272 return n; 273 } 274 275 int 276 mapfd(int fd) 277 { 278 redir *rp; 279 for(rp = runq->redir;rp;rp = rp->next){ 280 switch(rp->type){ 281 case RCLOSE: 282 if(rp->from==fd) 283 fd=-1; 284 break; 285 case RDUP: 286 case ROPEN: 287 if(rp->to==fd) 288 fd = rp->from; 289 break; 290 } 291 } 292 return fd; 293 } 294 union code rdcmds[4]; 295 296 void 297 execcmds(io *f) 298 { 299 static int first = 1; 300 if(first){ 301 rdcmds[0].i = 1; 302 rdcmds[1].f = Xrdcmds; 303 rdcmds[2].f = Xreturn; 304 first = 0; 305 } 306 start(rdcmds, 1, runq->local); 307 runq->cmdfd = f; 308 runq->iflast = 0; 309 } 310 311 void 312 execeval(void) 313 { 314 char *cmdline, *s, *t; 315 int len = 0; 316 word *ap; 317 if(count(runq->argv->words)<=1){ 318 Xerror1("Usage: eval cmd ..."); 319 return; 320 } 321 eflagok = 1; 322 for(ap = runq->argv->words->next;ap;ap = ap->next) 323 len+=1+strlen(ap->word); 324 cmdline = emalloc(len); 325 s = cmdline; 326 for(ap = runq->argv->words->next;ap;ap = ap->next){ 327 for(t = ap->word;*t;) *s++=*t++; 328 *s++=' '; 329 } 330 s[-1]='\n'; 331 poplist(); 332 execcmds(opencore(cmdline, len)); 333 efree(cmdline); 334 } 335 union code dotcmds[14]; 336 337 void 338 execdot(void) 339 { 340 int iflag = 0; 341 int fd; 342 list *av; 343 thread *p = runq; 344 char *zero, *file; 345 word *path; 346 static int first = 1; 347 348 if(first){ 349 dotcmds[0].i = 1; 350 dotcmds[1].f = Xmark; 351 dotcmds[2].f = Xword; 352 dotcmds[3].s="0"; 353 dotcmds[4].f = Xlocal; 354 dotcmds[5].f = Xmark; 355 dotcmds[6].f = Xword; 356 dotcmds[7].s="*"; 357 dotcmds[8].f = Xlocal; 358 dotcmds[9].f = Xrdcmds; 359 dotcmds[10].f = Xunlocal; 360 dotcmds[11].f = Xunlocal; 361 dotcmds[12].f = Xreturn; 362 first = 0; 363 } 364 else 365 eflagok = 1; 366 popword(); 367 if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){ 368 iflag = 1; 369 popword(); 370 } 371 /* get input file */ 372 if(p->argv->words==0){ 373 Xerror1("Usage: . [-i] file [arg ...]"); 374 return; 375 } 376 zero = strdup(p->argv->words->word); 377 popword(); 378 fd = -1; 379 for(path = searchpath(zero); path; path = path->next){ 380 if(path->word[0] != '\0') 381 file = appfile(path->word, zero); 382 else 383 file = strdup(zero); 384 385 fd = open(file, 0); 386 free(file); 387 if(fd >= 0) 388 break; 389 if(strcmp(file, "/dev/stdin")==0){ /* for sun & ucb */ 390 fd = Dup1(0); 391 if(fd>=0) 392 break; 393 } 394 } 395 if(fd<0){ 396 pfmt(err, "%s: ", zero); 397 setstatus("can't open"); 398 Xerror(".: can't open"); 399 return; 400 } 401 /* set up for a new command loop */ 402 start(dotcmds, 1, (struct var *)0); 403 pushredir(RCLOSE, fd, 0); 404 runq->cmdfile = zero; 405 runq->cmdfd = openfd(fd); 406 runq->iflag = iflag; 407 runq->iflast = 0; 408 /* push $* value */ 409 pushlist(); 410 runq->argv->words = p->argv->words; 411 /* free caller's copy of $* */ 412 av = p->argv; 413 p->argv = av->next; 414 efree((char *)av); 415 /* push $0 value */ 416 pushlist(); 417 pushword(zero); 418 ndot++; 419 } 420 421 void 422 execflag(void) 423 { 424 char *letter, *val; 425 switch(count(runq->argv->words)){ 426 case 2: 427 setstatus(flag[(uchar)runq->argv->words->next->word[0]]?"":"flag not set"); 428 break; 429 case 3: 430 letter = runq->argv->words->next->word; 431 val = runq->argv->words->next->next->word; 432 if(strlen(letter)==1){ 433 if(strcmp(val, "+")==0){ 434 flag[(uchar)letter[0]] = flagset; 435 break; 436 } 437 if(strcmp(val, "-")==0){ 438 flag[(uchar)letter[0]] = 0; 439 break; 440 } 441 } 442 default: 443 Xerror1("Usage: flag [letter] [+-]"); 444 return; 445 } 446 poplist(); 447 } 448 449 void 450 execwhatis(void){ /* mildly wrong -- should fork before writing */ 451 word *a, *b, *path; 452 var *v; 453 struct builtin *bp; 454 char *file; 455 struct io out[1]; 456 int found, sep; 457 a = runq->argv->words->next; 458 if(a==0){ 459 Xerror1("Usage: whatis name ..."); 460 return; 461 } 462 setstatus(""); 463 memset(out, 0, sizeof out); 464 out->fd = mapfd(1); 465 out->bufp = out->buf; 466 out->ebuf = &out->buf[NBUF]; 467 out->strp = 0; 468 for(;a;a = a->next){ 469 v = vlook(a->word); 470 if(v->val){ 471 pfmt(out, "%s=", a->word); 472 if(v->val->next==0) 473 pfmt(out, "%q\n", v->val->word); 474 else{ 475 sep='('; 476 for(b = v->val;b && b->word;b = b->next){ 477 pfmt(out, "%c%q", sep, b->word); 478 sep=' '; 479 } 480 pfmt(out, ")\n"); 481 } 482 found = 1; 483 } 484 else 485 found = 0; 486 v = gvlook(a->word); 487 if(v->fn) 488 pfmt(out, "fn %q %s\n", v->name, v->fn[v->pc-1].s); 489 else{ 490 for(bp = Builtin;bp->name;bp++) 491 if(strcmp(a->word, bp->name)==0){ 492 pfmt(out, "builtin %s\n", a->word); 493 break; 494 } 495 if(!bp->name){ 496 for(path = searchpath(a->word); path; 497 path = path->next){ 498 if(path->word[0] != '\0') 499 file = appfile(path->word, 500 a->word); 501 else 502 file = strdup(a->word); 503 if(Executable(file)){ 504 pfmt(out, "%s\n", file); 505 free(file); 506 break; 507 } 508 free(file); 509 } 510 if(!path && !found){ 511 pfmt(err, "%s: not found\n", a->word); 512 setstatus("not found"); 513 } 514 } 515 } 516 } 517 poplist(); 518 flush(err); 519 } 520 521 void 522 execwait(void) 523 { 524 switch(count(runq->argv->words)){ 525 default: 526 Xerror1("Usage: wait [pid]"); 527 return; 528 case 2: 529 Waitfor(atoi(runq->argv->words->next->word), 0); 530 break; 531 case 1: 532 Waitfor(-1, 0); 533 break; 534 } 535 poplist(); 536 } 537