home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / Shells / tcsh / Source / sh.exec.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-02-21  |  24.7 KB  |  1,045 lines

  1. /* $Header: /u/christos/src/tcsh-6.03/RCS/sh.exec.c,v 3.21 1992/10/27 16:18:15 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.21 1992/10/27 16:18:15 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 /* VFORK */
  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. static    int     iscommand    __P((Char *));
  144.  
  145. void
  146. doexec(t)
  147.     register struct command *t;
  148. {
  149.     register Char *dp, **pv, **av, *sav;
  150.     register struct varent *v;
  151.     register bool slash;
  152.     register int hashval, i;
  153.     Char   *blk[2];
  154.  
  155.     /*
  156.      * Glob the command name. We will search $path even if this does something,
  157.      * as in sh but not in csh.  One special case: if there is no PATH, then we
  158.      * execute only commands which start with '/'.
  159.      */
  160.     blk[0] = t->t_dcom[0];
  161.     blk[1] = 0;
  162.     gflag = 0, tglob(blk);
  163.     if (gflag) {
  164.     pv = globall(blk);
  165.     if (pv == 0) {
  166.         setname(short2str(blk[0]));
  167.         stderror(ERR_NAME | ERR_NOMATCH);
  168.     }
  169.     gargv = 0;
  170.     }
  171.     else
  172.     pv = saveblk(blk);
  173.  
  174.     trim(pv);
  175.  
  176.     exerr = 0;
  177.     expath = Strsave(pv[0]);
  178. #ifdef VFORK
  179.     Vexpath = expath;
  180. #endif /* VFORK */
  181.  
  182.     v = adrof(STRpath);
  183.     if (v == 0 && expath[0] != '/') {
  184.     blkfree(pv);
  185.     pexerr();
  186.     }
  187.     slash = any(short2str(expath), '/');
  188.  
  189.     /*
  190.      * Glob the argument list, if necessary. Otherwise trim off the quote bits.
  191.      */
  192.     gflag = 0;
  193.     av = &t->t_dcom[1];
  194.     tglob(av);
  195.     if (gflag) {
  196.     av = globall(av);
  197.     if (av == 0) {
  198.         blkfree(pv);
  199.         setname(short2str(expath));
  200.         stderror(ERR_NAME | ERR_NOMATCH);
  201.     }
  202.     gargv = 0;
  203.     }
  204.     else
  205.     av = saveblk(av);
  206.  
  207.     blkfree(t->t_dcom);
  208.     t->t_dcom = blkspl(pv, av);
  209.     xfree((ptr_t) pv);
  210.     xfree((ptr_t) av);
  211.     av = t->t_dcom;
  212.     trim(av);
  213.  
  214.     if (*av == NULL || **av == '\0')
  215.     pexerr();
  216.  
  217.     xechoit(av);        /* Echo command if -x */
  218. #ifdef CLOSE_ON_EXEC
  219.     /*
  220.      * Since all internal file descriptors are set to close on exec, we don't
  221.      * need to close them explicitly here.  Just reorient ourselves for error
  222.      * messages.
  223.      */
  224.     SHIN = 0;
  225.     SHOUT = 1;
  226.     SHDIAG = 2;
  227.     OLDSTD = 0;
  228.     isoutatty = isatty(SHOUT);
  229.     isdiagatty = isatty(SHDIAG);
  230. #else
  231.     closech();            /* Close random fd's */
  232. #endif
  233.     /*
  234.      * We must do this AFTER any possible forking (like `foo` in glob) so that
  235.      * this shell can still do subprocesses.
  236.      */
  237. #ifdef BSDSIGS
  238.     (void) sigsetmask((sigmask_t) 0);
  239. #else /* BSDSIGS */
  240.     (void) sigrelse(SIGINT);
  241.     (void) sigrelse(SIGCHLD);
  242. #endif /* BSDSIGS */
  243.  
  244.     /*
  245.      * If no path, no words in path, or a / in the filename then restrict the
  246.      * command search.
  247.      */
  248.     if (v == 0 || v->vec[0] == 0 || slash)
  249.     pv = justabs;
  250.     else
  251.     pv = v->vec;
  252.     sav = Strspl(STRslash, *av);/* / command name for postpending */
  253. #ifdef VFORK
  254.     Vsav = sav;
  255. #endif /* VFORK */
  256.     hashval = havhash ? hashname(*av) : 0;
  257.  
  258.     i = 0;
  259. #ifdef VFORK
  260.     hits++;
  261. #endif /* VFORK */
  262.     do {
  263.     /*
  264.      * Try to save time by looking at the hash table for where this command
  265.      * could be.  If we are doing delayed hashing, then we put the names in
  266.      * one at a time, as the user enters them.  This is kinda like Korn
  267.      * Shell's "tracked aliases".
  268.      */
  269.     if (!slash && pv[0][0] == '/' && havhash) {
  270. #ifdef FASTHASH
  271.         if (!bit(hashval, i))
  272.         goto cont;
  273. #else /* OLDHASH */
  274.         int hashval1 = hash(hashval, i);
  275.         if (!bit(xhash, hashval1))
  276.         goto cont;
  277. #endif /* FASTHASH */
  278.     }
  279.     if (pv[0][0] == 0 || eq(pv[0], STRdot))    /* don't make ./xxx */
  280.     {
  281.  
  282. #ifdef COHERENT
  283.         if (t->t_dflg & F_AMPERSAND) {
  284. # ifdef JOBDEBUG
  285.                 xprintf("set SIGINT to SIG_IGN\n");
  286.                 xprintf("set SIGQUIT to SIG_DFL\n");
  287. # endif /* JOBDEBUG */
  288.                 (void) signal(SIGINT,SIG_IGN); /* may not be necessary */
  289.             (void) signal(SIGQUIT,SIG_DFL);
  290.         }
  291.  
  292.         if (gointr && eq(gointr, STRminus)) {
  293. # ifdef JOBDEBUG
  294.                 xprintf("set SIGINT to SIG_IGN\n");
  295.                 xprintf("set SIGQUIT to SIG_IGN\n");
  296. # endif /* JOBDEBUG */
  297.                 (void) signal(SIGINT,SIG_IGN); /* may not be necessary */
  298.             (void) signal(SIGQUIT,SIG_IGN);
  299.         }
  300. #endif /* COHERENT */
  301.  
  302.         texec(*av, av);
  303. }
  304.     else {
  305.         dp = Strspl(*pv, sav);
  306. #ifdef VFORK
  307.         Vdp = dp;
  308. #endif /* VFORK */
  309.  
  310. #ifdef COHERENT
  311.         if ((t->t_dflg & F_AMPERSAND)) {
  312. # ifdef JOBDEBUG
  313.                 xprintf("set SIGINT to SIG_IGN\n");
  314. # endif /* JOBDEBUG */
  315.         /* 
  316.          * this is necessary on Coherent or all background 
  317.          * jobs are killed by CTRL-C 
  318.          * (there must be a better fix for this) 
  319.          */
  320.                 (void) signal(SIGINT,SIG_IGN); 
  321.         }
  322.         if (gointr && eq(gointr,STRminus)) {
  323. # ifdef JOBDEBUG
  324.                 xprintf("set SIGINT to SIG_IGN\n");
  325.                 xprintf("set SIGQUIT to SIG_IGN\n");
  326. # endif /* JOBDEBUG */
  327.                 (void) signal(SIGINT,SIG_IGN); /* may not be necessary */
  328.             (void) signal(SIGQUIT,SIG_IGN);
  329.         }
  330. #endif /* COHERENT */
  331.  
  332.         texec(dp, av);
  333. #ifdef VFORK
  334.         Vdp = 0;
  335. #endif /* VFORK */
  336.         xfree((ptr_t) dp);
  337.     }
  338. #ifdef VFORK
  339.     misses++;
  340. #endif /* VFORK */
  341. cont:
  342.     pv++;
  343.     i++;
  344.     } while (*pv);
  345. #ifdef VFORK
  346.     hits--;
  347.     Vsav = 0;
  348. #endif /* VFORK */
  349.     xfree((ptr_t) sav);
  350.     pexerr();
  351. }
  352.  
  353. static void
  354. pexerr()
  355. {
  356.     /* Couldn't find the damn thing */
  357.     if (expath) {
  358.     setname(short2str(expath));
  359. #ifdef VFORK
  360.     Vexpath = 0;
  361. #endif /* VFORK */
  362.     xfree((ptr_t) expath);
  363.     expath = 0;
  364.     }
  365.     else
  366.     setname("");
  367.     if (exerr)
  368.     stderror(ERR_NAME | ERR_STRING, exerr);
  369.     stderror(ERR_NAME | ERR_COMMAND);
  370. }
  371.  
  372. /*
  373.  * Execute command f, arg list t.
  374.  * Record error message if not found.
  375.  * Also do shell scripts here.
  376.  */
  377. static void
  378. texec(sf, st)
  379.     Char   *sf;
  380.     register Char **st;
  381. {
  382.     register char **t;
  383.     register char *f;
  384.     register struct varent *v;
  385.     Char  **vp;
  386.     Char   *lastsh[2];
  387.     char    pref[2];
  388.     int     fd;
  389.     Char   *st0, **ost;
  390.  
  391.     /* The order for the conversions is significant */
  392.     t = short2blk(st);
  393.     f = short2str(sf);
  394. #ifdef VFORK
  395.     Vt = t;
  396. #endif /* VFORK */
  397.     errno = 0;            /* don't use a previous error */
  398. #ifdef apollo
  399.     /*
  400.      * If we try to execute an nfs mounted directory on the apollo, we
  401.      * hang forever. So until apollo fixes that..
  402.      */
  403.     {
  404.     struct stat stb;
  405.     if (stat(f, &stb) == 0 && S_ISDIR(stb.st_mode))
  406.         errno = EISDIR;
  407.     }
  408.     if (errno == 0)
  409. #endif /* apollo */
  410.     (void) execv(f, t);
  411. #ifdef VFORK
  412.     Vt = 0;
  413. #endif /* VFORK */
  414.     blkfree((Char **) t);
  415.     switch (errno) {
  416.  
  417.     case ENOEXEC:
  418.     /*
  419.      * From: casper@fwi.uva.nl (Casper H.S. Dik) If we could not execute
  420.      * it, don't feed it to the shell if it looks like a binary!
  421.      */
  422.     if ((fd = open(f, O_RDONLY)) != -1) {
  423.         if (read(fd, (char *) pref, 2) == 2) {
  424.         if (!Isprint(pref[0]) && (pref[0] != '\n' && pref[0] != '\t')) {
  425.             (void) close(fd);
  426.             /*
  427.              * We *know* what ENOEXEC means.
  428.              */
  429.             stderror(ERR_ARCH, f, strerror(errno));
  430.         }
  431.         }
  432. #ifdef _PATH_BSHELL
  433.         else {
  434.         pref[0] = '#';
  435.         pref[1] = '\0';
  436.         }
  437. #endif
  438.     }
  439. #ifdef HASHBANG
  440.     if (fd == -1 ||
  441.         pref[0] != '#' || pref[1] != '!' || hashbang(fd, &vp) == -1) {
  442. #endif /* HASHBANG */
  443.     /*
  444.      * If there is an alias for shell, then put the words of the alias in
  445.      * front of the argument list replacing the command name. Note no
  446.      * interpretation of the words at this point.
  447.      */
  448.         v = adrof1(STRshell, &aliases);
  449.         if (v == 0) {
  450.         vp = lastsh;
  451.         vp[0] = adrof(STRshell) ? value(STRshell) : STR_SHELLPATH;
  452.         vp[1] = NULL;
  453. #ifdef _PATH_BSHELL
  454.         if (fd != -1 
  455. # ifndef ISC    /* Compatible with ISC's /bin/csh */
  456.             && pref[0] != '#'
  457. # endif /* ISC */
  458.             )
  459.             vp[0] = STR_BSHELL;
  460. #endif
  461.         vp = saveblk(vp);
  462.         }
  463.         else
  464.         vp = saveblk(v->vec);
  465. #ifdef HASHBANG
  466.     }
  467. #endif /* HASHBANG */
  468.     if (fd != -1)
  469.         (void) close(fd);
  470.  
  471.     st0 = st[0];
  472.     st[0] = sf;
  473.     ost = st;
  474.     st = blkspl(vp, st);    /* Splice up the new arglst */
  475.     ost[0] = st0;
  476.     sf = *st;
  477.     /* The order for the conversions is significant */
  478.     t = short2blk(st);
  479.     f = short2str(sf);
  480.     xfree((ptr_t) st);
  481.     blkfree((Char **) vp);
  482. #ifdef VFORK
  483.     Vt = t;
  484. #endif /* VFORK */
  485.     (void) execv(f, t);
  486. #ifdef VFORK
  487.     Vt = 0;
  488. #endif /* VFORK */
  489.     blkfree((Char **) t);
  490.     /* The sky is falling, the sky is falling! */
  491.     stderror(ERR_SYSTEM, f, strerror(errno));
  492.     break;
  493.  
  494.     case ENOMEM:
  495.     stderror(ERR_SYSTEM, f, strerror(errno));
  496.     break;
  497.  
  498. #ifdef _IBMR2
  499.     case 0:            /* execv fails and returns 0! */
  500. #endif /* _IBMR2 */
  501.     case ENOENT:
  502.     break;
  503.  
  504.     default:
  505.     if (exerr == 0) {
  506.         exerr = strerror(errno);
  507.         if (expath)
  508.         xfree((ptr_t) expath);
  509.         expath = Strsave(sf);
  510. #ifdef VFORK
  511.         Vexpath = expath;
  512. #endif /* VFORK */
  513.     }
  514.     break;
  515.     }
  516. }
  517.  
  518. /*ARGSUSED*/
  519. void
  520. execash(t, kp)
  521.     Char  **t;
  522.     register struct command *kp;
  523. {
  524.     int     saveIN, saveOUT, saveDIAG, saveSTD;
  525.     int     oSHIN;
  526.     int     oSHOUT;
  527.     int     oSHDIAG;
  528.     int     oOLDSTD;
  529.     jmp_buf_t osetexit;
  530.     int        my_reenter;
  531.     int     odidfds;
  532. #ifndef CLOSE_ON_EXEC
  533.     int        odidcch;
  534. #endif /* CLOSE_ON_EXEC */
  535.     sigret_t (*osigint)(), (*osigquit)(), (*osigterm)();
  536.  
  537.     if (chkstop == 0 && setintr)
  538.     panystop(0);
  539.     /*
  540.      * Hmm, we don't really want to do that now because we might
  541.      * fail, but what is the choice
  542.      */
  543.     rechist(NULL);
  544.  
  545.  
  546.     osigint  = signal(SIGINT, parintr);
  547.     osigquit = signal(SIGQUIT, parintr);
  548.     osigterm = signal(SIGTERM, parterm);
  549.  
  550.     odidfds = didfds;
  551. #ifndef CLOSE_ON_EXEC
  552.     odidcch = didcch;
  553. #endif /* CLOSE_ON_EXEC */
  554.     oSHIN = SHIN;
  555.     oSHOUT = SHOUT;
  556.     oSHDIAG = SHDIAG;
  557.     oOLDSTD = OLDSTD;
  558.  
  559.     saveIN = dcopy(SHIN, -1);
  560.     saveOUT = dcopy(SHOUT, -1);
  561.     saveDIAG = dcopy(SHDIAG, -1);
  562.     saveSTD = dcopy(OLDSTD, -1);
  563.     
  564.     lshift(kp->t_dcom, 1);
  565.  
  566.     getexit(osetexit);
  567.  
  568.     /* PWP: setjmp/longjmp bugfix for optimizing compilers */
  569. #ifdef cray
  570.     my_reenter = 1;             /* assume non-zero return val */
  571.     if (setexit() == 0) {
  572.         my_reenter = 0;         /* Oh well, we were wrong */
  573. #else /* !cray */
  574.     if ((my_reenter = setexit()) == 0) {
  575. #endif /* cray */
  576.     SHIN = dcopy(0, -1);
  577.     SHOUT = dcopy(1, -1);
  578.     SHDIAG = dcopy(2, -1);
  579. #ifndef CLOSE_ON_EXEC
  580.     didcch = 0;
  581. #endif /* CLOSE_ON_EXEC */
  582.     didfds = 0;
  583.     /*
  584.      * Decrement the shell level
  585.      */
  586.     shlvl(-1);
  587.     doexec(kp);
  588.     }
  589.  
  590.     (void) sigset(SIGINT, osigint);
  591.     (void) sigset(SIGQUIT, osigquit);
  592.     (void) sigset(SIGTERM, osigterm);
  593.  
  594.     doneinp = 0;
  595. #ifndef CLOSE_ON_EXEC
  596.     didcch = odidcch;
  597. #endif /* CLOSE_ON_EXEC */
  598.     didfds = odidfds;
  599.     (void) close(SHIN);
  600.     (void) close(SHOUT);
  601.     (void) close(SHDIAG);
  602.     (void) close(OLDSTD);
  603.     SHIN = dmove(saveIN, oSHIN);
  604.     SHOUT = dmove(saveOUT, oSHOUT);
  605.     SHDIAG = dmove(saveDIAG, oSHDIAG);
  606.     OLDSTD = dmove(saveSTD, oOLDSTD);
  607.  
  608.     resexit(osetexit);
  609.     if (my_reenter)
  610.     stderror(ERR_SILENT);
  611. }
  612.  
  613. void
  614. xechoit(t)
  615.     Char  **t;
  616. {
  617.     if (adrof(STRecho)) {
  618.     flush();
  619.     haderr = 1;
  620.     blkpr(t), xputchar('\n');
  621.     haderr = 0;
  622.     }
  623. }
  624.  
  625. /*ARGSUSED*/
  626. void
  627. dohash(vv, c)
  628.     Char **vv;
  629.     struct command *c;
  630. {
  631. #ifdef COMMENT
  632.     struct stat stb;
  633. #endif
  634.     DIR    *dirp;
  635.     register struct dirent *dp;
  636.     int     i = 0;
  637.     struct varent *v = adrof(STRpath);
  638.     Char  **pv;
  639.     int hashval;
  640.  
  641. #ifdef FASTHASH
  642.     if (vv && vv[1]) {
  643.         hashlength = atoi(short2str(vv[1]));
  644.         if (vv[2]) {
  645.         hashwidth = atoi(short2str(vv[2]));
  646.         if ((hashwidth != sizeof(unsigned char)) && 
  647.             (hashwidth != sizeof(unsigned short)) && 
  648.             (hashwidth != sizeof(unsigned long)))
  649.             hashwidth = 0;
  650.         if (vv[3])
  651.         hashdebug = atoi(short2str(vv[3]));
  652.         }
  653.     }
  654.  
  655.     if (hashwidth == 0) {
  656.         for (pv = v->vec; *pv; pv++, hashwidth++)
  657.         continue;
  658.         if (hashwidth <= widthof(unsigned char))
  659.         hashwidth = sizeof(unsigned char);
  660.         else if (hashwidth <= widthof(unsigned short))
  661.         hashwidth = sizeof(unsigned short);
  662.     else
  663.         hashwidth = sizeof(unsigned long);
  664.     }
  665.     if (hashlength == 0) 
  666.         hashlength = hashwidth * (8*64);/* "average" files per dir in path */
  667.  
  668.     if (xhash)
  669.         xfree((ptr_t) xhash);
  670.     xhash = (unsigned long *) xcalloc((size_t) (hashlength * hashwidth), 
  671.                       (size_t) 1);
  672. #endif /* FASTHASH */
  673.  
  674.     (void) getusername(NULL);    /* flush the tilde cashe */
  675.     tw_cmd_free();
  676.     havhash = 1;
  677.     if (v == NULL)
  678.     return;
  679.     for (pv = v->vec; *pv; pv++, i++) {
  680.     if (pv[0][0] != '/')
  681.         continue;
  682.     dirp = opendir(short2str(*pv));
  683.     if (dirp == NULL)
  684.         continue;
  685. #ifdef COMMENT            /* this isn't needed.  opendir won't open
  686.                  * non-dirs */
  687.     if (fstat(dirp->dd_fd, &stb) < 0 || !S_ISDIR(stb.st_mode)) {
  688.         (void) closedir(dirp);
  689.         continue;
  690.     }
  691. #endif
  692.     while ((dp = readdir(dirp)) != NULL) {
  693.         if (dp->d_ino == 0)
  694.         continue;
  695.         if (dp->d_name[0] == '.' &&
  696.         (dp->d_name[1] == '\0' ||
  697.          (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
  698.         continue;
  699. #ifdef FASTHASH
  700.         hashval = hashname(str2short(dp->d_name));
  701.         bis(hashval, i);
  702.         if (hashdebug & 1)
  703.             xprintf("hash=%-4d dir=%-2d prog=%s\n",
  704.                 hashname(str2short(dp->d_name)), i, dp->d_name);
  705. #else /* OLD HASH */
  706.         hashval = hash(hashname(str2short(dp->d_name)), i);
  707.         bis(xhash, hashval);
  708. #endif /* FASTHASH */
  709.         /* tw_add_comm_name (dp->d_name); */
  710.     }
  711.     (void) closedir(dirp);
  712.     }
  713. }
  714.  
  715. /*ARGSUSED*/
  716. void
  717. dounhash(v, c)
  718.     Char **v;
  719.     struct command *c;
  720. {
  721.     havhash = 0;
  722. #ifdef FASTHASH
  723.     if (xhash) {
  724.        xfree((ptr_t) xhash);
  725.        xhash = NULL;
  726.     }
  727. #endif /* FASTHASH */
  728. }
  729.  
  730. #ifdef VFORK
  731. /*ARGSUSED*/
  732. void
  733. hashstat(v, c)
  734.     Char **v;
  735.     struct command *c;
  736. {
  737. #ifdef FASTHASH 
  738.    if (havhash && hashlength && hashwidth)
  739.       xprintf("%d hash buckets of %d bits each\n",
  740.           hashlength, hashwidth*8);
  741.    if (hashdebug)
  742.       xprintf("debug mask = 0x%08x\n", hashdebug);
  743. #endif /* FASTHASH */
  744.    if (hits + misses)
  745.       xprintf("%d hits, %d misses, %d%%\n",
  746.           hits, misses, 100 * hits / (hits + misses));
  747. }
  748.  
  749. #endif /* VFORK */
  750.  
  751. /*
  752.  * Hash a command name.
  753.  */
  754. static int
  755. hashname(cp)
  756.     register Char *cp;
  757. {
  758.     register long h;
  759.  
  760.     for (h = 0; *cp; cp++)
  761.     h = hash(h, *cp);
  762.     return ((int) h);
  763. }
  764.  
  765. static int
  766. iscommand(name)
  767.     Char   *name;
  768. {
  769.     register Char **pv;
  770.     register Char *sav;
  771.     register struct varent *v;
  772.     register bool slash = any(short2str(name), '/');
  773.     register int hashval, i;
  774.  
  775.     v = adrof(STRpath);
  776.     if (v == 0 || v->vec[0] == 0 || slash)
  777.     pv = justabs;
  778.     else
  779.     pv = v->vec;
  780.     sav = Strspl(STRslash, name);    /* / command name for postpending */
  781.     hashval = havhash ? hashname(name) : 0;
  782.     i = 0;
  783.     do {
  784.     if (!slash && pv[0][0] == '/' && havhash) {
  785. #ifdef FASTHASH
  786.         if (!bit(hashval, i))
  787.         goto cont;
  788. #else /* OLDHASH */
  789.         int hashval1 = hash(hashval, i);
  790.         if (!bit(xhash, hashval1))
  791.         goto cont;
  792. #endif /* FASTHASH */
  793.     }
  794.     if (pv[0][0] == 0 || eq(pv[0], STRdot)) {    /* don't make ./xxx */
  795.         if (executable(NULL, name, 0)) {
  796.         xfree((ptr_t) sav);
  797.         return i + 1;
  798.         }
  799.     }
  800.     else {
  801.         if (executable(*pv, sav, 0)) {
  802.         xfree((ptr_t) sav);
  803.         return i + 1;
  804.         }
  805.     }
  806. cont:
  807.     pv++;
  808.     i++;
  809.     } while (*pv);
  810.     xfree((ptr_t) sav);
  811.     return 0;
  812. }
  813.  
  814. /* Also by:
  815.  *  Andreas Luik <luik@isaak.isa.de>
  816.  *  I S A  GmbH - Informationssysteme fuer computerintegrierte Automatisierung
  817.  *  Azenberstr. 35
  818.  *  D-7000 Stuttgart 1
  819.  *  West-Germany
  820.  * is the executable() routine below and changes to iscommand().
  821.  * Thanks again!!
  822.  */
  823.  
  824. /*
  825.  * executable() examines the pathname obtained by concatenating dir and name
  826.  * (dir may be NULL), and returns 1 either if it is executable by us, or
  827.  * if dir_ok is set and the pathname refers to a directory.
  828.  * This is a bit kludgy, but in the name of optimization...
  829.  */
  830. int
  831. executable(dir, name, dir_ok)
  832.     Char   *dir, *name;
  833.     bool    dir_ok;
  834. {
  835.     struct stat stbuf;
  836.     Char    path[MAXPATHLEN + 1];
  837.     char   *strname;
  838.  
  839.     if (dir && *dir) {
  840.     copyn(path, dir, MAXPATHLEN);
  841.     catn(path, name, MAXPATHLEN);
  842.     strname = short2str(path);
  843.     }
  844.     else
  845.     strname = short2str(name);
  846.     
  847.     return (stat(strname, &stbuf) != -1 &&
  848.         ((dir_ok && S_ISDIR(stbuf.st_mode)) ||
  849.          (S_ISREG(stbuf.st_mode) &&
  850.     /* save time by not calling access() in the hopeless case */
  851.           (stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) &&
  852.           access(strname, X_OK) == 0)));
  853. }
  854.  
  855. void
  856. tellmewhat(lex)
  857.     struct wordent *lex;
  858. {
  859.     register int i;
  860.     register struct biltins *bptr;
  861.     register struct wordent *sp = lex->next;
  862.     bool    aliased = 0;
  863.     Char   *s0, *s1, *s2;
  864.     Char    qc;
  865.  
  866.     if (adrof1(sp->word, &aliases)) {
  867.     alias(lex);
  868.     sp = lex->next;
  869.     aliased = 1;
  870.     }
  871.  
  872.     s0 = sp->word;        /* to get the memory freeing right... */
  873.  
  874.     /* handle quoted alias hack */
  875.     if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE)
  876.     (sp->word)++;
  877.  
  878.     /* do quoting, if it hasn't been done */
  879.     s1 = s2 = sp->word;
  880.     while (*s2)
  881.     switch (*s2) {
  882.     case '\'':
  883.     case '"':
  884.         qc = *s2++;
  885.         while (*s2 && *s2 != qc)
  886.         *s1++ = *s2++ | QUOTE;
  887.         if (*s2)
  888.         s2++;
  889.         break;
  890.     case '\\':
  891.         if (*++s2)
  892.         *s1++ = *s2++ | QUOTE;
  893.         break;
  894.     default:
  895.         *s1++ = *s2++;
  896.     }
  897.     *s1 = '\0';
  898.  
  899.     for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) {
  900.     if (eq(sp->word, str2short(bptr->bname))) {
  901.         if (aliased)
  902.         prlex(lex);
  903.         xprintf("%S: shell built-in command.\n", sp->word);
  904.         flush();
  905.         sp->word = s0;    /* we save and then restore this */
  906.         return;
  907.     }
  908.     }
  909.  
  910.     if ((i = iscommand(strip(sp->word))) != 0) {
  911.     register Char **pv;
  912.     register struct varent *v;
  913.     bool    slash = any(short2str(sp->word), '/');
  914.  
  915.     v = adrof(STRpath);
  916.     if (v == 0 || v->vec[0] == 0 || slash)
  917.         pv = justabs;
  918.     else
  919.         pv = v->vec;
  920.  
  921.     while (--i)
  922.         pv++;
  923.     if (pv[0][0] == 0 || eq(pv[0], STRdot)) {
  924.         if (!slash) {
  925.         sp->word = Strspl(STRdotsl, sp->word);
  926.         prlex(lex);
  927.         xfree((ptr_t) sp->word);
  928.         }
  929.         else
  930.         prlex(lex);
  931.         sp->word = s0;    /* we save and then restore this */
  932.         return;
  933.     }
  934.     s1 = Strspl(*pv, STRslash);
  935.     sp->word = Strspl(s1, sp->word);
  936.     xfree((ptr_t) s1);
  937.     prlex(lex);
  938.     xfree((ptr_t) sp->word);
  939.     }
  940.     else {
  941.     if (aliased)
  942.         prlex(lex);
  943.     xprintf("%S: Command not found.\n", sp->word);
  944.     flush();
  945.     }
  946.     sp->word = s0;        /* we save and then restore this */
  947. }
  948.  
  949. /*
  950.  * Builtin to look at and list all places a command may be defined:
  951.  * aliases, shell builtins, and the path.
  952.  *
  953.  * Marc Horowitz <marc@mit.edu>
  954.  * MIT Student Information Processing Board
  955.  */
  956.  
  957. /*ARGSUSED*/
  958. void
  959. dowhere(v, c)
  960.     register Char **v;
  961.     struct command *c;
  962. {
  963.     for (v++; *v; v++)
  964.     (void) find_cmd(*v, 1);
  965. }
  966.  
  967. int
  968. find_cmd(cmd, prt)
  969.     Char *cmd;
  970.     int prt;
  971. {
  972.     struct varent *var;
  973.     struct biltins *bptr;
  974.     Char **pv;
  975.     Char *sv;
  976.     int hashval, i, ex, rval = 0;
  977.  
  978.     if (prt && any(short2str(cmd), '/')) {
  979.     xprintf("where: / in command makes no sense\n");
  980.     return 0;
  981.     }
  982.  
  983.     /* first, look for an alias */
  984.  
  985.     if (prt && adrof1(cmd, &aliases)) {
  986.     if ((var = adrof1(cmd, &aliases)) != NULL) {
  987.         xprintf("%S is aliased to ", cmd);
  988.         blkpr(var->vec);
  989.         xputchar('\n');
  990.         rval = 1;
  991.     }
  992.     }
  993.  
  994.     /* next, look for a shell builtin */
  995.  
  996.     for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) {
  997.     if (eq(cmd, str2short(bptr->bname))) {
  998.         rval = 1;
  999.         if (prt)
  1000.         xprintf("%S is a shell built-in\n", cmd);
  1001.         else
  1002.         return 1;
  1003.     }
  1004.     }
  1005.  
  1006.     /* last, look through the path for the command */
  1007.  
  1008.     var = adrof(STRpath);
  1009.  
  1010.     hashval = havhash ? hashname(cmd) : 0;
  1011.  
  1012.     sv = Strspl(STRslash, cmd);
  1013.  
  1014.     for (pv = var->vec, i = 0; *pv; pv++, i++) {
  1015.     if (havhash && !eq(*pv, STRdot)) {
  1016. #ifdef FASTHASH
  1017.         if (!bit(hashval, i))
  1018.         continue;
  1019. #else /* OLDHASH */
  1020.         int hashval1 = hash(hashval, i);
  1021.         if (!bit(xhash, hashval1))
  1022.         continue;
  1023. #endif /* FASTHASH */
  1024.     }
  1025.     ex = executable(*pv, sv, 0);
  1026. #ifdef FASTHASH
  1027.     if (!ex && (hashdebug & 2)) {
  1028.         xprintf("hash miss: ");
  1029.         ex = 1;    /* Force printing */
  1030.     }
  1031. #endif /* FASTHASH */
  1032.     if (ex) {
  1033.         rval = 1;
  1034.         if (prt) {
  1035.         xprintf("%S/", *pv);
  1036.         xprintf("%S\n", cmd);
  1037.         }
  1038.         else
  1039.         return 1;
  1040.     }
  1041.     }
  1042.     xfree((ptr_t) sv);
  1043.     return rval;
  1044. }
  1045.