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