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