1 /*- 2 * Copyright (c) 1980, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)exec.c 8.1 (Berkeley) 05/31/93"; 10 #endif /* not lint */ 11 12 #include <sys/types.h> 13 #include <sys/param.h> 14 #include <dirent.h> 15 #include <fcntl.h> 16 #include <sys/stat.h> 17 #include <errno.h> 18 #include <stdlib.h> 19 #include <string.h> 20 #include <unistd.h> 21 #if __STDC__ 22 # include <stdarg.h> 23 #else 24 # include <varargs.h> 25 #endif 26 27 #include "csh.h" 28 #include "extern.h" 29 30 /* 31 * System level search and execute of a command. We look in each directory 32 * for the specified command name. If the name contains a '/' then we 33 * execute only the full path name. If there is no search path then we 34 * execute only full path names. 35 */ 36 extern char **environ; 37 38 /* 39 * As we search for the command we note the first non-trivial error 40 * message for presentation to the user. This allows us often 41 * to show that a file has the wrong mode/no access when the file 42 * is not in the last component of the search path, so we must 43 * go on after first detecting the error. 44 */ 45 static char *exerr; /* Execution error message */ 46 static Char *expath; /* Path for exerr */ 47 48 /* 49 * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used 50 * to hash execs. If it is allocated (havhash true), then to tell 51 * whether ``name'' is (possibly) present in the i'th component 52 * of the variable path, you look at the bit in xhash indexed by 53 * hash(hashname("name"), i). This is setup automatically 54 * after .login is executed, and recomputed whenever ``path'' is 55 * changed. 56 * The two part hash function is designed to let texec() call the 57 * more expensive hashname() only once and the simple hash() several 58 * times (once for each path component checked). 59 * Byte size is assumed to be 8. 60 */ 61 #define HSHSIZ 8192 /* 1k bytes */ 62 #define HSHMASK (HSHSIZ - 1) 63 #define HSHMUL 243 64 static char xhash[HSHSIZ / 8]; 65 66 #define hash(a, b) (((a) * HSHMUL + (b)) & HSHMASK) 67 #define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */ 68 #define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */ 69 static int hits, misses; 70 71 /* Dummy search path for just absolute search when no path */ 72 static Char *justabs[] = {STRNULL, 0}; 73 74 static void pexerr __P((void)); 75 static void texec __P((Char *, Char **)); 76 static int hashname __P((Char *)); 77 static void tellmewhat __P((struct wordent *)); 78 static int executable __P((Char *, Char *, bool)); 79 static int iscommand __P((Char *)); 80 81 82 void 83 /*ARGSUSED*/ 84 doexec(v, t) 85 Char **v; 86 struct command *t; 87 { 88 register Char *dp, **pv, **av, *sav; 89 register struct varent *pathv; 90 register bool slash; 91 register int hashval = 0, hashval1, i; 92 Char *blk[2]; 93 94 /* 95 * Glob the command name. We will search $path even if this does something, 96 * as in sh but not in csh. One special case: if there is no PATH, then we 97 * execute only commands which start with '/'. 98 */ 99 blk[0] = t->t_dcom[0]; 100 blk[1] = 0; 101 gflag = 0, tglob(blk); 102 if (gflag) { 103 pv = globall(blk); 104 if (pv == 0) { 105 setname(vis_str(blk[0])); 106 stderror(ERR_NAME | ERR_NOMATCH); 107 } 108 gargv = 0; 109 } 110 else 111 pv = saveblk(blk); 112 113 trim(pv); 114 115 exerr = 0; 116 expath = Strsave(pv[0]); 117 Vexpath = expath; 118 119 pathv = adrof(STRpath); 120 if (pathv == 0 && expath[0] != '/') { 121 blkfree(pv); 122 pexerr(); 123 } 124 slash = any(short2str(expath), '/'); 125 126 /* 127 * Glob the argument list, if necessary. Otherwise trim off the quote bits. 128 */ 129 gflag = 0; 130 av = &t->t_dcom[1]; 131 tglob(av); 132 if (gflag) { 133 av = globall(av); 134 if (av == 0) { 135 blkfree(pv); 136 setname(vis_str(expath)); 137 stderror(ERR_NAME | ERR_NOMATCH); 138 } 139 gargv = 0; 140 } 141 else 142 av = saveblk(av); 143 144 blkfree(t->t_dcom); 145 t->t_dcom = blkspl(pv, av); 146 xfree((ptr_t) pv); 147 xfree((ptr_t) av); 148 av = t->t_dcom; 149 trim(av); 150 151 if (*av == NULL || **av == '\0') 152 pexerr(); 153 154 xechoit(av); /* Echo command if -x */ 155 /* 156 * Since all internal file descriptors are set to close on exec, we don't 157 * need to close them explicitly here. Just reorient ourselves for error 158 * messages. 159 */ 160 SHIN = 0; 161 SHOUT = 1; 162 SHERR = 2; 163 OLDSTD = 0; 164 /* 165 * We must do this AFTER any possible forking (like `foo` in glob) so that 166 * this shell can still do subprocesses. 167 */ 168 (void) sigsetmask((sigset_t) 0); 169 /* 170 * If no path, no words in path, or a / in the filename then restrict the 171 * command search. 172 */ 173 if (pathv == 0 || pathv->vec[0] == 0 || slash) 174 pv = justabs; 175 else 176 pv = pathv->vec; 177 sav = Strspl(STRslash, *av);/* / command name for postpending */ 178 Vsav = sav; 179 if (havhash) 180 hashval = hashname(*av); 181 i = 0; 182 hits++; 183 do { 184 /* 185 * Try to save time by looking at the hash table for where this command 186 * could be. If we are doing delayed hashing, then we put the names in 187 * one at a time, as the user enters them. This is kinda like Korn 188 * Shell's "tracked aliases". 189 */ 190 if (!slash && pv[0][0] == '/' && havhash) { 191 hashval1 = hash(hashval, i); 192 if (!bit(xhash, hashval1)) 193 goto cont; 194 } 195 if (pv[0][0] == 0 || eq(pv[0], STRdot)) /* don't make ./xxx */ 196 texec(*av, av); 197 else { 198 dp = Strspl(*pv, sav); 199 Vdp = dp; 200 texec(dp, av); 201 Vdp = 0; 202 xfree((ptr_t) dp); 203 } 204 misses++; 205 cont: 206 pv++; 207 i++; 208 } while (*pv); 209 hits--; 210 Vsav = 0; 211 xfree((ptr_t) sav); 212 pexerr(); 213 } 214 215 static void 216 pexerr() 217 { 218 /* Couldn't find the damn thing */ 219 if (expath) { 220 setname(vis_str(expath)); 221 Vexpath = 0; 222 xfree((ptr_t) expath); 223 expath = 0; 224 } 225 else 226 setname(""); 227 if (exerr) 228 stderror(ERR_NAME | ERR_STRING, exerr); 229 stderror(ERR_NAME | ERR_COMMAND); 230 } 231 232 /* 233 * Execute command f, arg list t. 234 * Record error message if not found. 235 * Also do shell scripts here. 236 */ 237 static void 238 texec(sf, st) 239 Char *sf; 240 register Char **st; 241 { 242 register char **t; 243 register char *f; 244 register struct varent *v; 245 register Char **vp; 246 Char *lastsh[2]; 247 int fd; 248 unsigned char c; 249 Char *st0, **ost; 250 251 /* The order for the conversions is significant */ 252 t = short2blk(st); 253 f = short2str(sf); 254 Vt = t; 255 errno = 0; /* don't use a previous error */ 256 (void) execve(f, t, environ); 257 Vt = 0; 258 blkfree((Char **) t); 259 switch (errno) { 260 261 case ENOEXEC: 262 /* 263 * From: casper@fwi.uva.nl (Casper H.S. Dik) If we could not execute 264 * it, don't feed it to the shell if it looks like a binary! 265 */ 266 if ((fd = open(f, O_RDONLY)) != -1) { 267 if (read(fd, (char *) &c, 1) == 1) { 268 if (!Isprint(c) && (c != '\n' && c != '\t')) { 269 (void) close(fd); 270 /* 271 * We *know* what ENOEXEC means. 272 */ 273 stderror(ERR_ARCH, f, strerror(errno)); 274 } 275 } 276 #ifdef _PATH_BSHELL 277 else 278 c = '#'; 279 #endif 280 (void) close(fd); 281 } 282 /* 283 * If there is an alias for shell, then put the words of the alias in 284 * front of the argument list replacing the command name. Note no 285 * interpretation of the words at this point. 286 */ 287 v = adrof1(STRshell, &aliases); 288 if (v == 0) { 289 vp = lastsh; 290 vp[0] = adrof(STRshell) ? value(STRshell) : STR_SHELLPATH; 291 vp[1] = NULL; 292 #ifdef _PATH_BSHELL 293 if (fd != -1 && c != '#') 294 vp[0] = STR_BSHELL; 295 #endif 296 } 297 else 298 vp = v->vec; 299 st0 = st[0]; 300 st[0] = sf; 301 ost = st; 302 st = blkspl(vp, st); /* Splice up the new arglst */ 303 ost[0] = st0; 304 sf = *st; 305 /* The order for the conversions is significant */ 306 t = short2blk(st); 307 f = short2str(sf); 308 xfree((ptr_t) st); 309 Vt = t; 310 (void) execve(f, t, environ); 311 Vt = 0; 312 blkfree((Char **) t); 313 /* The sky is falling, the sky is falling! */ 314 315 case ENOMEM: 316 stderror(ERR_SYSTEM, f, strerror(errno)); 317 318 case ENOENT: 319 break; 320 321 default: 322 if (exerr == 0) { 323 exerr = strerror(errno); 324 if (expath) 325 xfree((ptr_t) expath); 326 expath = Strsave(sf); 327 Vexpath = expath; 328 } 329 } 330 } 331 332 /*ARGSUSED*/ 333 void 334 execash(t, kp) 335 Char **t; 336 register struct command *kp; 337 { 338 int saveIN, saveOUT, saveDIAG, saveSTD; 339 int oSHIN; 340 int oSHOUT; 341 int oSHERR; 342 int oOLDSTD; 343 jmp_buf osetexit; 344 int my_reenter; 345 int odidfds; 346 sig_t osigint, osigquit, osigterm; 347 348 if (chkstop == 0 && setintr) 349 panystop(0); 350 /* 351 * Hmm, we don't really want to do that now because we might 352 * fail, but what is the choice 353 */ 354 rechist(); 355 356 osigint = signal(SIGINT, parintr); 357 osigquit = signal(SIGQUIT, parintr); 358 osigterm = signal(SIGTERM, parterm); 359 360 odidfds = didfds; 361 oSHIN = SHIN; 362 oSHOUT = SHOUT; 363 oSHERR = SHERR; 364 oOLDSTD = OLDSTD; 365 366 saveIN = dcopy(SHIN, -1); 367 saveOUT = dcopy(SHOUT, -1); 368 saveDIAG = dcopy(SHERR, -1); 369 saveSTD = dcopy(OLDSTD, -1); 370 371 lshift(kp->t_dcom, 1); 372 373 getexit(osetexit); 374 375 if ((my_reenter = setexit()) == 0) { 376 SHIN = dcopy(0, -1); 377 SHOUT = dcopy(1, -1); 378 SHERR = dcopy(2, -1); 379 didfds = 0; 380 doexec(t, kp); 381 } 382 383 (void) signal(SIGINT, osigint); 384 (void) signal(SIGQUIT, osigquit); 385 (void) signal(SIGTERM, osigterm); 386 387 doneinp = 0; 388 didfds = odidfds; 389 (void) close(SHIN); 390 (void) close(SHOUT); 391 (void) close(SHERR); 392 (void) close(OLDSTD); 393 SHIN = dmove(saveIN, oSHIN); 394 SHOUT = dmove(saveOUT, oSHOUT); 395 SHERR = dmove(saveDIAG, oSHERR); 396 OLDSTD = dmove(saveSTD, oOLDSTD); 397 398 resexit(osetexit); 399 if (my_reenter) 400 stderror(ERR_SILENT); 401 } 402 403 void 404 xechoit(t) 405 Char **t; 406 { 407 if (adrof(STRecho)) { 408 (void) fflush(csherr); 409 blkpr(csherr, t); 410 (void) fputc('\n', csherr); 411 } 412 } 413 414 void 415 /*ARGSUSED*/ 416 dohash(v, t) 417 Char **v; 418 struct command *t; 419 { 420 DIR *dirp; 421 register struct dirent *dp; 422 register int cnt; 423 int i = 0; 424 struct varent *pathv = adrof(STRpath); 425 Char **pv; 426 int hashval; 427 428 havhash = 1; 429 for (cnt = 0; cnt < sizeof xhash; cnt++) 430 xhash[cnt] = 0; 431 if (pathv == 0) 432 return; 433 for (pv = pathv->vec; *pv; pv++, i++) { 434 if (pv[0][0] != '/') 435 continue; 436 dirp = opendir(short2str(*pv)); 437 if (dirp == NULL) 438 continue; 439 while ((dp = readdir(dirp)) != NULL) { 440 if (dp->d_ino == 0) 441 continue; 442 if (dp->d_name[0] == '.' && 443 (dp->d_name[1] == '\0' || 444 (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) 445 continue; 446 hashval = hash(hashname(str2short(dp->d_name)), i); 447 bis(xhash, hashval); 448 /* tw_add_comm_name (dp->d_name); */ 449 } 450 (void) closedir(dirp); 451 } 452 } 453 454 void 455 /*ARGSUSED*/ 456 dounhash(v, t) 457 Char **v; 458 struct command *t; 459 { 460 havhash = 0; 461 } 462 463 void 464 /*ARGSUSED*/ 465 hashstat(v, t) 466 Char **v; 467 struct command *t; 468 { 469 if (hits + misses) 470 (void) fprintf(cshout, "%d hits, %d misses, %d%%\n", 471 hits, misses, 100 * hits / (hits + misses)); 472 } 473 474 /* 475 * Hash a command name. 476 */ 477 static int 478 hashname(cp) 479 register Char *cp; 480 { 481 register long h = 0; 482 483 while (*cp) 484 h = hash(h, *cp++); 485 return ((int) h); 486 } 487 488 static int 489 iscommand(name) 490 Char *name; 491 { 492 register Char **pv; 493 register Char *sav; 494 register struct varent *v; 495 register bool slash = any(short2str(name), '/'); 496 register int hashval = 0, hashval1, i; 497 498 v = adrof(STRpath); 499 if (v == 0 || v->vec[0] == 0 || slash) 500 pv = justabs; 501 else 502 pv = v->vec; 503 sav = Strspl(STRslash, name); /* / command name for postpending */ 504 if (havhash) 505 hashval = hashname(name); 506 i = 0; 507 do { 508 if (!slash && pv[0][0] == '/' && havhash) { 509 hashval1 = hash(hashval, i); 510 if (!bit(xhash, hashval1)) 511 goto cont; 512 } 513 if (pv[0][0] == 0 || eq(pv[0], STRdot)) { /* don't make ./xxx */ 514 if (executable(NULL, name, 0)) { 515 xfree((ptr_t) sav); 516 return i + 1; 517 } 518 } 519 else { 520 if (executable(*pv, sav, 0)) { 521 xfree((ptr_t) sav); 522 return i + 1; 523 } 524 } 525 cont: 526 pv++; 527 i++; 528 } while (*pv); 529 xfree((ptr_t) sav); 530 return 0; 531 } 532 533 /* Also by: 534 * Andreas Luik <luik@isaak.isa.de> 535 * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung 536 * Azenberstr. 35 537 * D-7000 Stuttgart 1 538 * West-Germany 539 * is the executable() routine below and changes to iscommand(). 540 * Thanks again!! 541 */ 542 543 /* 544 * executable() examines the pathname obtained by concatenating dir and name 545 * (dir may be NULL), and returns 1 either if it is executable by us, or 546 * if dir_ok is set and the pathname refers to a directory. 547 * This is a bit kludgy, but in the name of optimization... 548 */ 549 static int 550 executable(dir, name, dir_ok) 551 Char *dir, *name; 552 bool dir_ok; 553 { 554 struct stat stbuf; 555 Char path[MAXPATHLEN + 1], *dp, *sp; 556 char *strname; 557 558 if (dir && *dir) { 559 for (dp = path, sp = dir; *sp; *dp++ = *sp++) 560 if (dp == &path[MAXPATHLEN + 1]) { 561 *--dp = '\0'; 562 break; 563 } 564 for (sp = name; *sp; *dp++ = *sp++) 565 if (dp == &path[MAXPATHLEN + 1]) { 566 *--dp = '\0'; 567 break; 568 } 569 *dp = '\0'; 570 strname = short2str(path); 571 } 572 else 573 strname = short2str(name); 574 return (stat(strname, &stbuf) != -1 && 575 ((S_ISREG(stbuf.st_mode) && 576 /* save time by not calling access() in the hopeless case */ 577 (stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) && 578 access(strname, X_OK) == 0) || 579 (dir_ok && S_ISDIR(stbuf.st_mode)))); 580 } 581 582 /* The dowhich() is by: 583 * Andreas Luik <luik@isaak.isa.de> 584 * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung 585 * Azenberstr. 35 586 * D-7000 Stuttgart 1 587 * West-Germany 588 * Thanks!! 589 */ 590 /*ARGSUSED*/ 591 void 592 dowhich(v, c) 593 register Char **v; 594 struct command *c; 595 { 596 struct wordent lex[3]; 597 struct varent *vp; 598 599 lex[0].next = &lex[1]; 600 lex[1].next = &lex[2]; 601 lex[2].next = &lex[0]; 602 603 lex[0].prev = &lex[2]; 604 lex[1].prev = &lex[0]; 605 lex[2].prev = &lex[1]; 606 607 lex[0].word = STRNULL; 608 lex[2].word = STRret; 609 610 while (*++v) { 611 if ((vp = adrof1(*v, &aliases)) != NULL) { 612 (void) fprintf(cshout, "%s: \t aliased to ", vis_str(*v)); 613 blkpr(cshout, vp->vec); 614 (void) fputc('\n', cshout); 615 } 616 else { 617 lex[1].word = *v; 618 tellmewhat(lex); 619 } 620 } 621 } 622 623 static void 624 tellmewhat(lex) 625 struct wordent *lex; 626 { 627 register int i; 628 register struct biltins *bptr; 629 register struct wordent *sp = lex->next; 630 bool aliased = 0; 631 Char *s0, *s1, *s2; 632 Char qc; 633 634 if (adrof1(sp->word, &aliases)) { 635 alias(lex); 636 sp = lex->next; 637 aliased = 1; 638 } 639 640 s0 = sp->word; /* to get the memory freeing right... */ 641 642 /* handle quoted alias hack */ 643 if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE) 644 (sp->word)++; 645 646 /* do quoting, if it hasn't been done */ 647 s1 = s2 = sp->word; 648 while (*s2) 649 switch (*s2) { 650 case '\'': 651 case '"': 652 qc = *s2++; 653 while (*s2 && *s2 != qc) 654 *s1++ = *s2++ | QUOTE; 655 if (*s2) 656 s2++; 657 break; 658 case '\\': 659 if (*++s2) 660 *s1++ = *s2++ | QUOTE; 661 break; 662 default: 663 *s1++ = *s2++; 664 } 665 *s1 = '\0'; 666 667 for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) { 668 if (eq(sp->word, str2short(bptr->bname))) { 669 if (aliased) 670 prlex(cshout, lex); 671 (void) fprintf(cshout, "%s: shell built-in command.\n", 672 vis_str(sp->word)); 673 sp->word = s0; /* we save and then restore this */ 674 return; 675 } 676 } 677 678 if ((i = iscommand(strip(sp->word))) != 0) { 679 register Char **pv; 680 register struct varent *v; 681 bool slash = any(short2str(sp->word), '/'); 682 683 v = adrof(STRpath); 684 if (v == 0 || v->vec[0] == 0 || slash) 685 pv = justabs; 686 else 687 pv = v->vec; 688 689 while (--i) 690 pv++; 691 if (pv[0][0] == 0 || eq(pv[0], STRdot)) { 692 sp->word = Strspl(STRdotsl, sp->word); 693 prlex(cshout, lex); 694 xfree((ptr_t) sp->word); 695 sp->word = s0; /* we save and then restore this */ 696 return; 697 } 698 s1 = Strspl(*pv, STRslash); 699 sp->word = Strspl(s1, sp->word); 700 xfree((ptr_t) s1); 701 prlex(cshout, lex); 702 xfree((ptr_t) sp->word); 703 } 704 else { 705 if (aliased) 706 prlex(cshout, lex); 707 (void) fprintf(csherr, "%s: Command not found.\n", vis_str(sp->word)); 708 } 709 sp->word = s0; /* we save and then restore this */ 710 } 711