source: trunk/third/tcsh/sh.exec.c @ 22036

Revision 22036, 28.8 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r22035, which included commits to RCS files with non-trunk default branches.
Line 
1/* $Header: /afs/dev.mit.edu/source/repository/third/tcsh/sh.exec.c,v 1.1.1.3 2005-06-03 14:35:03 ghudson 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
35RCSID("$Id: sh.exec.c,v 1.1.1.3 2005-06-03 14:35:03 ghudson 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 */
65static char *exerr;             /* Execution error message */
66static 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
88static unsigned long *xhash = NULL;
89static unsigned int hashlength = 0, uhashlength = 0;
90static unsigned int hashwidth = 0, uhashwidth = 0;
91static 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                         (1UL << (i & (widthof(t) - 1))))
97# define tbis(f, i, t)  (((t *) xhash)[(f)] |= \
98                         (1UL << (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
129static 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
138static int hits, misses;
139#endif /* VFORK */
140
141/* Dummy search path for just absolute search when no path */
142static Char *justabs[] = {STRNULL, 0};
143
144static  void    pexerr          __P((void));
145static  void    texec           __P((Char *, Char **));
146int     hashname        __P((Char *));
147static  int     iscommand       __P((Char *));
148
149void
150doexec(t, do_glob)
151    struct command *t;
152    int do_glob;
153{
154    Char *dp, **pv, **av, *sav;
155    struct varent *v;
156    int 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 */
349cont:
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
361static void
362pexerr()
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 */
385static void
386texec(sf, st)
387    Char   *sf;
388    Char **st;
389{
390    char **t;
391    char *f;
392    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|O_LARGEFILE)) != -1) {
442            int nread;
443#ifdef O_TEXT
444            setmode(fd, O_TEXT);
445#endif
446            if ((nread = read(fd, (char *) pref, 2)) == 2) {
447                if (!isprint((unsigned char)pref[0]) &&
448                    (pref[0] != '\n' && pref[0] != '\t')) {
449                    (void) close(fd);
450                    /*
451                     * We *know* what ENOEXEC means.
452                     */
453                    stderror(ERR_ARCH, f, strerror(errno));
454                }
455            }
456            else if (nread < 0 && errno != EINTR) {
457#ifdef convex
458                /* need to print error incase the file is migrated */
459                stderror(ERR_SYSTEM, f, strerror(errno));
460#endif
461            }
462#ifdef _PATH_BSHELL
463            else {
464                pref[0] = '#';
465                pref[1] = '\0';
466            }
467#endif
468        }
469#ifdef HASHBANG
470        if (fd == -1 ||
471            pref[0] != '#' || pref[1] != '!' || hashbang(fd, &vp) == -1) {
472#endif /* HASHBANG */
473        /*
474         * If there is an alias for shell, then put the words of the alias in
475         * front of the argument list replacing the command name. Note no
476         * interpretation of the words at this point.
477         */
478            v = adrof1(STRshell, &aliases);
479            if (v == NULL || v->vec == NULL) {
480                vp = lastsh;
481                vp[0] = adrof(STRshell) ? varval(STRshell) : STR_SHELLPATH;
482                vp[1] = NULL;
483#ifdef _PATH_BSHELL
484                if (fd != -1
485# ifndef ISC    /* Compatible with ISC's /bin/csh */
486                    && pref[0] != '#'
487# endif /* ISC */
488                    )
489                    vp[0] = STR_BSHELL;
490#endif
491                vp = saveblk(vp);
492            }
493            else
494                vp = saveblk(v->vec);
495#ifdef HASHBANG
496        }
497#endif /* HASHBANG */
498        if (fd != -1)
499            (void) close(fd);
500
501        st0 = st[0];
502        st[0] = sf;
503        ost = st;
504        st = blkspl(vp, st);    /* Splice up the new arglst */
505        ost[0] = st0;
506        sf = *st;
507        /* The order for the conversions is significant */
508        t = short2blk(st);
509        f = short2str(sf);
510        xfree((ptr_t) st);
511        blkfree((Char **) vp);
512#ifdef VFORK
513        Vt = t;
514#endif /* VFORK */
515#ifdef ISC_POSIX_EXEC_BUG
516        __setostype(0);         /* "0" is "__OS_SYSV" in <sys/user.h> */
517#endif /* ISC_POSIX_EXEC_BUG */
518        (void) execv(f, t);
519#ifdef ISC_POSIX_EXEC_BUG
520        __setostype(1);         /* "1" is "__OS_POSIX" in <sys/user.h> */
521#endif /* ISC_POSIX_EXEC_BUG */
522#ifdef VFORK
523        Vt = 0;
524#endif /* VFORK */
525        blkfree((Char **) t);
526        /* The sky is falling, the sky is falling! */
527        stderror(ERR_SYSTEM, f, strerror(errno));
528        break;
529
530    case ENOMEM:
531        stderror(ERR_SYSTEM, f, strerror(errno));
532        break;
533
534#ifdef _IBMR2
535    case 0:                     /* execv fails and returns 0! */
536#endif /* _IBMR2 */
537    case ENOENT:
538        break;
539
540    default:
541        if (exerr == 0) {
542            exerr = strerror(errno);
543            if (expath)
544                xfree((ptr_t) expath);
545            expath = Strsave(sf);
546#ifdef VFORK
547            Vexpath = expath;
548#endif /* VFORK */
549        }
550        break;
551    }
552}
553
554/*ARGSUSED*/
555void
556execash(t, kp)
557    Char  **t;
558    struct command *kp;
559{
560    int     saveIN, saveOUT, saveDIAG, saveSTD;
561    int     oSHIN;
562    int     oSHOUT;
563    int     oSHDIAG;
564    int     oOLDSTD;
565    jmp_buf_t osetexit;
566    int     my_reenter;
567    int     odidfds;
568#ifndef CLOSE_ON_EXEC
569    int     odidcch;
570#endif /* CLOSE_ON_EXEC */
571    signalfun_t osigint, osigquit, osigterm;
572
573    USE(t);
574    if (chkstop == 0 && setintr)
575        panystop(0);
576    /*
577     * Hmm, we don't really want to do that now because we might
578     * fail, but what is the choice
579     */
580    rechist(NULL, adrof(STRsavehist) != NULL);
581
582
583    osigint  = signal(SIGINT, parintr);
584    osigquit = signal(SIGQUIT, parintr);
585    osigterm = signal(SIGTERM, parterm);
586
587    odidfds = didfds;
588#ifndef CLOSE_ON_EXEC
589    odidcch = didcch;
590#endif /* CLOSE_ON_EXEC */
591    oSHIN = SHIN;
592    oSHOUT = SHOUT;
593    oSHDIAG = SHDIAG;
594    oOLDSTD = OLDSTD;
595
596    (void)close_on_exec (saveIN = dcopy(SHIN, -1), 1);
597    (void)close_on_exec (saveOUT = dcopy(SHOUT, -1), 1);
598    (void)close_on_exec (saveDIAG = dcopy(SHDIAG, -1), 1);
599    (void)close_on_exec (saveSTD = dcopy(OLDSTD, -1), 1);
600       
601    lshift(kp->t_dcom, 1);
602
603    getexit(osetexit);
604
605    /* PWP: setjmp/longjmp bugfix for optimizing compilers */
606#ifdef cray
607    my_reenter = 1;             /* assume non-zero return val */
608    if (setexit() == 0) {
609        my_reenter = 0;         /* Oh well, we were wrong */
610#else /* !cray */
611    if ((my_reenter = setexit()) == 0) {
612#endif /* cray */
613        (void)close_on_exec (SHIN = dcopy(0, -1), 1);
614        (void)close_on_exec (SHOUT = dcopy(1, -1), 1);
615        (void)close_on_exec (SHDIAG = dcopy(2, -1), 1);
616#ifndef CLOSE_ON_EXEC
617        didcch = 0;
618#endif /* CLOSE_ON_EXEC */
619        didfds = 0;
620        /*
621         * Decrement the shell level
622         */
623        shlvl(-1);
624#ifdef WINNT_NATIVE
625        __nt_really_exec=1;
626#endif /* WINNT_NATIVE */
627        doexec(kp, 1);
628    }
629
630    (void) sigset(SIGINT, osigint);
631    (void) sigset(SIGQUIT, osigquit);
632    (void) sigset(SIGTERM, osigterm);
633
634    doneinp = 0;
635#ifndef CLOSE_ON_EXEC
636    didcch = odidcch;
637#endif /* CLOSE_ON_EXEC */
638    didfds = odidfds;
639    (void) close(SHIN);
640    (void) close(SHOUT);
641    (void) close(SHDIAG);
642    (void) close(OLDSTD);
643    (void)close_on_exec(SHIN = dmove(saveIN, oSHIN), 1);
644    (void)close_on_exec(SHOUT = dmove(saveOUT, oSHOUT), 1);
645    (void)close_on_exec(SHDIAG = dmove(saveDIAG, oSHDIAG), 1);
646    (void)close_on_exec(OLDSTD = dmove(saveSTD, oOLDSTD), 1);
647
648    resexit(osetexit);
649    if (my_reenter)
650        stderror(ERR_SILENT);
651}
652
653void
654xechoit(t)
655    Char  **t;
656{
657    if (adrof(STRecho)) {
658        int odidfds = didfds;
659        flush();
660        haderr = 1;
661        didfds = 0;
662        blkpr(t), xputchar('\n');
663        flush();
664        didfds = odidfds;
665        haderr = 0;
666    }
667}
668
669/*ARGSUSED*/
670void
671dohash(vv, c)
672    Char **vv;
673    struct command *c;
674{
675#ifdef COMMENT
676    struct stat stb;
677#endif
678    DIR    *dirp;
679    struct dirent *dp;
680    int     i = 0;
681    struct varent *v = adrof(STRpath);
682    Char  **pv;
683    int hashval;
684#ifdef WINNT_NATIVE
685    int is_windir; /* check if it is the windows directory */
686    USE(hashval);
687#endif /* WINNT_NATIVE */
688
689    USE(c);
690#ifdef FASTHASH
691    if (vv && vv[1]) {
692        uhashlength = atoi(short2str(vv[1]));
693        if (vv[2]) {
694            uhashwidth = atoi(short2str(vv[2]));
695            if ((uhashwidth != sizeof(unsigned char)) &&
696                (uhashwidth != sizeof(unsigned short)) &&
697                (uhashwidth != sizeof(unsigned long)))
698                uhashwidth = 0;
699            if (vv[3])
700                hashdebug = atoi(short2str(vv[3]));
701        }
702    }
703
704    if (uhashwidth)
705        hashwidth = uhashwidth;
706    else {
707        hashwidth = 0;
708        if (v == NULL)
709            return;
710        for (pv = v->vec; pv && *pv; pv++, hashwidth++)
711            continue;
712        if (hashwidth <= widthof(unsigned char))
713            hashwidth = sizeof(unsigned char);
714        else if (hashwidth <= widthof(unsigned short))
715            hashwidth = sizeof(unsigned short);
716        else if (hashwidth <= widthof(unsigned int))
717            hashwidth = sizeof(unsigned int);
718        else
719            hashwidth = sizeof(unsigned long);
720    }
721
722    if (uhashlength)
723        hashlength = uhashlength;
724    else
725        hashlength = hashwidth * (8*64);/* "average" files per dir in path */
726   
727    if (xhash)
728        xfree((ptr_t) xhash);
729    xhash = (unsigned long *) xcalloc((size_t) (hashlength * hashwidth),
730                                      (size_t) 1);
731#endif /* FASTHASH */
732
733    (void) getusername(NULL);   /* flush the tilde cashe */
734    tw_cmd_free();
735    havhash = 1;
736    if (v == NULL)
737        return;
738    for (pv = v->vec; pv && *pv; pv++, i++) {
739        if (!ABSOLUTEP(pv[0]))
740            continue;
741        dirp = opendir(short2str(*pv));
742        if (dirp == NULL)
743            continue;
744#ifdef COMMENT                  /* this isn't needed.  opendir won't open
745                                 * non-dirs */
746        if (fstat(dirp->dd_fd, &stb) < 0 || !S_ISDIR(stb.st_mode)) {
747            (void) closedir(dirp);
748            continue;
749        }
750#endif
751#ifdef WINNT_NATIVE
752        is_windir = nt_check_if_windir(short2str(*pv));
753#endif /* WINNT_NATIVE */
754        while ((dp = readdir(dirp)) != NULL) {
755            if (dp->d_ino == 0)
756                continue;
757            if (dp->d_name[0] == '.' &&
758                (dp->d_name[1] == '\0' ||
759                 (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
760                continue;
761#ifdef WINNT_NATIVE
762            nt_check_name_and_hash(is_windir, dp->d_name, i);
763#else /* !WINNT_NATIVE*/
764#if defined(_UWIN) || defined(__CYGWIN__)
765            /* Turn foo.{exe,com,bat} into foo since UWIN's readdir returns
766             * the file with the .exe, .com, .bat extension
767             */
768            {
769                size_t  ext = strlen(dp->d_name) - 4;
770                if ((ext > 0) && (strcasecmp(&dp->d_name[ext], ".exe") == 0 ||
771                                  strcasecmp(&dp->d_name[ext], ".bat") == 0 ||
772                                  strcasecmp(&dp->d_name[ext], ".com") == 0))
773                    {
774                        dp->d_name[ext] = '\0';
775#if defined(__CYGWIN__)
776                        strlwr(dp->d_name);
777#endif /* __CYGWIN__ */
778                    }
779            }
780#endif /* _UWIN || __CYGWIN__ */
781# ifdef FASTHASH
782            hashval = hashname(str2short(dp->d_name));
783            bis(hashval, i);
784            if (hashdebug & 1)
785                xprintf(CGETS(13, 1, "hash=%-4d dir=%-2d prog=%s\n"),
786                        hashname(str2short(dp->d_name)), i, dp->d_name);
787# else /* OLD HASH */
788            hashval = hash(hashname(str2short(dp->d_name)), i);
789            bis(xhash, hashval);
790# endif /* FASTHASH */
791            /* tw_add_comm_name (dp->d_name); */
792#endif /* WINNT_NATIVE */
793        }
794        (void) closedir(dirp);
795    }
796}
797
798/*ARGSUSED*/
799void
800dounhash(v, c)
801    Char **v;
802    struct command *c;
803{
804    USE(c);
805    USE(v);
806    havhash = 0;
807#ifdef FASTHASH
808    if (xhash) {
809       xfree((ptr_t) xhash);
810       xhash = NULL;
811    }
812#endif /* FASTHASH */
813}
814
815/*ARGSUSED*/
816void
817hashstat(v, c)
818    Char **v;
819    struct command *c;
820{
821    USE(c);
822    USE(v);
823#ifdef FASTHASH
824   if (havhash && hashlength && hashwidth)
825      xprintf(CGETS(13, 2, "%d hash buckets of %d bits each\n"),
826              hashlength, hashwidth*8);
827   if (hashdebug)
828      xprintf(CGETS(13, 3, "debug mask = 0x%08x\n"), hashdebug);
829#endif /* FASTHASH */
830#ifdef VFORK
831   if (hits + misses)
832      xprintf(CGETS(13, 4, "%d hits, %d misses, %d%%\n"),
833              hits, misses, 100 * hits / (hits + misses));
834#endif
835}
836
837
838/*
839 * Hash a command name.
840 */
841int
842hashname(cp)
843    Char *cp;
844{
845    unsigned long h;
846
847    for (h = 0; *cp; cp++)
848        h = hash(h, *cp);
849    return ((int) h);
850}
851
852static int
853iscommand(name)
854    Char   *name;
855{
856    Char **pv;
857    Char *sav;
858    struct varent *v;
859    int slash = any(short2str(name), '/');
860    int hashval, i;
861
862    v = adrof(STRpath);
863    if (v == NULL || v->vec == NULL || v->vec[0] == NULL || slash)
864        pv = justabs;
865    else
866        pv = v->vec;
867    sav = Strspl(STRslash, name);       /* / command name for postpending */
868    hashval = havhash ? hashname(name) : 0;
869    i = 0;
870    do {
871        if (!slash && ABSOLUTEP(pv[0]) && havhash) {
872#ifdef FASTHASH
873            if (!bit(hashval, i))
874                goto cont;
875#else /* OLDHASH */
876            int hashval1 = hash(hashval, i);
877            if (!bit(xhash, hashval1))
878                goto cont;
879#endif /* FASTHASH */
880        }
881        if (pv[0][0] == 0 || eq(pv[0], STRdot)) {       /* don't make ./xxx */
882            if (executable(NULL, name, 0)) {
883                xfree((ptr_t) sav);
884                return i + 1;
885            }
886        }
887        else {
888            if (executable(*pv, sav, 0)) {
889                xfree((ptr_t) sav);
890                return i + 1;
891            }
892        }
893cont:
894        pv++;
895        i++;
896    } while (*pv);
897    xfree((ptr_t) sav);
898    return 0;
899}
900
901/* Also by:
902 *  Andreas Luik <luik@isaak.isa.de>
903 *  I S A  GmbH - Informationssysteme fuer computerintegrierte Automatisierung
904 *  Azenberstr. 35
905 *  D-7000 Stuttgart 1
906 *  West-Germany
907 * is the executable() routine below and changes to iscommand().
908 * Thanks again!!
909 */
910
911#ifndef WINNT_NATIVE
912/*
913 * executable() examines the pathname obtained by concatenating dir and name
914 * (dir may be NULL), and returns 1 either if it is executable by us, or
915 * if dir_ok is set and the pathname refers to a directory.
916 * This is a bit kludgy, but in the name of optimization...
917 */
918int
919executable(dir, name, dir_ok)
920    Char   *dir, *name;
921    int    dir_ok;
922{
923    struct stat stbuf;
924    Char    path[MAXPATHLEN + 1];
925    char   *strname;
926    (void) memset(path, 0, sizeof(path));
927
928    if (dir && *dir) {
929        copyn(path, dir, MAXPATHLEN);
930        catn(path, name, MAXPATHLEN);
931        strname = short2str(path);
932    }
933    else
934        strname = short2str(name);
935   
936    return (stat(strname, &stbuf) != -1 &&
937            ((dir_ok && S_ISDIR(stbuf.st_mode)) ||
938             (S_ISREG(stbuf.st_mode) &&
939    /* save time by not calling access() in the hopeless case */
940              (stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) &&
941              access(strname, X_OK) == 0
942        )));
943}
944#endif /*!WINNT_NATIVE*/
945
946int
947tellmewhat(lexp, str)
948    struct wordent *lexp;
949    Char *str;
950{
951    int i;
952    struct biltins *bptr;
953    struct wordent *sp = lexp->next;
954    int    aliased = 0, found;
955    Char   *s0, *s1, *s2, *cmd;
956    Char    qc;
957
958    if (adrof1(sp->word, &aliases)) {
959        alias(lexp);
960        sp = lexp->next;
961        aliased = 1;
962    }
963
964    s0 = sp->word;              /* to get the memory freeing right... */
965
966    /* handle quoted alias hack */
967    if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE)
968        (sp->word)++;
969
970    /* do quoting, if it hasn't been done */
971    s1 = s2 = sp->word;
972    while (*s2)
973        switch (*s2) {
974        case '\'':
975        case '"':
976            qc = *s2++;
977            while (*s2 && *s2 != qc)
978                *s1++ = *s2++ | QUOTE;
979            if (*s2)
980                s2++;
981            break;
982        case '\\':
983            if (*++s2)
984                *s1++ = *s2++ | QUOTE;
985            break;
986        default:
987            *s1++ = *s2++;
988        }
989    *s1 = '\0';
990
991    for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) {
992        if (eq(sp->word, str2short(bptr->bname))) {
993            if (str == NULL) {
994                if (aliased)
995                    prlex(lexp);
996                xprintf(CGETS(13, 5, "%S: shell built-in command.\n"),
997                              sp->word);
998                flush();
999            }
1000            else
1001                (void) Strcpy(str, sp->word);
1002            sp->word = s0;      /* we save and then restore this */
1003            return TRUE;
1004        }
1005    }
1006#ifdef WINNT_NATIVE
1007    for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++) {
1008        if (eq(sp->word, str2short(bptr->bname))) {
1009            if (str == NULL) {
1010                if (aliased)
1011                    prlex(lexp);
1012                xprintf(CGETS(13, 5, "%S: shell built-in command.\n"),
1013                              sp->word);
1014                flush();
1015            }
1016            else
1017                (void) Strcpy(str, sp->word);
1018            sp->word = s0;      /* we save and then restore this */
1019            return TRUE;
1020        }
1021    }
1022#endif /* WINNT_NATIVE*/
1023
1024    sp->word = cmd = globone(sp->word, G_IGNORE);
1025
1026    if ((i = iscommand(sp->word)) != 0) {
1027        Char **pv;
1028        struct varent *v;
1029        int    slash = any(short2str(sp->word), '/');
1030
1031        v = adrof(STRpath);
1032        if (v == NULL || v->vec == NULL || v->vec[0] == NULL || slash)
1033            pv = justabs;
1034        else
1035            pv = v->vec;
1036
1037        while (--i)
1038            pv++;
1039        if (pv[0][0] == 0 || eq(pv[0], STRdot)) {
1040            if (!slash) {
1041                sp->word = Strspl(STRdotsl, sp->word);
1042                prlex(lexp);
1043                xfree((ptr_t) sp->word);
1044            }
1045            else
1046                prlex(lexp);
1047        }
1048        else {
1049            s1 = Strspl(*pv, STRslash);
1050            sp->word = Strspl(s1, sp->word);
1051            xfree((ptr_t) s1);
1052            if (str == NULL)
1053                prlex(lexp);
1054            else
1055                (void) Strcpy(str, sp->word);
1056            xfree((ptr_t) sp->word);
1057        }
1058        found = 1;
1059    }
1060    else {
1061        if (str == NULL) {
1062            if (aliased)
1063                prlex(lexp);
1064            xprintf(CGETS(13, 6, "%S: Command not found.\n"), sp->word);
1065            flush();
1066        }
1067        else
1068            (void) Strcpy(str, sp->word);
1069        found = 0;
1070    }
1071    sp->word = s0;              /* we save and then restore this */
1072    xfree((ptr_t) cmd);
1073    return found;
1074}
1075
1076/*
1077 * Builtin to look at and list all places a command may be defined:
1078 * aliases, shell builtins, and the path.
1079 *
1080 * Marc Horowitz <marc@mit.edu>
1081 * MIT Student Information Processing Board
1082 */
1083
1084/*ARGSUSED*/
1085void
1086dowhere(v, c)
1087    Char **v;
1088    struct command *c;
1089{
1090    int found = 1;
1091    USE(c);
1092    for (v++; *v; v++)
1093        found &= find_cmd(*v, 1);
1094    /* Make status nonzero if any command is not found. */
1095    if (!found)
1096      set(STRstatus, Strsave(STR1), VAR_READWRITE);
1097}
1098
1099int
1100find_cmd(cmd, prt)
1101    Char *cmd;
1102    int prt;
1103{
1104    struct varent *var;
1105    struct biltins *bptr;
1106    Char **pv;
1107    Char *sv;
1108    int hashval, i, ex, rval = 0;
1109
1110    if (prt && any(short2str(cmd), '/')) {
1111        xprintf(CGETS(13, 7, "where: / in command makes no sense\n"));
1112        return rval;
1113    }
1114
1115    /* first, look for an alias */
1116
1117    if (prt && adrof1(cmd, &aliases)) {
1118        if ((var = adrof1(cmd, &aliases)) != NULL) {
1119            xprintf(CGETS(13, 8, "%S is aliased to "), cmd);
1120            if (var->vec != NULL)
1121                blkpr(var->vec);
1122            xputchar('\n');
1123            rval = 1;
1124        }
1125    }
1126
1127    /* next, look for a shell builtin */
1128
1129    for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) {
1130        if (eq(cmd, str2short(bptr->bname))) {
1131            rval = 1;
1132            if (prt)
1133                xprintf(CGETS(13, 9, "%S is a shell built-in\n"), cmd);
1134            else
1135                return rval;
1136        }
1137    }
1138#ifdef WINNT_NATIVE
1139    for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++) {
1140        if (eq(cmd, str2short(bptr->bname))) {
1141            rval = 1;
1142            if (prt)
1143                xprintf(CGETS(13, 9, "%S is a shell built-in\n"), cmd);
1144            else
1145                return rval;
1146        }
1147    }
1148#endif /* WINNT_NATIVE*/
1149
1150    /* last, look through the path for the command */
1151
1152    if ((var = adrof(STRpath)) == NULL)
1153        return rval;
1154
1155    hashval = havhash ? hashname(cmd) : 0;
1156
1157    sv = Strspl(STRslash, cmd);
1158
1159    for (pv = var->vec, i = 0; pv && *pv; pv++, i++) {
1160        if (havhash && !eq(*pv, STRdot)) {
1161#ifdef FASTHASH
1162            if (!bit(hashval, i))
1163                continue;
1164#else /* OLDHASH */
1165            int hashval1 = hash(hashval, i);
1166            if (!bit(xhash, hashval1))
1167                continue;
1168#endif /* FASTHASH */
1169        }
1170        ex = executable(*pv, sv, 0);
1171#ifdef FASTHASH
1172        if (!ex && (hashdebug & 2)) {
1173            xprintf(CGETS(13, 10, "hash miss: "));
1174            ex = 1;     /* Force printing */
1175        }
1176#endif /* FASTHASH */
1177        if (ex) {
1178            rval = 1;
1179            if (prt) {
1180                xprintf("%S/", *pv);
1181                xprintf("%S\n", cmd);
1182            }
1183            else
1184                return rval;
1185        }
1186    }
1187    xfree((ptr_t) sv);
1188    return rval;
1189}
1190#ifdef WINNT_NATIVE
1191int hashval_extern(cp)
1192        Char *cp;
1193{
1194        return havhash?hashname(cp):0;
1195}
1196int bit_extern(val,i)
1197        int val;
1198        int i;
1199{
1200        return bit(val,i);
1201}
1202void bis_extern(val,i)
1203        int val;
1204        int i;
1205{
1206        bis(val,i);
1207}
1208#endif /* WINNT_NATIVE */
1209
Note: See TracBrowser for help on using the repository browser.