home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume25 / tcsh-6.01 / part10 / sh.exec.c < prev    next >
C/C++ Source or Header  |  1991-12-19  |  23KB  |  960 lines

  1. /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.01/RCS/sh.exec.c,v 3.9 1991/12/14 20:45:46 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. All advertising materials mentioning features or use of this software
  18.  *    must display the following acknowledgement:
  19.  *    This product includes software developed by the University of
  20.  *    California, Berkeley and its contributors.
  21.  * 4. Neither the name of the University nor the names of its contributors
  22.  *    may be used to endorse or promote products derived from this software
  23.  *    without specific prior written permission.
  24.  *
  25.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35.  * SUCH DAMAGE.
  36.  */
  37. #include "sh.h"
  38.  
  39. RCSID("$Id: sh.exec.c,v 3.9 1991/12/14 20:45:46 christos Exp $")
  40.  
  41. #include "tc.h"
  42. #include "tw.h"
  43.  
  44. /*
  45.  * C shell
  46.  */
  47.  
  48. #ifndef OLDHASH
  49. # define FASTHASH    /* Fast hashing is the default */
  50. #endif /* OLDHASH */
  51.  
  52. /*
  53.  * System level search and execute of a command.
  54.  * We look in each directory for the specified command name.
  55.  * If the name contains a '/' then we execute only the full path name.
  56.  * If there is no search path then we execute only full path names.
  57.  */
  58.  
  59. /*
  60.  * As we search for the command we note the first non-trivial error
  61.  * message for presentation to the user.  This allows us often
  62.  * to show that a file has the wrong mode/no access when the file
  63.  * is not in the last component of the search path, so we must
  64.  * go on after first detecting the error.
  65.  */
  66. static char *exerr;        /* Execution error message */
  67. static Char *expath;        /* Path for exerr */
  68.  
  69. /*
  70.  * The two part hash function is designed to let texec() call the
  71.  * more expensive hashname() only once and the simple hash() several
  72.  * times (once for each path component checked).
  73.  * Byte size is assumed to be 8.
  74.  */
  75. #define BITS_PER_BYTE    8
  76.  
  77. #ifdef FASTHASH
  78. /*
  79.  * xhash is an array of hash buckets which are used to hash execs.  If
  80.  * it is allocated (havhash true), then to tell if ``name'' is
  81.  * (possibly) presend in the i'th component of the variable path, look
  82.  * at the [hashname(name)] bucket of size [hashwidth] bytes, in the [i
  83.  * mod size*8]'th bit.  The cache size is defaults to a length of 1024
  84.  * buckets, each 1 byte wide.  This implementation guarantees that
  85.  * objects n bytes wide will be aligned on n byte boundaries.
  86.  */
  87. # define HSHMUL        241
  88.  
  89. static unsigned long *xhash = NULL;
  90. static unsigned int hashlength = 0;
  91. static unsigned int hashwidth = 0;
  92. static int hashdebug = 0;
  93.  
  94. # define hash(a, b)    (((a) * HSHMUL + (b)) % (hashlength))
  95. # define widthof(t)    (sizeof(t) * BITS_PER_BYTE)
  96. # define tbit(f, i, t)    (((t *) xhash)[(f)] &  \
  97.              1 << (i & (widthof(t) - 1)))
  98. # define tbis(f, i, t)    (((t *) xhash)[(f)] |= \
  99.              1 << (i & (widthof(t) - 1)))
  100. # define cbit(f, i)    tbit(f, i, unsigned char)
  101. # define cbis(f, i)    tbis(f, i, unsigned char)
  102. # define sbit(f, i)    tbit(f, i, unsigned short)
  103. # define sbis(f, i)    tbis(f, i, unsigned short)
  104. # define lbit(f, i)    tbit(f, i, unsigned long)
  105. # define lbis(f, i)    tbis(f, i, unsigned long)
  106.  
  107. # define bit(f, i) (hashwidth==sizeof(unsigned char)  ? cbit(f,i) : \
  108.             (hashwidth==sizeof(unsigned short) ? sbit(f,i) : lbit(f,i)))
  109. # define bis(f, i) (hashwidth==sizeof(unsigned char)  ? cbis(f,i) : \
  110.            (hashwidth==sizeof(unsigned short) ? sbis(f,i) : lbis(f,i)))
  111.  
  112. #else /* OLDHASH */
  113. /*
  114.  * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used
  115.  * to hash execs.  If it is allocated (havhash true), then to tell
  116.  * whether ``name'' is (possibly) present in the i'th component
  117.  * of the variable path, you look at the bit in xhash indexed by
  118.  * hash(hashname("name"), i).  This is setup automatically
  119.  * after .login is executed, and recomputed whenever ``path'' is
  120.  * changed.
  121.  */
  122. # define HSHSIZ        8192    /* 1k bytes */
  123. # define HSHMASK        (HSHSIZ - 1)
  124. # define HSHMUL        243
  125. static char xhash[HSHSIZ / BITS_PER_BYTE];
  126.  
  127. # define hash(a, b)    (((a) * HSHMUL + (b)) & HSHMASK)
  128. # define bit(h, b)    ((h)[(b) >> 3] & 1 << ((b) & 7))    /* bit test */
  129. # define bis(h, b)    ((h)[(b) >> 3] |= 1 << ((b) & 7))    /* bit set */
  130.  
  131. #endif /* FASTHASH */
  132.  
  133. #ifdef VFORK
  134. static int hits, misses;
  135. #endif
  136.  
  137. /* Dummy search path for just absolute search when no path */
  138. static Char *justabs[] = {STRNULL, 0};
  139.  
  140. static    void    pexerr        __P((void));
  141. static    void    texec        __P((Char *, Char **));
  142. static    int    hashname    __P((Char *));
  143.  
  144. void
  145. doexec(t)
  146.     register struct command *t;
  147. {
  148.     register Char *dp, **pv, **av, *sav;
  149.     register struct varent *v;
  150.     register bool slash;
  151.     register int hashval, i;
  152.     Char   *blk[2];
  153.  
  154.     /*
  155.      * Glob the command name. We will search $path even if this does something,
  156.      * as in sh but not in csh.  One special case: if there is no PATH, then we
  157.      * execute only commands which start with '/'.
  158.      */
  159.     blk[0] = t->t_dcom[0];
  160.     blk[1] = 0;
  161.     gflag = 0, tglob(blk);
  162.     if (gflag) {
  163.     pv = globall(blk);
  164.     if (pv == 0) {
  165.         setname(short2str(blk[0]));
  166.         stderror(ERR_NAME | ERR_NOMATCH);
  167.     }
  168.     gargv = 0;
  169.     }
  170.     else
  171.     pv = saveblk(blk);
  172.  
  173.     trim(pv);
  174.  
  175.     exerr = 0;
  176.     expath = Strsave(pv[0]);
  177. #ifdef VFORK
  178.     Vexpath = expath;
  179. #endif
  180.  
  181.     v = adrof(STRpath);
  182.     if (v == 0 && expath[0] != '/') {
  183.     blkfree(pv);
  184.     pexerr();
  185.     }
  186.     slash = any(short2str(expath), '/');
  187.  
  188.     /*
  189.      * Glob the argument list, if necessary. Otherwise trim off the quote bits.
  190.      */
  191.     gflag = 0;
  192.     av = &t->t_dcom[1];
  193.     tglob(av);
  194.     if (gflag) {
  195.     av = globall(av);
  196.     if (av == 0) {
  197.         blkfree(pv);
  198.         setname(short2str(expath));
  199.         stderror(ERR_NAME | ERR_NOMATCH);
  200.     }
  201.     gargv = 0;
  202.     }
  203.     else
  204.     av = saveblk(av);
  205.  
  206.     blkfree(t->t_dcom);
  207.     t->t_dcom = blkspl(pv, av);
  208.     xfree((ptr_t) pv);
  209.     xfree((ptr_t) av);
  210.     av = t->t_dcom;
  211.     trim(av);
  212.  
  213.     if (*av == NULL || **av == '\0')
  214.     pexerr();
  215.  
  216.     xechoit(av);        /* Echo command if -x */
  217. #ifdef FIOCLEX
  218.     /*
  219.      * Since all internal file descriptors are set to close on exec, we don't
  220.      * need to close them explicitly here.  Just reorient ourselves for error
  221.      * messages.
  222.      */
  223.     SHIN = 0;
  224.     SHOUT = 1;
  225.     SHDIAG = 2;
  226.     OLDSTD = 0;
  227.     isoutatty = isatty(SHOUT);
  228.     isdiagatty = isatty(SHDIAG);
  229. #else
  230.     closech();            /* Close random fd's */
  231. #endif
  232.     /*
  233.      * We must do this AFTER any possible forking (like `foo` in glob) so that
  234.      * this shell can still do subprocesses.
  235.      */
  236. #ifdef BSDSIGS
  237.     (void) sigsetmask((sigmask_t) 0);
  238. #else                /* BSDSIGS */
  239.     (void) sigrelse(SIGINT);
  240.     (void) sigrelse(SIGCHLD);
  241. #endif                /* BSDSIGS */
  242.  
  243.     /*
  244.      * If no path, no words in path, or a / in the filename then restrict the
  245.      * command search.
  246.      */
  247.     if (v == 0 || v->vec[0] == 0 || slash)
  248.     pv = justabs;
  249.     else
  250.     pv = v->vec;
  251.     sav = Strspl(STRslash, *av);/* / command name for postpending */
  252. #ifdef VFORK
  253.     Vsav = sav;
  254. #endif
  255.     hashval = havhash ? hashname(*av) : 0;
  256.  
  257.     i = 0;
  258. #ifdef VFORK
  259.     hits++;
  260. #endif
  261.     do {
  262.     /*
  263.      * Try to save time by looking at the hash table for where this command
  264.      * could be.  If we are doing delayed hashing, then we put the names in
  265.      * one at a time, as the user enters them.  This is kinda like Korn
  266.      * Shell's "tracked aliases".
  267.      */
  268.     if (!slash && pv[0][0] == '/' && havhash) {
  269. #ifdef FASTHASH
  270.         if (!bit(hashval, i))
  271.         goto cont;
  272. #else /* OLDHASH */
  273.         int hashval1 = hash(hashval, i);
  274.         if (!bit(xhash, hashval1))
  275.         goto cont;
  276. #endif /* FASTHASH */
  277.     }
  278.     if (pv[0][0] == 0 || eq(pv[0], STRdot))    /* don't make ./xxx */
  279.         texec(*av, av);
  280.     else {
  281.         dp = Strspl(*pv, sav);
  282. #ifdef VFORK
  283.         Vdp = dp;
  284. #endif
  285.         texec(dp, av);
  286. #ifdef VFORK
  287.         Vdp = 0;
  288. #endif
  289.         xfree((ptr_t) dp);
  290.     }
  291. #ifdef VFORK
  292.     misses++;
  293. #endif
  294. cont:
  295.     pv++;
  296.     i++;
  297.     } while (*pv);
  298. #ifdef VFORK
  299.     hits--;
  300. #endif
  301. #ifdef VFORK
  302.     Vsav = 0;
  303. #endif
  304.     xfree((ptr_t) sav);
  305.     pexerr();
  306. }
  307.  
  308. static void
  309. pexerr()
  310. {
  311.     /* Couldn't find the damn thing */
  312.     if (expath) {
  313.     setname(short2str(expath));
  314. #ifdef VFORK
  315.     Vexpath = 0;
  316. #endif
  317.     xfree((ptr_t) expath);
  318.     expath = 0;
  319.     }
  320.     else
  321.     setname("");
  322.     if (exerr)
  323.     stderror(ERR_NAME | ERR_STRING, exerr);
  324.     stderror(ERR_NAME | ERR_COMMAND);
  325. }
  326.  
  327. /*
  328.  * Execute command f, arg list t.
  329.  * Record error message if not found.
  330.  * Also do shell scripts here.
  331.  */
  332. static void
  333. texec(sf, st)
  334.     Char   *sf;
  335.     register Char **st;
  336. {
  337.     register char **t;
  338.     register char *f;
  339.     register struct varent *v;
  340.     register Char **vp;
  341.     Char   *lastsh[2];
  342.     int     fd;
  343.     unsigned char c;
  344.     Char   *st0, **ost;
  345.  
  346.     /* The order for the conversions is significant */
  347.     t = short2blk(st);
  348.     f = short2str(sf);
  349. #ifdef VFORK
  350.     Vt = t;
  351. #endif
  352.     errno = 0;            /* don't use a previous error */
  353. #ifdef apollo
  354.     /*
  355.      * If we try to execute an nfs mounted directory on the apollo, we
  356.      * hang forever. So until apollo fixes that..
  357.      */
  358.     {
  359.     struct stat stb;
  360.     if (stat(f, &stb) == 0 && S_ISDIR(stb.st_mode))
  361.         errno = EISDIR;
  362.     }
  363.     if (errno == 0)
  364. #endif
  365.     (void) execv(f, t);
  366. #ifdef VFORK
  367.     Vt = 0;
  368. #endif
  369.     blkfree((Char **) t);
  370.     switch (errno) {
  371.  
  372.     case ENOEXEC:
  373.     /*
  374.      * From: casper@fwi.uva.nl (Casper H.S. Dik) If we could not execute
  375.      * it, don't feed it to the shell if it looks like a binary!
  376.      */
  377.     if ((fd = open(f, O_RDONLY)) != -1) {
  378.         if (read(fd, (char *) &c, 1) == 1) {
  379.         if (!Isprint(c) && (c != '\n' && c != '\t')) {
  380.             (void) close(fd);
  381.             /*
  382.              * We *know* what ENOEXEC means.
  383.              */
  384.             stderror(ERR_ARCH, f, strerror(errno));
  385.         }
  386.         }
  387. #ifdef _PATH_BSHELL
  388.         else
  389.         c = '#';
  390. #endif
  391.         (void) close(fd);
  392.     }
  393.     /*
  394.      * If there is an alias for shell, then put the words of the alias in
  395.      * front of the argument list replacing the command name. Note no
  396.      * interpretation of the words at this point.
  397.      */
  398.     v = adrof1(STRshell, &aliases);
  399.     if (v == 0) {
  400.         vp = lastsh;
  401.         vp[0] = adrof(STRshell) ? value(STRshell) : STR_SHELLPATH;
  402.         vp[1] = NULL;
  403. #ifdef _PATH_BSHELL
  404.         if (fd != -1 
  405. # ifndef ISC    /* Compatible with ISC's /bin/csh */
  406.         && c != '#'
  407. # endif /* ISC */
  408.         )
  409.         vp[0] = STR_BSHELL;
  410. #endif
  411.     }
  412.     else
  413.         vp = v->vec;
  414.     st0 = st[0];
  415.     st[0] = sf;
  416.     ost = st;
  417.     st = blkspl(vp, st);    /* Splice up the new arglst */
  418.     ost[0] = st0;
  419.     sf = *st;
  420.     /* The order for the conversions is significant */
  421.     t = short2blk(st);
  422.     f = short2str(sf);
  423.     xfree((ptr_t) st);
  424. #ifdef VFORK
  425.     Vt = t;
  426. #endif
  427.     (void) execv(f, t);
  428. #ifdef VFORK
  429.     Vt = 0;
  430. #endif
  431.     blkfree((Char **) t);
  432.     /* The sky is falling, the sky is falling! */
  433.  
  434.     case ENOMEM:
  435.     stderror(ERR_SYSTEM, f, strerror(errno));
  436.  
  437. #ifdef _IBMR2
  438.     case 0:            /* execv fails and returns 0! */
  439. #endif                /* _IBMR2 */
  440.     case ENOENT:
  441.     break;
  442.  
  443.     default:
  444.     if (exerr == 0) {
  445.         exerr = strerror(errno);
  446.         if (expath)
  447.         xfree((ptr_t) expath);
  448.         expath = Strsave(sf);
  449. #ifdef VFORK
  450.         Vexpath = expath;
  451. #endif
  452.     }
  453.     }
  454. }
  455.  
  456. /*ARGSUSED*/
  457. void
  458. execash(t, kp)
  459.     Char  **t;
  460.     register struct command *kp;
  461. {
  462.     int     saveIN, saveOUT, saveDIAG, saveSTD;
  463.     int     oSHIN;
  464.     int     oSHOUT;
  465.     int     oSHDIAG;
  466.     int     oOLDSTD;
  467.     jmp_buf osetexit;
  468.     int        my_reenter;
  469.     int     odidfds;
  470. #ifndef FIOCLEX
  471.     int        odidcch;
  472. #endif /* FIOCLEX */
  473.     sigret_t (*osigint)(), (*osigquit)(), (*osigterm)();
  474.  
  475.     if (chkstop == 0 && setintr)
  476.     panystop(0);
  477.     /*
  478.      * Hmm, we don't really want to do that now because we might
  479.      * fail, but what is the choice
  480.      */
  481.     rechist();
  482.  
  483.  
  484.     osigint  = signal(SIGINT, parintr);
  485.     osigquit = signal(SIGQUIT, parintr);
  486.     osigterm = signal(SIGTERM, parterm);
  487.  
  488.     odidfds = didfds;
  489. #ifndef FIOCLEX
  490.     odidcch = didcch;
  491. #endif /* FIOCLEX */
  492.     oSHIN = SHIN;
  493.     oSHOUT = SHOUT;
  494.     oSHDIAG = SHDIAG;
  495.     oOLDSTD = OLDSTD;
  496.  
  497.     saveIN = dcopy(SHIN, -1);
  498.     saveOUT = dcopy(SHOUT, -1);
  499.     saveDIAG = dcopy(SHDIAG, -1);
  500.     saveSTD = dcopy(OLDSTD, -1);
  501.     
  502.     lshift(kp->t_dcom, 1);
  503.  
  504.     getexit(osetexit);
  505.  
  506.     /* PWP: setjmp/longjmp bugfix for optimizing compilers */
  507. #ifdef cray
  508.     my_reenter = 1;             /* assume non-zero return val */
  509.     if (setexit() == 0) {
  510.         my_reenter = 0;         /* Oh well, we were wrong */
  511. #else /* !cray */
  512.     if ((my_reenter = setexit()) == 0) {
  513. #endif /* cray */
  514.     SHIN = dcopy(0, -1);
  515.     SHOUT = dcopy(1, -1);
  516.     SHDIAG = dcopy(2, -1);
  517. #ifndef FIOCLEX
  518.     didcch = 0;
  519. #endif /* FIOCLEX */
  520.     didfds = 0;
  521.     /*
  522.      * Decrement the shell level
  523.      */
  524.     shlvl(-1);
  525.     doexec(kp);
  526.     }
  527.  
  528.     (void) sigset(SIGINT, osigint);
  529.     (void) sigset(SIGQUIT, osigquit);
  530.     (void) sigset(SIGTERM, osigterm);
  531.  
  532.     doneinp = 0;
  533. #ifndef FIOCLEX
  534.     didcch = odidcch;
  535. #endif /* FIOCLEX */
  536.     didfds = odidfds;
  537.     (void) close(SHIN);
  538.     (void) close(SHOUT);
  539.     (void) close(SHDIAG);
  540.     (void) close(OLDSTD);
  541.     SHIN = dmove(saveIN, oSHIN);
  542.     SHOUT = dmove(saveOUT, oSHOUT);
  543.     SHDIAG = dmove(saveDIAG, oSHDIAG);
  544.     OLDSTD = dmove(saveSTD, oOLDSTD);
  545.  
  546.     resexit(osetexit);
  547.     if (my_reenter)
  548.     stderror(ERR_SILENT);
  549. }
  550.  
  551. void
  552. xechoit(t)
  553.     Char  **t;
  554. {
  555.     if (adrof(STRecho)) {
  556.     flush();
  557.     haderr = 1;
  558.     blkpr(t), xputchar('\n');
  559.     haderr = 0;
  560.     }
  561. }
  562.  
  563. /*ARGSUSED*/
  564. void
  565. dohash(vv, c)
  566.     Char **vv;
  567.     struct command *c;
  568. {
  569. #ifdef COMMENT
  570.     struct stat stb;
  571. #endif
  572.     DIR    *dirp;
  573.     register struct dirent *dp;
  574.     int     i = 0;
  575.     struct varent *v = adrof(STRpath);
  576.     Char  **pv;
  577.     int hashval;
  578.  
  579. #ifdef FASTHASH
  580.     if (vv && vv[1]) {
  581.        hashlength = atoi(short2str(vv[1]));
  582.        if (vv[2]) {
  583.       hashwidth = atoi(short2str(vv[2]));
  584.       if ((hashwidth != sizeof(unsigned char)) && 
  585.           (hashwidth != sizeof(unsigned short)) && 
  586.           (hashwidth != sizeof(unsigned long)))
  587.          hashwidth = 0;
  588.       if (vv[3])
  589.          hashdebug = atoi(short2str(vv[3]));
  590.        }
  591.     }
  592.  
  593.     if (hashwidth == 0) {
  594.        for (pv = v->vec; *pv; pv++, hashwidth++);
  595.        if (hashwidth <= widthof(unsigned char))
  596.       hashwidth = sizeof(unsigned char);
  597.        else if (hashwidth <= widthof(unsigned short))
  598.       hashwidth = sizeof(unsigned short);
  599.        else
  600.       hashwidth = sizeof(unsigned long);
  601.     }
  602.     if (hashlength == 0) {
  603.        hashlength = hashwidth * (8*64);    /* "average" files per dir in path */
  604.     }
  605.  
  606.     if (xhash)
  607.        xfree((ptr_t) xhash);
  608.     xhash = (unsigned long *) xcalloc(hashlength * hashwidth, 1);
  609. #endif /* FASTHASH */
  610.  
  611.     (void) getusername(NULL);    /* flush the tilde cashe */
  612.     tw_clear_comm_list();
  613.     havhash = 1;
  614.     if (v == NULL)
  615.     return;
  616.     for (pv = v->vec; *pv; pv++, i++) {
  617.     if (pv[0][0] != '/')
  618.         continue;
  619.     dirp = opendir(short2str(*pv));
  620.     if (dirp == NULL)
  621.         continue;
  622. #ifdef COMMENT            /* this isn't needed.  opendir won't open
  623.                  * non-dirs */
  624.     if (fstat(dirp->dd_fd, &stb) < 0 || !S_ISDIR(stb.st_mode)) {
  625.         (void) closedir(dirp);
  626.         continue;
  627.     }
  628. #endif
  629.     while ((dp = readdir(dirp)) != NULL) {
  630.         if (dp->d_ino == 0)
  631.         continue;
  632.         if (dp->d_name[0] == '.' &&
  633.         (dp->d_name[1] == '\0' ||
  634.          (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
  635.         continue;
  636. #ifdef FASTHASH
  637.         hashval = hashname(str2short(dp->d_name));
  638.         bis(hashval, i);
  639.         if (hashdebug & 1)
  640.            xprintf("hash=%-4d dir=%-2d prog=%s\n",
  641.                hashname(str2short(dp->d_name)), i, dp->d_name);
  642. #else /* OLD HASH */
  643.         hashval = hash(hashname(str2short(dp->d_name)), i);
  644.         bis(xhash, hashval);
  645. #endif /* FASTHASH */
  646.         /* tw_add_comm_name (dp->d_name); */
  647.     }
  648.     (void) closedir(dirp);
  649.     }
  650. }
  651.  
  652. /*ARGSUSED*/
  653. void
  654. dounhash(v, c)
  655.     Char **v;
  656.     struct command *c;
  657. {
  658.     havhash = 0;
  659. #ifdef FASTHASH
  660.     if (xhash) {
  661.        xfree((ptr_t) xhash);
  662.        xhash = NULL;
  663.     }
  664. #endif /* FASTHASH */
  665. }
  666.  
  667. #ifdef VFORK
  668. /*ARGSUSED*/
  669. void
  670. hashstat(v, c)
  671.     Char **v;
  672.     struct command *c;
  673. {
  674. #ifdef FASTHASH 
  675.    if (havhash && hashlength && hashwidth)
  676.       xprintf("%d hash buckets of %d bits each\n",
  677.           hashlength, hashwidth*8);
  678.    if (hashdebug)
  679.       xprintf("debug mask = 0x%08x\n", hashdebug);
  680. #endif /* FASTHASH */
  681.    if (hits + misses)
  682.       xprintf("%d hits, %d misses, %d%%\n",
  683.           hits, misses, 100 * hits / (hits + misses));
  684. }
  685.  
  686. #endif
  687.  
  688. /*
  689.  * Hash a command name.
  690.  */
  691. static int
  692. hashname(cp)
  693.     register Char *cp;
  694. {
  695.     register long h;
  696.  
  697.     for (h = 0; *cp; cp++)
  698.     h = hash(h, *cp);
  699.     return ((int) h);
  700. }
  701.  
  702. int
  703. iscommand(name)
  704.     Char   *name;
  705. {
  706.     register Char **pv;
  707.     register Char *sav;
  708.     register struct varent *v;
  709.     register bool slash = any(short2str(name), '/');
  710.     register int hashval, i;
  711.  
  712.     v = adrof(STRpath);
  713.     if (v == 0 || v->vec[0] == 0 || slash)
  714.     pv = justabs;
  715.     else
  716.     pv = v->vec;
  717.     sav = Strspl(STRslash, name);    /* / command name for postpending */
  718.     hashval = havhash ? hashname(name) : 0;
  719.     i = 0;
  720.     do {
  721.     if (!slash && pv[0][0] == '/' && havhash) {
  722. #ifdef FASTHASH
  723.         if (!bit(hashval, i))
  724.         goto cont;
  725. #else /* OLDHASH */
  726.         int hashval1 = hash(hashval, i);
  727.         if (!bit(xhash, hashval1))
  728.         goto cont;
  729. #endif /* FASTHASH */
  730.     }
  731.     if (pv[0][0] == 0 || eq(pv[0], STRdot)) {    /* don't make ./xxx */
  732.         if (executable(NULL, name, 0)) {
  733.         xfree((ptr_t) sav);
  734.         return i + 1;
  735.         }
  736.     }
  737.     else {
  738.         if (executable(*pv, sav, 0)) {
  739.         xfree((ptr_t) sav);
  740.         return i + 1;
  741.         }
  742.     }
  743. cont:
  744.     pv++;
  745.     i++;
  746.     } while (*pv);
  747.     xfree((ptr_t) sav);
  748.     return 0;
  749. }
  750.  
  751. /* Also by:
  752.  *  Andreas Luik <luik@isaak.isa.de>
  753.  *  I S A  GmbH - Informationssysteme fuer computerintegrierte Automatisierung
  754.  *  Azenberstr. 35
  755.  *  D-7000 Stuttgart 1
  756.  *  West-Germany
  757.  * is the executable() routine below and changes to iscommand().
  758.  * Thanks again!!
  759.  */
  760.  
  761. /*
  762.  * executable() examines the pathname obtained by concatenating dir and name
  763.  * (dir may be NULL), and returns 1 either if it is executable by us, or
  764.  * if dir_ok is set and the pathname refers to a directory.
  765.  * This is a bit kludgy, but in the name of optimization...
  766.  */
  767. int
  768. executable(dir, name, dir_ok)
  769.     Char   *dir, *name;
  770.     bool    dir_ok;
  771. {
  772.     struct stat stbuf;
  773.     Char    path[MAXPATHLEN + 1];
  774.     char   *strname;
  775.  
  776.     if (dir && *dir) {
  777.     copyn(path, dir, MAXPATHLEN);
  778.     catn(path, name, MAXPATHLEN);
  779.     strname = short2str(path);
  780.     }
  781.     else
  782.     strname = short2str(name);
  783.     return (stat(strname, &stbuf) != -1 &&
  784.         ((S_ISREG(stbuf.st_mode) &&
  785.     /* save time by not calling access() in the hopeless case */
  786.           (stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) &&
  787.           access(strname, X_OK) == 0) ||
  788.          (dir_ok && S_ISDIR(stbuf.st_mode))));
  789. }
  790.  
  791. void
  792. tellmewhat(lex)
  793.     struct wordent *lex;
  794. {
  795.     register int i;
  796.     register struct biltins *bptr;
  797.     register struct wordent *sp = lex->next;
  798.     bool    aliased = 0;
  799.     Char   *s0, *s1, *s2;
  800.     Char    qc;
  801.  
  802.     if (adrof1(sp->word, &aliases)) {
  803.     alias(lex);
  804.     sp = lex->next;
  805.     aliased = 1;
  806.     }
  807.  
  808.     s0 = sp->word;        /* to get the memory freeing right... */
  809.  
  810.     /* handle quoted alias hack */
  811.     if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE)
  812.     (sp->word)++;
  813.  
  814.     /* do quoting, if it hasn't been done */
  815.     s1 = s2 = sp->word;
  816.     while (*s2)
  817.     switch (*s2) {
  818.     case '\'':
  819.     case '"':
  820.         qc = *s2++;
  821.         while (*s2 && *s2 != qc)
  822.         *s1++ = *s2++ | QUOTE;
  823.         if (*s2)
  824.         s2++;
  825.         break;
  826.     case '\\':
  827.         if (*++s2)
  828.         *s1++ = *s2++ | QUOTE;
  829.         break;
  830.     default:
  831.         *s1++ = *s2++;
  832.     }
  833.     *s1 = '\0';
  834.  
  835.     for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) {
  836.     if (eq(sp->word, str2short(bptr->bname))) {
  837.         if (aliased)
  838.         prlex(lex);
  839.         xprintf("%s: shell built-in command.\n", short2str(sp->word));
  840.         flush();
  841.         sp->word = s0;    /* we save and then restore this */
  842.         return;
  843.     }
  844.     }
  845.  
  846.     if (i = iscommand(strip(sp->word))) {
  847.     register Char **pv;
  848.     register struct varent *v;
  849.     bool    slash = any(short2str(sp->word), '/');
  850.  
  851.     v = adrof(STRpath);
  852.     if (v == 0 || v->vec[0] == 0 || slash)
  853.         pv = justabs;
  854.     else
  855.         pv = v->vec;
  856.  
  857.     while (--i)
  858.         pv++;
  859.     if (pv[0][0] == 0 || eq(pv[0], STRdot)) {
  860.         sp->word = Strspl(STRdotsl, sp->word);
  861.         prlex(lex);
  862.         xfree((ptr_t) sp->word);
  863.         sp->word = s0;    /* we save and then restore this */
  864.         return;
  865.     }
  866.     s1 = Strspl(*pv, STRslash);
  867.     sp->word = Strspl(s1, sp->word);
  868.     xfree((ptr_t) s1);
  869.     prlex(lex);
  870.     xfree((ptr_t) sp->word);
  871.     }
  872.     else {
  873.     if (aliased)
  874.         prlex(lex);
  875.     xprintf("%s: Command not found.\n", short2str(sp->word));
  876.     flush();
  877.     }
  878.     sp->word = s0;        /* we save and then restore this */
  879. }
  880.  
  881. /*
  882.  * Builtin to look at and list all places a command may be defined:
  883.  * aliases, shell builtins, and the path.
  884.  *
  885.  * Marc Horowitz <marc@mit.edu>
  886.  * MIT Student Information Processing Board
  887.  */
  888.  
  889. /*ARGSUSED*/
  890. void
  891. dowhere(v, c)
  892.     register Char **v;
  893.     struct command *c;
  894. {
  895.     struct varent *var;
  896.     struct biltins *bptr;
  897.     Char **pv;
  898.     Char *sv;
  899.     int hashval, i, ex;
  900.  
  901.     for (v++; *v; v++) {
  902.     if (any(short2str(*v), '/')) {
  903.         xprintf("where: / in command makes no sense\n");
  904.         continue;
  905.     }
  906.  
  907.     /* first, look for an alias */
  908.  
  909.     if (adrof1(*v, &aliases)) {
  910.         if (var = adrof1(*v, &aliases)) {
  911.         xprintf("%s is aliased to ", short2str(*v));
  912.         blkpr(var->vec);
  913.         xprintf("\n");
  914.         }
  915.     }
  916.  
  917.     /* next, look for a shell builtin */
  918.  
  919.     for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) {
  920.         if (eq(*v, str2short(bptr->bname))) {
  921.         xprintf("%s is a shell built-in\n", short2str(*v));
  922.         /* flush(); */
  923.         }
  924.     }
  925.  
  926.     /* last, look through the path for the command */
  927.  
  928.     var = adrof(STRpath);
  929.  
  930.     hashval = havhash ? hashname(*v) : 0;
  931.  
  932.     sv = Strspl(STRslash, *v);
  933.  
  934.     for (pv = var->vec, i = 0; *pv; pv++, i++) {
  935.         if (havhash && !eq(*pv, STRdot)) {
  936. #ifdef FASTHASH
  937.         if (!bit(hashval, i))
  938.             continue;
  939. #else /* OLDHASH */
  940.         int hashval1 = hash(hashval, i);
  941.         if (!bit(xhash, hashval1))
  942.             continue;
  943. #endif /* FASTHASH */
  944.         }
  945.         ex = executable(*pv, sv, 0);
  946. #ifdef FASTHASH
  947.         if (!ex && (hashdebug & 2)) {
  948.         xprintf("hash miss: ");
  949.         ex = 1;    /* Force printing */
  950.         }
  951. #endif /* FASTHASH */
  952.         if (ex) {
  953.         xprintf("%s/",short2str(*pv));
  954.         xprintf("%s\n",short2str(*v));
  955.         }
  956.     }
  957.     xfree((ptr_t) sv);
  958.     }
  959. }
  960.