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