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