1 /* $Header: /src/pub/tcsh/sh.exec.c,v 3.56 2002/06/25 19:02:11 christos Exp $ */ 2 /* 3 * sh.exec.c: Search, find, and execute a command! 4 */ 5 /*- 6 * Copyright (c) 1980, 1991 The Regents of the University of California. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. 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 #include "sh.h" 34 35 RCSID("$Id: sh.exec.c,v 3.56 2002/06/25 19:02:11 christos Exp $") 36 37 #include "tc.h" 38 #include "tw.h" 39 #ifdef WINNT_NATIVE 40 #include <nt.const.h> 41 #endif /*WINNT_NATIVE*/ 42 43 /* 44 * C shell 45 */ 46 47 #ifndef OLDHASH 48 # define FASTHASH /* Fast hashing is the default */ 49 #endif /* OLDHASH */ 50 51 /* 52 * System level search and execute of a command. 53 * We look in each directory for the specified command name. 54 * If the name contains a '/' then we execute only the full path name. 55 * If there is no search path then we execute only full path names. 56 */ 57 58 /* 59 * As we search for the command we note the first non-trivial error 60 * message for presentation to the user. This allows us often 61 * to show that a file has the wrong mode/no access when the file 62 * is not in the last component of the search path, so we must 63 * go on after first detecting the error. 64 */ 65 static char *exerr; /* Execution error message */ 66 static Char *expath; /* Path for exerr */ 67 68 /* 69 * The two part hash function is designed to let texec() call the 70 * more expensive hashname() only once and the simple hash() several 71 * times (once for each path component checked). 72 * Byte size is assumed to be 8. 73 */ 74 #define BITS_PER_BYTE 8 75 76 #ifdef FASTHASH 77 /* 78 * xhash is an array of hash buckets which are used to hash execs. If 79 * it is allocated (havhash true), then to tell if ``name'' is 80 * (possibly) presend in the i'th component of the variable path, look 81 * at the [hashname(name)] bucket of size [hashwidth] bytes, in the [i 82 * mod size*8]'th bit. The cache size is defaults to a length of 1024 83 * buckets, each 1 byte wide. This implementation guarantees that 84 * objects n bytes wide will be aligned on n byte boundaries. 85 */ 86 # define HSHMUL 241 87 88 static unsigned long *xhash = NULL; 89 static unsigned int hashlength = 0, uhashlength = 0; 90 static unsigned int hashwidth = 0, uhashwidth = 0; 91 static int hashdebug = 0; 92 93 # define hash(a, b) (((a) * HSHMUL + (b)) % (hashlength)) 94 # define widthof(t) (sizeof(t) * BITS_PER_BYTE) 95 # define tbit(f, i, t) (((t *) xhash)[(f)] & \ 96 (1L << (i & (widthof(t) - 1)))) 97 # define tbis(f, i, t) (((t *) xhash)[(f)] |= \ 98 (1L << (i & (widthof(t) - 1)))) 99 # define cbit(f, i) tbit(f, i, unsigned char) 100 # define cbis(f, i) tbis(f, i, unsigned char) 101 # define sbit(f, i) tbit(f, i, unsigned short) 102 # define sbis(f, i) tbis(f, i, unsigned short) 103 # define ibit(f, i) tbit(f, i, unsigned int) 104 # define ibis(f, i) tbis(f, i, unsigned int) 105 # define lbit(f, i) tbit(f, i, unsigned long) 106 # define lbis(f, i) tbis(f, i, unsigned long) 107 108 # define bit(f, i) (hashwidth==sizeof(unsigned char) ? cbit(f,i) : \ 109 ((hashwidth==sizeof(unsigned short) ? sbit(f,i) : \ 110 ((hashwidth==sizeof(unsigned int) ? ibit(f,i) : \ 111 lbit(f,i)))))) 112 # define bis(f, i) (hashwidth==sizeof(unsigned char) ? cbis(f,i) : \ 113 ((hashwidth==sizeof(unsigned short) ? sbis(f,i) : \ 114 ((hashwidth==sizeof(unsigned int) ? ibis(f,i) : \ 115 lbis(f,i)))))) 116 #else /* OLDHASH */ 117 /* 118 * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used 119 * to hash execs. If it is allocated (havhash true), then to tell 120 * whether ``name'' is (possibly) present in the i'th component 121 * of the variable path, you look at the bit in xhash indexed by 122 * hash(hashname("name"), i). This is setup automatically 123 * after .login is executed, and recomputed whenever ``path'' is 124 * changed. 125 */ 126 # define HSHSIZ 8192 /* 1k bytes */ 127 # define HSHMASK (HSHSIZ - 1) 128 # define HSHMUL 243 129 static char xhash[HSHSIZ / BITS_PER_BYTE]; 130 131 # define hash(a, b) (((a) * HSHMUL + (b)) & HSHMASK) 132 # define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */ 133 # define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */ 134 135 #endif /* FASTHASH */ 136 137 #ifdef VFORK 138 static int hits, misses; 139 #endif /* VFORK */ 140 141 /* Dummy search path for just absolute search when no path */ 142 static Char *justabs[] = {STRNULL, 0}; 143 144 static void pexerr __P((void)); 145 static void texec __P((Char *, Char **)); 146 int hashname __P((Char *)); 147 static int iscommand __P((Char *)); 148 149 void 150 doexec(t, do_glob) 151 register struct command *t; 152 bool do_glob; 153 { 154 Char *dp, **pv, **av, *sav; 155 struct varent *v; 156 bool slash; 157 int hashval, i; 158 Char *blk[2]; 159 160 /* 161 * Glob the command name. We will search $path even if this does something, 162 * as in sh but not in csh. One special case: if there is no PATH, then we 163 * execute only commands which start with '/'. 164 */ 165 blk[0] = t->t_dcom[0]; 166 blk[1] = 0; 167 gflag = 0; 168 if (do_glob) 169 tglob(blk); 170 if (gflag) { 171 pv = globall(blk); 172 if (pv == 0) { 173 setname(short2str(blk[0])); 174 stderror(ERR_NAME | ERR_NOMATCH); 175 } 176 gargv = 0; 177 } 178 else 179 pv = saveblk(blk); 180 181 trim(pv); 182 183 exerr = 0; 184 expath = Strsave(pv[0]); 185 #ifdef VFORK 186 Vexpath = expath; 187 #endif /* VFORK */ 188 189 v = adrof(STRpath); 190 if (v == 0 && expath[0] != '/' && expath[0] != '.') { 191 blkfree(pv); 192 pexerr(); 193 } 194 slash = any(short2str(expath), '/'); 195 196 /* 197 * Glob the argument list, if necessary. Otherwise trim off the quote bits. 198 */ 199 gflag = 0; 200 av = &t->t_dcom[1]; 201 if (do_glob) 202 tglob(av); 203 if (gflag) { 204 av = globall(av); 205 if (av == 0) { 206 blkfree(pv); 207 setname(short2str(expath)); 208 stderror(ERR_NAME | ERR_NOMATCH); 209 } 210 gargv = 0; 211 } 212 else 213 av = saveblk(av); 214 215 blkfree(t->t_dcom); 216 t->t_dcom = blkspl(pv, av); 217 xfree((ptr_t) pv); 218 xfree((ptr_t) av); 219 av = t->t_dcom; 220 trim(av); 221 222 if (*av == NULL || **av == '\0') 223 pexerr(); 224 225 xechoit(av); /* Echo command if -x */ 226 #ifdef CLOSE_ON_EXEC 227 /* 228 * Since all internal file descriptors are set to close on exec, we don't 229 * need to close them explicitly here. Just reorient ourselves for error 230 * messages. 231 */ 232 SHIN = 0; 233 SHOUT = 1; 234 SHDIAG = 2; 235 OLDSTD = 0; 236 isoutatty = isatty(SHOUT); 237 isdiagatty = isatty(SHDIAG); 238 #else 239 closech(); /* Close random fd's */ 240 #endif 241 /* 242 * We must do this AFTER any possible forking (like `foo` in glob) so that 243 * this shell can still do subprocesses. 244 */ 245 #ifdef BSDSIGS 246 (void) sigsetmask((sigmask_t) 0); 247 #else /* BSDSIGS */ 248 (void) sigrelse(SIGINT); 249 (void) sigrelse(SIGCHLD); 250 #endif /* BSDSIGS */ 251 252 /* 253 * If no path, no words in path, or a / in the filename then restrict the 254 * command search. 255 */ 256 if (v == NULL || v->vec == NULL || v->vec[0] == NULL || slash) 257 pv = justabs; 258 else 259 pv = v->vec; 260 sav = Strspl(STRslash, *av);/* / command name for postpending */ 261 #ifdef VFORK 262 Vsav = sav; 263 #endif /* VFORK */ 264 hashval = havhash ? hashname(*av) : 0; 265 266 i = 0; 267 #ifdef VFORK 268 hits++; 269 #endif /* VFORK */ 270 do { 271 /* 272 * Try to save time by looking at the hash table for where this command 273 * could be. If we are doing delayed hashing, then we put the names in 274 * one at a time, as the user enters them. This is kinda like Korn 275 * Shell's "tracked aliases". 276 */ 277 if (!slash && ABSOLUTEP(pv[0]) && havhash) { 278 #ifdef FASTHASH 279 if (!bit(hashval, i)) 280 goto cont; 281 #else /* OLDHASH */ 282 int hashval1 = hash(hashval, i); 283 if (!bit(xhash, hashval1)) 284 goto cont; 285 #endif /* FASTHASH */ 286 } 287 if (pv[0][0] == 0 || eq(pv[0], STRdot)) /* don't make ./xxx */ 288 { 289 290 #ifdef COHERENT 291 if (t->t_dflg & F_AMPERSAND) { 292 # ifdef JOBDEBUG 293 xprintf("set SIGINT to SIG_IGN\n"); 294 xprintf("set SIGQUIT to SIG_DFL\n"); 295 # endif /* JOBDEBUG */ 296 (void) signal(SIGINT,SIG_IGN); /* may not be necessary */ 297 (void) signal(SIGQUIT,SIG_DFL); 298 } 299 300 if (gointr && eq(gointr, STRminus)) { 301 # ifdef JOBDEBUG 302 xprintf("set SIGINT to SIG_IGN\n"); 303 xprintf("set SIGQUIT to SIG_IGN\n"); 304 # endif /* JOBDEBUG */ 305 (void) signal(SIGINT,SIG_IGN); /* may not be necessary */ 306 (void) signal(SIGQUIT,SIG_IGN); 307 } 308 #endif /* COHERENT */ 309 310 texec(*av, av); 311 } 312 else { 313 dp = Strspl(*pv, sav); 314 #ifdef VFORK 315 Vdp = dp; 316 #endif /* VFORK */ 317 318 #ifdef COHERENT 319 if ((t->t_dflg & F_AMPERSAND)) { 320 # ifdef JOBDEBUG 321 xprintf("set SIGINT to SIG_IGN\n"); 322 # endif /* JOBDEBUG */ 323 /* 324 * this is necessary on Coherent or all background 325 * jobs are killed by CTRL-C 326 * (there must be a better fix for this) 327 */ 328 (void) signal(SIGINT,SIG_IGN); 329 } 330 if (gointr && eq(gointr,STRminus)) { 331 # ifdef JOBDEBUG 332 xprintf("set SIGINT to SIG_IGN\n"); 333 xprintf("set SIGQUIT to SIG_IGN\n"); 334 # endif /* JOBDEBUG */ 335 (void) signal(SIGINT,SIG_IGN); /* may not be necessary */ 336 (void) signal(SIGQUIT,SIG_IGN); 337 } 338 #endif /* COHERENT */ 339 340 texec(dp, av); 341 #ifdef VFORK 342 Vdp = 0; 343 #endif /* VFORK */ 344 xfree((ptr_t) dp); 345 } 346 #ifdef VFORK 347 misses++; 348 #endif /* VFORK */ 349 cont: 350 pv++; 351 i++; 352 } while (*pv); 353 #ifdef VFORK 354 hits--; 355 Vsav = 0; 356 #endif /* VFORK */ 357 xfree((ptr_t) sav); 358 pexerr(); 359 } 360 361 static void 362 pexerr() 363 { 364 /* Couldn't find the damn thing */ 365 if (expath) { 366 setname(short2str(expath)); 367 #ifdef VFORK 368 Vexpath = 0; 369 #endif /* VFORK */ 370 xfree((ptr_t) expath); 371 expath = 0; 372 } 373 else 374 setname(""); 375 if (exerr) 376 stderror(ERR_NAME | ERR_STRING, exerr); 377 stderror(ERR_NAME | ERR_COMMAND); 378 } 379 380 /* 381 * Execute command f, arg list t. 382 * Record error message if not found. 383 * Also do shell scripts here. 384 */ 385 static void 386 texec(sf, st) 387 Char *sf; 388 register Char **st; 389 { 390 register char **t; 391 register char *f; 392 register struct varent *v; 393 Char **vp; 394 Char *lastsh[2]; 395 char pref[2]; 396 int fd; 397 Char *st0, **ost; 398 399 /* The order for the conversions is significant */ 400 t = short2blk(st); 401 f = short2str(sf); 402 #ifdef VFORK 403 Vt = t; 404 #endif /* VFORK */ 405 errno = 0; /* don't use a previous error */ 406 #ifdef apollo 407 /* 408 * If we try to execute an nfs mounted directory on the apollo, we 409 * hang forever. So until apollo fixes that.. 410 */ 411 { 412 struct stat stb; 413 if (stat(f, &stb) == 0 && S_ISDIR(stb.st_mode)) 414 errno = EISDIR; 415 } 416 if (errno == 0) 417 #endif /* apollo */ 418 { 419 #ifdef ISC_POSIX_EXEC_BUG 420 __setostype(0); /* "0" is "__OS_SYSV" in <sys/user.h> */ 421 #endif /* ISC_POSIX_EXEC_BUG */ 422 (void) execv(f, t); 423 #ifdef ISC_POSIX_EXEC_BUG 424 __setostype(1); /* "1" is "__OS_POSIX" in <sys/user.h> */ 425 #endif /* ISC_POSIX_EXEC_BUG */ 426 } 427 #ifdef VFORK 428 Vt = 0; 429 #endif /* VFORK */ 430 blkfree((Char **) t); 431 switch (errno) { 432 433 case ENOEXEC: 434 #ifdef WINNT_NATIVE 435 nt_feed_to_cmd(f,t); 436 #endif /* WINNT_NATIVE */ 437 /* 438 * From: casper@fwi.uva.nl (Casper H.S. Dik) If we could not execute 439 * it, don't feed it to the shell if it looks like a binary! 440 */ 441 if ((fd = open(f, O_RDONLY)) != -1) { 442 int nread; 443 if ((nread = read(fd, (char *) pref, 2)) == 2) { 444 if (!Isprint(pref[0]) && (pref[0] != '\n' && pref[0] != '\t')) { 445 (void) close(fd); 446 /* 447 * We *know* what ENOEXEC means. 448 */ 449 stderror(ERR_ARCH, f, strerror(errno)); 450 } 451 } 452 else if (nread < 0 && errno != EINTR) { 453 #ifdef convex 454 /* need to print error incase the file is migrated */ 455 stderror(ERR_SYSTEM, f, strerror(errno)); 456 #endif 457 } 458 #ifdef _PATH_BSHELL 459 else { 460 pref[0] = '#'; 461 pref[1] = '\0'; 462 } 463 #endif 464 } 465 #ifdef HASHBANG 466 if (fd == -1 || 467 pref[0] != '#' || pref[1] != '!' || hashbang(fd, &vp) == -1) { 468 #endif /* HASHBANG */ 469 /* 470 * If there is an alias for shell, then put the words of the alias in 471 * front of the argument list replacing the command name. Note no 472 * interpretation of the words at this point. 473 */ 474 v = adrof1(STRshell, &aliases); 475 if (v == NULL || v->vec == NULL) { 476 vp = lastsh; 477 vp[0] = adrof(STRshell) ? varval(STRshell) : STR_SHELLPATH; 478 vp[1] = NULL; 479 #ifdef _PATH_BSHELL 480 if (fd != -1 481 # ifndef ISC /* Compatible with ISC's /bin/csh */ 482 && pref[0] != '#' 483 # endif /* ISC */ 484 ) 485 vp[0] = STR_BSHELL; 486 #endif 487 vp = saveblk(vp); 488 } 489 else 490 vp = saveblk(v->vec); 491 #ifdef HASHBANG 492 } 493 #endif /* HASHBANG */ 494 if (fd != -1) 495 (void) close(fd); 496 497 st0 = st[0]; 498 st[0] = sf; 499 ost = st; 500 st = blkspl(vp, st); /* Splice up the new arglst */ 501 ost[0] = st0; 502 sf = *st; 503 /* The order for the conversions is significant */ 504 t = short2blk(st); 505 f = short2str(sf); 506 xfree((ptr_t) st); 507 blkfree((Char **) vp); 508 #ifdef VFORK 509 Vt = t; 510 #endif /* VFORK */ 511 #ifdef ISC_POSIX_EXEC_BUG 512 __setostype(0); /* "0" is "__OS_SYSV" in <sys/user.h> */ 513 #endif /* ISC_POSIX_EXEC_BUG */ 514 (void) execv(f, t); 515 #ifdef ISC_POSIX_EXEC_BUG 516 __setostype(1); /* "1" is "__OS_POSIX" in <sys/user.h> */ 517 #endif /* ISC_POSIX_EXEC_BUG */ 518 #ifdef VFORK 519 Vt = 0; 520 #endif /* VFORK */ 521 blkfree((Char **) t); 522 /* The sky is falling, the sky is falling! */ 523 stderror(ERR_SYSTEM, f, strerror(errno)); 524 break; 525 526 case ENOMEM: 527 stderror(ERR_SYSTEM, f, strerror(errno)); 528 break; 529 530 #ifdef _IBMR2 531 case 0: /* execv fails and returns 0! */ 532 #endif /* _IBMR2 */ 533 case ENOENT: 534 break; 535 536 default: 537 if (exerr == 0) { 538 exerr = strerror(errno); 539 if (expath) 540 xfree((ptr_t) expath); 541 expath = Strsave(sf); 542 #ifdef VFORK 543 Vexpath = expath; 544 #endif /* VFORK */ 545 } 546 break; 547 } 548 } 549 550 /*ARGSUSED*/ 551 void 552 execash(t, kp) 553 Char **t; 554 register struct command *kp; 555 { 556 int saveIN, saveOUT, saveDIAG, saveSTD; 557 int oSHIN; 558 int oSHOUT; 559 int oSHDIAG; 560 int oOLDSTD; 561 jmp_buf_t osetexit; 562 int my_reenter; 563 int odidfds; 564 #ifndef CLOSE_ON_EXEC 565 int odidcch; 566 #endif /* CLOSE_ON_EXEC */ 567 signalfun_t osigint, osigquit, osigterm; 568 569 USE(t); 570 if (chkstop == 0 && setintr) 571 panystop(0); 572 /* 573 * Hmm, we don't really want to do that now because we might 574 * fail, but what is the choice 575 */ 576 rechist(NULL, adrof(STRsavehist) != NULL); 577 578 579 osigint = signal(SIGINT, parintr); 580 osigquit = signal(SIGQUIT, parintr); 581 osigterm = signal(SIGTERM, parterm); 582 583 odidfds = didfds; 584 #ifndef CLOSE_ON_EXEC 585 odidcch = didcch; 586 #endif /* CLOSE_ON_EXEC */ 587 oSHIN = SHIN; 588 oSHOUT = SHOUT; 589 oSHDIAG = SHDIAG; 590 oOLDSTD = OLDSTD; 591 592 saveIN = dcopy(SHIN, -1); 593 saveOUT = dcopy(SHOUT, -1); 594 saveDIAG = dcopy(SHDIAG, -1); 595 saveSTD = dcopy(OLDSTD, -1); 596 597 lshift(kp->t_dcom, 1); 598 599 getexit(osetexit); 600 601 /* PWP: setjmp/longjmp bugfix for optimizing compilers */ 602 #ifdef cray 603 my_reenter = 1; /* assume non-zero return val */ 604 if (setexit() == 0) { 605 my_reenter = 0; /* Oh well, we were wrong */ 606 #else /* !cray */ 607 if ((my_reenter = setexit()) == 0) { 608 #endif /* cray */ 609 SHIN = dcopy(0, -1); 610 SHOUT = dcopy(1, -1); 611 SHDIAG = dcopy(2, -1); 612 #ifndef CLOSE_ON_EXEC 613 didcch = 0; 614 #endif /* CLOSE_ON_EXEC */ 615 didfds = 0; 616 /* 617 * Decrement the shell level 618 */ 619 shlvl(-1); 620 #ifdef WINNT_NATIVE 621 __nt_really_exec=1; 622 #endif /* WINNT_NATIVE */ 623 doexec(kp, 1); 624 } 625 626 (void) sigset(SIGINT, osigint); 627 (void) sigset(SIGQUIT, osigquit); 628 (void) sigset(SIGTERM, osigterm); 629 630 doneinp = 0; 631 #ifndef CLOSE_ON_EXEC 632 didcch = odidcch; 633 #endif /* CLOSE_ON_EXEC */ 634 didfds = odidfds; 635 (void) close(SHIN); 636 (void) close(SHOUT); 637 (void) close(SHDIAG); 638 (void) close(OLDSTD); 639 SHIN = dmove(saveIN, oSHIN); 640 SHOUT = dmove(saveOUT, oSHOUT); 641 SHDIAG = dmove(saveDIAG, oSHDIAG); 642 OLDSTD = dmove(saveSTD, oOLDSTD); 643 644 resexit(osetexit); 645 if (my_reenter) 646 stderror(ERR_SILENT); 647 } 648 649 void 650 xechoit(t) 651 Char **t; 652 { 653 if (adrof(STRecho)) { 654 int odidfds = didfds; 655 flush(); 656 haderr = 1; 657 didfds = 0; 658 blkpr(t), xputchar('\n'); 659 flush(); 660 didfds = odidfds; 661 haderr = 0; 662 } 663 } 664 665 /*ARGSUSED*/ 666 void 667 dohash(vv, c) 668 Char **vv; 669 struct command *c; 670 { 671 #ifdef COMMENT 672 struct stat stb; 673 #endif 674 DIR *dirp; 675 register struct dirent *dp; 676 int i = 0; 677 struct varent *v = adrof(STRpath); 678 Char **pv; 679 int hashval; 680 #ifdef WINNT_NATIVE 681 int is_windir; /* check if it is the windows directory */ 682 USE(hashval); 683 #endif /* WINNT_NATIVE */ 684 685 USE(c); 686 #ifdef FASTHASH 687 if (vv && vv[1]) { 688 uhashlength = atoi(short2str(vv[1])); 689 if (vv[2]) { 690 uhashwidth = atoi(short2str(vv[2])); 691 if ((uhashwidth != sizeof(unsigned char)) && 692 (uhashwidth != sizeof(unsigned short)) && 693 (uhashwidth != sizeof(unsigned long))) 694 uhashwidth = 0; 695 if (vv[3]) 696 hashdebug = atoi(short2str(vv[3])); 697 } 698 } 699 700 if (uhashwidth) 701 hashwidth = uhashwidth; 702 else { 703 hashwidth = 0; 704 if (v == NULL) 705 return; 706 for (pv = v->vec; pv && *pv; pv++, hashwidth++) 707 continue; 708 if (hashwidth <= widthof(unsigned char)) 709 hashwidth = sizeof(unsigned char); 710 else if (hashwidth <= widthof(unsigned short)) 711 hashwidth = sizeof(unsigned short); 712 else if (hashwidth <= widthof(unsigned int)) 713 hashwidth = sizeof(unsigned int); 714 else 715 hashwidth = sizeof(unsigned long); 716 } 717 718 if (uhashlength) 719 hashlength = uhashlength; 720 else 721 hashlength = hashwidth * (8*64);/* "average" files per dir in path */ 722 723 if (xhash) 724 xfree((ptr_t) xhash); 725 xhash = (unsigned long *) xcalloc((size_t) (hashlength * hashwidth), 726 (size_t) 1); 727 #endif /* FASTHASH */ 728 729 (void) getusername(NULL); /* flush the tilde cashe */ 730 tw_cmd_free(); 731 havhash = 1; 732 if (v == NULL) 733 return; 734 for (pv = v->vec; pv && *pv; pv++, i++) { 735 if (!ABSOLUTEP(pv[0])) 736 continue; 737 dirp = opendir(short2str(*pv)); 738 if (dirp == NULL) 739 continue; 740 #ifdef COMMENT /* this isn't needed. opendir won't open 741 * non-dirs */ 742 if (fstat(dirp->dd_fd, &stb) < 0 || !S_ISDIR(stb.st_mode)) { 743 (void) closedir(dirp); 744 continue; 745 } 746 #endif 747 #ifdef WINNT_NATIVE 748 is_windir = nt_check_if_windir(short2str(*pv)); 749 #endif /* WINNT_NATIVE */ 750 while ((dp = readdir(dirp)) != NULL) { 751 if (dp->d_ino == 0) 752 continue; 753 if (dp->d_name[0] == '.' && 754 (dp->d_name[1] == '\0' || 755 (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) 756 continue; 757 #ifdef WINNT_NATIVE 758 nt_check_name_and_hash(is_windir, dp->d_name, i); 759 #else /* !WINNT_NATIVE*/ 760 #if defined(_UWIN) || defined(__CYGWIN__) 761 /* Turn foo.{exe,com,bat} into foo since UWIN's readdir returns 762 * the file with the .exe, .com, .bat extension 763 */ 764 { 765 size_t ext = strlen(dp->d_name) - 4; 766 if ((ext > 0) && (strcmp(&dp->d_name[ext], ".exe") == 0 || 767 strcmp(&dp->d_name[ext], ".bat") == 0 || 768 strcmp(&dp->d_name[ext], ".com") == 0)) 769 dp->d_name[ext] = '\0'; 770 } 771 #endif /* _UWIN || __CYGWIN__ */ 772 # ifdef FASTHASH 773 hashval = hashname(str2short(dp->d_name)); 774 bis(hashval, i); 775 if (hashdebug & 1) 776 xprintf(CGETS(13, 1, "hash=%-4d dir=%-2d prog=%s\n"), 777 hashname(str2short(dp->d_name)), i, dp->d_name); 778 # else /* OLD HASH */ 779 hashval = hash(hashname(str2short(dp->d_name)), i); 780 bis(xhash, hashval); 781 # endif /* FASTHASH */ 782 /* tw_add_comm_name (dp->d_name); */ 783 #endif /* WINNT_NATIVE */ 784 } 785 (void) closedir(dirp); 786 } 787 } 788 789 /*ARGSUSED*/ 790 void 791 dounhash(v, c) 792 Char **v; 793 struct command *c; 794 { 795 USE(c); 796 USE(v); 797 havhash = 0; 798 #ifdef FASTHASH 799 if (xhash) { 800 xfree((ptr_t) xhash); 801 xhash = NULL; 802 } 803 #endif /* FASTHASH */ 804 } 805 806 /*ARGSUSED*/ 807 void 808 hashstat(v, c) 809 Char **v; 810 struct command *c; 811 { 812 USE(c); 813 USE(v); 814 #ifdef FASTHASH 815 if (havhash && hashlength && hashwidth) 816 xprintf(CGETS(13, 2, "%d hash buckets of %d bits each\n"), 817 hashlength, hashwidth*8); 818 if (hashdebug) 819 xprintf(CGETS(13, 3, "debug mask = 0x%08x\n"), hashdebug); 820 #endif /* FASTHASH */ 821 #ifdef VFORK 822 if (hits + misses) 823 xprintf(CGETS(13, 4, "%d hits, %d misses, %d%%\n"), 824 hits, misses, 100 * hits / (hits + misses)); 825 #endif 826 } 827 828 829 /* 830 * Hash a command name. 831 */ 832 int 833 hashname(cp) 834 register Char *cp; 835 { 836 register unsigned long h; 837 838 for (h = 0; *cp; cp++) 839 h = hash(h, *cp); 840 return ((int) h); 841 } 842 843 static int 844 iscommand(name) 845 Char *name; 846 { 847 register Char **pv; 848 register Char *sav; 849 register struct varent *v; 850 register bool slash = any(short2str(name), '/'); 851 register int hashval, i; 852 853 v = adrof(STRpath); 854 if (v == NULL || v->vec == NULL || v->vec[0] == NULL || slash) 855 pv = justabs; 856 else 857 pv = v->vec; 858 sav = Strspl(STRslash, name); /* / command name for postpending */ 859 hashval = havhash ? hashname(name) : 0; 860 i = 0; 861 do { 862 if (!slash && ABSOLUTEP(pv[0]) && havhash) { 863 #ifdef FASTHASH 864 if (!bit(hashval, i)) 865 goto cont; 866 #else /* OLDHASH */ 867 int hashval1 = hash(hashval, i); 868 if (!bit(xhash, hashval1)) 869 goto cont; 870 #endif /* FASTHASH */ 871 } 872 if (pv[0][0] == 0 || eq(pv[0], STRdot)) { /* don't make ./xxx */ 873 if (executable(NULL, name, 0)) { 874 xfree((ptr_t) sav); 875 return i + 1; 876 } 877 } 878 else { 879 if (executable(*pv, sav, 0)) { 880 xfree((ptr_t) sav); 881 return i + 1; 882 } 883 } 884 cont: 885 pv++; 886 i++; 887 } while (*pv); 888 xfree((ptr_t) sav); 889 return 0; 890 } 891 892 /* Also by: 893 * Andreas Luik <luik@isaak.isa.de> 894 * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung 895 * Azenberstr. 35 896 * D-7000 Stuttgart 1 897 * West-Germany 898 * is the executable() routine below and changes to iscommand(). 899 * Thanks again!! 900 */ 901 902 #ifndef WINNT_NATIVE 903 /* 904 * executable() examines the pathname obtained by concatenating dir and name 905 * (dir may be NULL), and returns 1 either if it is executable by us, or 906 * if dir_ok is set and the pathname refers to a directory. 907 * This is a bit kludgy, but in the name of optimization... 908 */ 909 int 910 executable(dir, name, dir_ok) 911 Char *dir, *name; 912 bool dir_ok; 913 { 914 struct stat stbuf; 915 Char path[MAXPATHLEN + 1]; 916 char *strname; 917 (void) memset(path, 0, sizeof(path)); 918 919 if (dir && *dir) { 920 copyn(path, dir, MAXPATHLEN); 921 catn(path, name, MAXPATHLEN); 922 strname = short2str(path); 923 } 924 else 925 strname = short2str(name); 926 927 return (stat(strname, &stbuf) != -1 && 928 ((dir_ok && S_ISDIR(stbuf.st_mode)) || 929 (S_ISREG(stbuf.st_mode) && 930 /* save time by not calling access() in the hopeless case */ 931 (stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) && 932 access(strname, X_OK) == 0 933 ))); 934 } 935 #endif /*!WINNT_NATIVE*/ 936 937 int 938 tellmewhat(lexp, str) 939 struct wordent *lexp; 940 Char *str; 941 { 942 register int i; 943 register struct biltins *bptr; 944 register struct wordent *sp = lexp->next; 945 bool aliased = 0, found; 946 Char *s0, *s1, *s2, *cmd; 947 Char qc; 948 949 if (adrof1(sp->word, &aliases)) { 950 alias(lexp); 951 sp = lexp->next; 952 aliased = 1; 953 } 954 955 s0 = sp->word; /* to get the memory freeing right... */ 956 957 /* handle quoted alias hack */ 958 if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE) 959 (sp->word)++; 960 961 /* do quoting, if it hasn't been done */ 962 s1 = s2 = sp->word; 963 while (*s2) 964 switch (*s2) { 965 case '\'': 966 case '"': 967 qc = *s2++; 968 while (*s2 && *s2 != qc) 969 *s1++ = *s2++ | QUOTE; 970 if (*s2) 971 s2++; 972 break; 973 case '\\': 974 if (*++s2) 975 *s1++ = *s2++ | QUOTE; 976 break; 977 default: 978 *s1++ = *s2++; 979 } 980 *s1 = '\0'; 981 982 for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) { 983 if (eq(sp->word, str2short(bptr->bname))) { 984 if (str == NULL) { 985 if (aliased) 986 prlex(lexp); 987 xprintf(CGETS(13, 5, "%S: shell built-in command.\n"), 988 sp->word); 989 flush(); 990 } 991 else 992 (void) Strcpy(str, sp->word); 993 sp->word = s0; /* we save and then restore this */ 994 return TRUE; 995 } 996 } 997 #ifdef WINNT_NATIVE 998 for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++) { 999 if (eq(sp->word, str2short(bptr->bname))) { 1000 if (str == NULL) { 1001 if (aliased) 1002 prlex(lexp); 1003 xprintf(CGETS(13, 5, "%S: shell built-in command.\n"), 1004 sp->word); 1005 flush(); 1006 } 1007 else 1008 (void) Strcpy(str, sp->word); 1009 sp->word = s0; /* we save and then restore this */ 1010 return TRUE; 1011 } 1012 } 1013 #endif /* WINNT_NATIVE*/ 1014 1015 sp->word = cmd = globone(sp->word, G_IGNORE); 1016 1017 if ((i = iscommand(sp->word)) != 0) { 1018 register Char **pv; 1019 register struct varent *v; 1020 bool slash = any(short2str(sp->word), '/'); 1021 1022 v = adrof(STRpath); 1023 if (v == NULL || v->vec == NULL || v->vec[0] == NULL || slash) 1024 pv = justabs; 1025 else 1026 pv = v->vec; 1027 1028 while (--i) 1029 pv++; 1030 if (pv[0][0] == 0 || eq(pv[0], STRdot)) { 1031 if (!slash) { 1032 sp->word = Strspl(STRdotsl, sp->word); 1033 prlex(lexp); 1034 xfree((ptr_t) sp->word); 1035 } 1036 else 1037 prlex(lexp); 1038 } 1039 else { 1040 s1 = Strspl(*pv, STRslash); 1041 sp->word = Strspl(s1, sp->word); 1042 xfree((ptr_t) s1); 1043 if (str == NULL) 1044 prlex(lexp); 1045 else 1046 (void) Strcpy(str, sp->word); 1047 xfree((ptr_t) sp->word); 1048 } 1049 found = 1; 1050 } 1051 else { 1052 if (str == NULL) { 1053 if (aliased) 1054 prlex(lexp); 1055 xprintf(CGETS(13, 6, "%S: Command not found.\n"), sp->word); 1056 flush(); 1057 } 1058 else 1059 (void) Strcpy(str, sp->word); 1060 found = 0; 1061 } 1062 sp->word = s0; /* we save and then restore this */ 1063 xfree((ptr_t) cmd); 1064 return found; 1065 } 1066 1067 /* 1068 * Builtin to look at and list all places a command may be defined: 1069 * aliases, shell builtins, and the path. 1070 * 1071 * Marc Horowitz <marc@mit.edu> 1072 * MIT Student Information Processing Board 1073 */ 1074 1075 /*ARGSUSED*/ 1076 void 1077 dowhere(v, c) 1078 register Char **v; 1079 struct command *c; 1080 { 1081 int found = 1; 1082 USE(c); 1083 for (v++; *v; v++) 1084 found &= find_cmd(*v, 1); 1085 /* Make status nonzero if any command is not found. */ 1086 if (!found) 1087 set(STRstatus, Strsave(STR1), VAR_READWRITE); 1088 } 1089 1090 int 1091 find_cmd(cmd, prt) 1092 Char *cmd; 1093 int prt; 1094 { 1095 struct varent *var; 1096 struct biltins *bptr; 1097 Char **pv; 1098 Char *sv; 1099 int hashval, i, ex, rval = 0; 1100 1101 if (prt && any(short2str(cmd), '/')) { 1102 xprintf(CGETS(13, 7, "where: / in command makes no sense\n")); 1103 return rval; 1104 } 1105 1106 /* first, look for an alias */ 1107 1108 if (prt && adrof1(cmd, &aliases)) { 1109 if ((var = adrof1(cmd, &aliases)) != NULL) { 1110 xprintf(CGETS(13, 8, "%S is aliased to "), cmd); 1111 if (var->vec != NULL) 1112 blkpr(var->vec); 1113 xputchar('\n'); 1114 rval = 1; 1115 } 1116 } 1117 1118 /* next, look for a shell builtin */ 1119 1120 for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) { 1121 if (eq(cmd, str2short(bptr->bname))) { 1122 rval = 1; 1123 if (prt) 1124 xprintf(CGETS(13, 9, "%S is a shell built-in\n"), cmd); 1125 else 1126 return rval; 1127 } 1128 } 1129 #ifdef WINNT_NATIVE 1130 for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++) { 1131 if (eq(cmd, str2short(bptr->bname))) { 1132 rval = 1; 1133 if (prt) 1134 xprintf(CGETS(13, 9, "%S is a shell built-in\n"), cmd); 1135 else 1136 return rval; 1137 } 1138 } 1139 #endif /* WINNT_NATIVE*/ 1140 1141 /* last, look through the path for the command */ 1142 1143 if ((var = adrof(STRpath)) == NULL) 1144 return rval; 1145 1146 hashval = havhash ? hashname(cmd) : 0; 1147 1148 sv = Strspl(STRslash, cmd); 1149 1150 for (pv = var->vec, i = 0; pv && *pv; pv++, i++) { 1151 if (havhash && !eq(*pv, STRdot)) { 1152 #ifdef FASTHASH 1153 if (!bit(hashval, i)) 1154 continue; 1155 #else /* OLDHASH */ 1156 int hashval1 = hash(hashval, i); 1157 if (!bit(xhash, hashval1)) 1158 continue; 1159 #endif /* FASTHASH */ 1160 } 1161 ex = executable(*pv, sv, 0); 1162 #ifdef FASTHASH 1163 if (!ex && (hashdebug & 2)) { 1164 xprintf(CGETS(13, 10, "hash miss: ")); 1165 ex = 1; /* Force printing */ 1166 } 1167 #endif /* FASTHASH */ 1168 if (ex) { 1169 rval = 1; 1170 if (prt) { 1171 xprintf("%S/", *pv); 1172 xprintf("%S\n", cmd); 1173 } 1174 else 1175 return rval; 1176 } 1177 } 1178 xfree((ptr_t) sv); 1179 return rval; 1180 } 1181 #ifdef WINNT_NATIVE 1182 int hashval_extern(cp) 1183 Char *cp; 1184 { 1185 return havhash?hashname(cp):0; 1186 } 1187 int bit_extern(val,i) 1188 int val; 1189 int i; 1190 { 1191 return bit(val,i); 1192 } 1193 void bis_extern(val,i) 1194 int val; 1195 int i; 1196 { 1197 bis(val,i); 1198 } 1199 #endif /* WINNT_NATIVE */ 1200 1201