Home | History | Annotate | Line # | Download | only in csh
exec.c revision 1.26.4.1
      1  1.26.4.1      matt /* $NetBSD: exec.c,v 1.26.4.1 2008/01/09 01:20:00 matt Exp $ */
      2       1.6       cgd 
      3       1.1       cgd /*-
      4       1.5   mycroft  * Copyright (c) 1980, 1991, 1993
      5       1.5   mycroft  *	The Regents of the University of California.  All rights reserved.
      6       1.1       cgd  *
      7       1.1       cgd  * Redistribution and use in source and binary forms, with or without
      8       1.1       cgd  * modification, are permitted provided that the following conditions
      9       1.1       cgd  * are met:
     10       1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     11       1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     12       1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     13       1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     14       1.1       cgd  *    documentation and/or other materials provided with the distribution.
     15      1.21       agc  * 3. Neither the name of the University nor the names of its contributors
     16       1.1       cgd  *    may be used to endorse or promote products derived from this software
     17       1.1       cgd  *    without specific prior written permission.
     18       1.1       cgd  *
     19       1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20       1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21       1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22       1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23       1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24       1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25       1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26       1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27       1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28       1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29       1.1       cgd  * SUCH DAMAGE.
     30       1.1       cgd  */
     31       1.1       cgd 
     32      1.11  christos #include <sys/cdefs.h>
     33       1.1       cgd #ifndef lint
     34       1.6       cgd #if 0
     35       1.8  christos static char sccsid[] = "@(#)exec.c	8.3 (Berkeley) 5/23/95";
     36       1.6       cgd #else
     37  1.26.4.1      matt __RCSID("$NetBSD: exec.c,v 1.26.4.1 2008/01/09 01:20:00 matt Exp $");
     38       1.6       cgd #endif
     39       1.1       cgd #endif /* not lint */
     40       1.1       cgd 
     41      1.16       wiz #include <sys/param.h>
     42      1.16       wiz #include <sys/stat.h>
     43       1.1       cgd #include <sys/types.h>
     44      1.16       wiz 
     45       1.1       cgd #include <dirent.h>
     46      1.16       wiz #include <errno.h>
     47       1.1       cgd #include <fcntl.h>
     48      1.19       wiz #include <stdarg.h>
     49       1.1       cgd #include <stdlib.h>
     50       1.1       cgd #include <string.h>
     51       1.1       cgd #include <unistd.h>
     52       1.1       cgd 
     53       1.1       cgd #include "csh.h"
     54       1.1       cgd #include "extern.h"
     55       1.1       cgd 
     56       1.1       cgd /*
     57       1.1       cgd  * System level search and execute of a command.  We look in each directory
     58       1.1       cgd  * for the specified command name.  If the name contains a '/' then we
     59       1.1       cgd  * execute only the full path name.  If there is no search path then we
     60       1.1       cgd  * execute only full path names.
     61       1.1       cgd  */
     62       1.1       cgd extern char **environ;
     63       1.1       cgd 
     64       1.1       cgd /*
     65       1.1       cgd  * As we search for the command we note the first non-trivial error
     66       1.1       cgd  * message for presentation to the user.  This allows us often
     67       1.1       cgd  * to show that a file has the wrong mode/no access when the file
     68       1.1       cgd  * is not in the last component of the search path, so we must
     69       1.1       cgd  * go on after first detecting the error.
     70       1.1       cgd  */
     71      1.12   mycroft static const char *exerr;	/* Execution error message */
     72       1.1       cgd static Char *expath;		/* Path for exerr */
     73       1.1       cgd 
     74       1.1       cgd /*
     75       1.1       cgd  * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used
     76       1.1       cgd  * to hash execs.  If it is allocated (havhash true), then to tell
     77       1.1       cgd  * whether ``name'' is (possibly) present in the i'th component
     78       1.1       cgd  * of the variable path, you look at the bit in xhash indexed by
     79       1.1       cgd  * hash(hashname("name"), i).  This is setup automatically
     80       1.1       cgd  * after .login is executed, and recomputed whenever ``path'' is
     81       1.1       cgd  * changed.
     82       1.1       cgd  * The two part hash function is designed to let texec() call the
     83       1.1       cgd  * more expensive hashname() only once and the simple hash() several
     84       1.1       cgd  * times (once for each path component checked).
     85       1.1       cgd  * Byte size is assumed to be 8.
     86       1.1       cgd  */
     87      1.16       wiz #define	HSHSIZ 8192	/* 1k bytes */
     88      1.16       wiz #define HSHMASK	(HSHSIZ - 1)
     89      1.16       wiz #define HSHMUL 243
     90       1.1       cgd static char xhash[HSHSIZ / 8];
     91       1.1       cgd 
     92      1.16       wiz #define hash(a, b) (((a) * HSHMUL + (b)) & HSHMASK)
     93      1.16       wiz #define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7))	/* bit test */
     94      1.16       wiz #define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7))	/* bit set */
     95       1.1       cgd static int hits, misses;
     96       1.1       cgd 
     97       1.1       cgd /* Dummy search path for just absolute search when no path */
     98       1.1       cgd static Char *justabs[] = {STRNULL, 0};
     99       1.1       cgd 
    100  1.26.4.1      matt static void pexerr(void) __dead;
    101      1.16       wiz static void texec(Char *, Char **);
    102      1.16       wiz static int hashname(Char *);
    103      1.16       wiz static int tellmewhat(struct wordent *, Char *);
    104      1.26  christos static int executable(Char *, Char *, int);
    105      1.16       wiz static int iscommand(Char *);
    106       1.1       cgd 
    107       1.1       cgd void
    108       1.5   mycroft /*ARGSUSED*/
    109      1.16       wiz doexec(Char **v, struct command *t)
    110       1.1       cgd {
    111      1.10       tls     struct varent *pathv;
    112      1.16       wiz     Char *blk[2], **av, *dp, **pv, *sav;
    113      1.16       wiz     int i, hashval, hashval1;
    114      1.20    kleink     sigset_t nsigset;
    115      1.26  christos     int slash;
    116       1.1       cgd 
    117      1.16       wiz     hashval = 0;
    118       1.1       cgd     /*
    119       1.1       cgd      * Glob the command name. We will search $path even if this does something,
    120       1.1       cgd      * as in sh but not in csh.  One special case: if there is no PATH, then we
    121       1.1       cgd      * execute only commands which start with '/'.
    122       1.1       cgd      */
    123       1.1       cgd     blk[0] = t->t_dcom[0];
    124       1.1       cgd     blk[1] = 0;
    125       1.1       cgd     gflag = 0, tglob(blk);
    126       1.1       cgd     if (gflag) {
    127       1.1       cgd 	pv = globall(blk);
    128       1.1       cgd 	if (pv == 0) {
    129       1.5   mycroft 	    setname(vis_str(blk[0]));
    130       1.1       cgd 	    stderror(ERR_NAME | ERR_NOMATCH);
    131       1.1       cgd 	}
    132       1.1       cgd 	gargv = 0;
    133       1.1       cgd     }
    134       1.1       cgd     else
    135       1.1       cgd 	pv = saveblk(blk);
    136       1.1       cgd 
    137       1.1       cgd     trim(pv);
    138       1.1       cgd 
    139       1.1       cgd     exerr = 0;
    140       1.1       cgd     expath = Strsave(pv[0]);
    141       1.1       cgd     Vexpath = expath;
    142       1.1       cgd 
    143       1.5   mycroft     pathv = adrof(STRpath);
    144       1.5   mycroft     if (pathv == 0 && expath[0] != '/') {
    145       1.1       cgd 	blkfree(pv);
    146       1.1       cgd 	pexerr();
    147       1.1       cgd     }
    148       1.1       cgd     slash = any(short2str(expath), '/');
    149       1.1       cgd 
    150       1.1       cgd     /*
    151       1.1       cgd      * Glob the argument list, if necessary. Otherwise trim off the quote bits.
    152       1.1       cgd      */
    153       1.1       cgd     gflag = 0;
    154       1.1       cgd     av = &t->t_dcom[1];
    155       1.1       cgd     tglob(av);
    156       1.1       cgd     if (gflag) {
    157       1.1       cgd 	av = globall(av);
    158       1.1       cgd 	if (av == 0) {
    159       1.1       cgd 	    blkfree(pv);
    160       1.5   mycroft 	    setname(vis_str(expath));
    161       1.1       cgd 	    stderror(ERR_NAME | ERR_NOMATCH);
    162       1.1       cgd 	}
    163       1.1       cgd 	gargv = 0;
    164       1.1       cgd     }
    165       1.1       cgd     else
    166       1.1       cgd 	av = saveblk(av);
    167       1.1       cgd 
    168       1.1       cgd     blkfree(t->t_dcom);
    169       1.1       cgd     t->t_dcom = blkspl(pv, av);
    170       1.1       cgd     xfree((ptr_t) pv);
    171       1.1       cgd     xfree((ptr_t) av);
    172       1.1       cgd     av = t->t_dcom;
    173       1.1       cgd     trim(av);
    174       1.1       cgd 
    175       1.1       cgd     if (*av == NULL || **av == '\0')
    176       1.1       cgd 	pexerr();
    177       1.1       cgd 
    178       1.1       cgd     xechoit(av);		/* Echo command if -x */
    179       1.1       cgd     /*
    180       1.1       cgd      * Since all internal file descriptors are set to close on exec, we don't
    181       1.1       cgd      * need to close them explicitly here.  Just reorient ourselves for error
    182       1.1       cgd      * messages.
    183       1.1       cgd      */
    184       1.1       cgd     SHIN = 0;
    185       1.1       cgd     SHOUT = 1;
    186       1.5   mycroft     SHERR = 2;
    187       1.1       cgd     OLDSTD = 0;
    188       1.1       cgd     /*
    189       1.1       cgd      * We must do this AFTER any possible forking (like `foo` in glob) so that
    190       1.1       cgd      * this shell can still do subprocesses.
    191       1.1       cgd      */
    192      1.20    kleink     sigemptyset(&nsigset);
    193      1.20    kleink     (void)sigprocmask(SIG_SETMASK, &nsigset, NULL);
    194       1.1       cgd     /*
    195       1.1       cgd      * If no path, no words in path, or a / in the filename then restrict the
    196       1.1       cgd      * command search.
    197       1.1       cgd      */
    198       1.5   mycroft     if (pathv == 0 || pathv->vec[0] == 0 || slash)
    199       1.1       cgd 	pv = justabs;
    200       1.1       cgd     else
    201       1.5   mycroft 	pv = pathv->vec;
    202      1.16       wiz     sav = Strspl(STRslash, *av); 	/* / command name for postpending */
    203       1.1       cgd     Vsav = sav;
    204       1.1       cgd     if (havhash)
    205       1.1       cgd 	hashval = hashname(*av);
    206       1.1       cgd     i = 0;
    207       1.1       cgd     hits++;
    208       1.1       cgd     do {
    209       1.1       cgd 	/*
    210       1.1       cgd 	 * Try to save time by looking at the hash table for where this command
    211       1.1       cgd 	 * could be.  If we are doing delayed hashing, then we put the names in
    212       1.1       cgd 	 * one at a time, as the user enters them.  This is kinda like Korn
    213       1.1       cgd 	 * Shell's "tracked aliases".
    214       1.1       cgd 	 */
    215       1.1       cgd 	if (!slash && pv[0][0] == '/' && havhash) {
    216       1.1       cgd 	    hashval1 = hash(hashval, i);
    217       1.1       cgd 	    if (!bit(xhash, hashval1))
    218       1.1       cgd 		goto cont;
    219       1.1       cgd 	}
    220       1.1       cgd 	if (pv[0][0] == 0 || eq(pv[0], STRdot))	/* don't make ./xxx */
    221       1.1       cgd 	    texec(*av, av);
    222       1.1       cgd 	else {
    223       1.1       cgd 	    dp = Strspl(*pv, sav);
    224       1.1       cgd 	    Vdp = dp;
    225       1.1       cgd 	    texec(dp, av);
    226       1.1       cgd 	    Vdp = 0;
    227      1.16       wiz 	    xfree((ptr_t)dp);
    228       1.1       cgd 	}
    229       1.1       cgd 	misses++;
    230       1.1       cgd cont:
    231       1.1       cgd 	pv++;
    232       1.1       cgd 	i++;
    233       1.1       cgd     } while (*pv);
    234       1.1       cgd     hits--;
    235       1.1       cgd     Vsav = 0;
    236      1.16       wiz     xfree((ptr_t)sav);
    237       1.1       cgd     pexerr();
    238      1.15   mycroft     /* NOTREACHED */
    239       1.1       cgd }
    240       1.1       cgd 
    241       1.1       cgd static void
    242      1.16       wiz pexerr(void)
    243       1.1       cgd {
    244       1.1       cgd     /* Couldn't find the damn thing */
    245       1.1       cgd     if (expath) {
    246       1.5   mycroft 	setname(vis_str(expath));
    247       1.1       cgd 	Vexpath = 0;
    248      1.16       wiz 	xfree((ptr_t)expath);
    249       1.1       cgd 	expath = 0;
    250       1.1       cgd     }
    251       1.1       cgd     else
    252       1.1       cgd 	setname("");
    253       1.1       cgd     if (exerr)
    254       1.1       cgd 	stderror(ERR_NAME | ERR_STRING, exerr);
    255      1.13   mycroft     else
    256      1.13   mycroft 	stderror(ERR_NAME | ERR_COMMAND);
    257      1.13   mycroft     /* NOTREACHED */
    258       1.1       cgd }
    259       1.1       cgd 
    260       1.1       cgd /*
    261       1.1       cgd  * Execute command f, arg list t.
    262       1.1       cgd  * Record error message if not found.
    263       1.1       cgd  * Also do shell scripts here.
    264       1.1       cgd  */
    265       1.1       cgd static void
    266      1.16       wiz texec(Char *sf, Char **st)
    267       1.1       cgd {
    268      1.10       tls     struct varent *v;
    269      1.16       wiz     Char *lastsh[2], **vp, *st0, **ost;
    270      1.16       wiz     char *f, **t;
    271      1.16       wiz     int fd;
    272      1.23  christos     unsigned char c = '\0';
    273       1.1       cgd 
    274       1.1       cgd     /* The order for the conversions is significant */
    275       1.1       cgd     t = short2blk(st);
    276       1.1       cgd     f = short2str(sf);
    277       1.1       cgd     Vt = t;
    278       1.1       cgd     errno = 0;			/* don't use a previous error */
    279      1.16       wiz     (void)execve(f, t, environ);
    280       1.1       cgd     Vt = 0;
    281      1.16       wiz     blkfree((Char **)t);
    282       1.1       cgd     switch (errno) {
    283       1.1       cgd 
    284       1.1       cgd     case ENOEXEC:
    285       1.1       cgd 	/*
    286       1.1       cgd 	 * From: casper (at) fwi.uva.nl (Casper H.S. Dik) If we could not execute
    287       1.1       cgd 	 * it, don't feed it to the shell if it looks like a binary!
    288       1.1       cgd 	 */
    289       1.1       cgd 	if ((fd = open(f, O_RDONLY)) != -1) {
    290      1.16       wiz 	    if (read(fd, (char *)&c, 1) == 1) {
    291       1.1       cgd 		if (!Isprint(c) && (c != '\n' && c != '\t')) {
    292      1.16       wiz 		    (void)close(fd);
    293       1.1       cgd 		    /*
    294       1.1       cgd 		     * We *know* what ENOEXEC means.
    295       1.1       cgd 		     */
    296       1.1       cgd 		    stderror(ERR_ARCH, f, strerror(errno));
    297       1.1       cgd 		}
    298       1.1       cgd 	    }
    299       1.1       cgd #ifdef _PATH_BSHELL
    300       1.1       cgd 	    else
    301       1.1       cgd 		c = '#';
    302       1.1       cgd #endif
    303      1.16       wiz 	    (void)close(fd);
    304       1.1       cgd 	}
    305       1.1       cgd 	/*
    306       1.1       cgd 	 * If there is an alias for shell, then put the words of the alias in
    307       1.1       cgd 	 * front of the argument list replacing the command name. Note no
    308       1.1       cgd 	 * interpretation of the words at this point.
    309       1.1       cgd 	 */
    310       1.1       cgd 	v = adrof1(STRshell, &aliases);
    311       1.1       cgd 	if (v == 0) {
    312       1.1       cgd 	    vp = lastsh;
    313       1.1       cgd 	    vp[0] = adrof(STRshell) ? value(STRshell) : STR_SHELLPATH;
    314       1.1       cgd 	    vp[1] = NULL;
    315       1.1       cgd #ifdef _PATH_BSHELL
    316       1.1       cgd 	    if (fd != -1 && c != '#')
    317       1.1       cgd 		vp[0] = STR_BSHELL;
    318       1.1       cgd #endif
    319       1.1       cgd 	}
    320       1.1       cgd 	else
    321       1.1       cgd 	    vp = v->vec;
    322       1.1       cgd 	st0 = st[0];
    323       1.1       cgd 	st[0] = sf;
    324       1.1       cgd 	ost = st;
    325       1.1       cgd 	st = blkspl(vp, st);	/* Splice up the new arglst */
    326       1.1       cgd 	ost[0] = st0;
    327       1.1       cgd 	sf = *st;
    328       1.1       cgd 	/* The order for the conversions is significant */
    329       1.1       cgd 	t = short2blk(st);
    330       1.1       cgd 	f = short2str(sf);
    331       1.1       cgd 	xfree((ptr_t) st);
    332       1.1       cgd 	Vt = t;
    333      1.16       wiz 	(void)execve(f, t, environ);
    334       1.1       cgd 	Vt = 0;
    335       1.1       cgd 	blkfree((Char **) t);
    336      1.13   mycroft 	/* FALLTHROUGH */
    337       1.1       cgd 
    338       1.1       cgd     case ENOMEM:
    339       1.1       cgd 	stderror(ERR_SYSTEM, f, strerror(errno));
    340      1.13   mycroft 	/* NOTREACHED */
    341       1.1       cgd 
    342       1.1       cgd     case ENOENT:
    343       1.1       cgd 	break;
    344       1.1       cgd 
    345       1.1       cgd     default:
    346       1.1       cgd 	if (exerr == 0) {
    347       1.1       cgd 	    exerr = strerror(errno);
    348       1.1       cgd 	    if (expath)
    349       1.1       cgd 		xfree((ptr_t) expath);
    350       1.1       cgd 	    expath = Strsave(sf);
    351       1.1       cgd 	    Vexpath = expath;
    352       1.1       cgd 	}
    353       1.1       cgd     }
    354       1.1       cgd }
    355       1.1       cgd 
    356       1.1       cgd /*ARGSUSED*/
    357       1.1       cgd void
    358      1.16       wiz execash(Char **t, struct command *kp)
    359      1.16       wiz {
    360       1.5   mycroft     jmp_buf osetexit;
    361      1.16       wiz     sig_t osigint, osigquit, osigterm;
    362      1.16       wiz     int my_reenter, odidfds, oOLDSTD, oSHERR, oSHIN, oSHOUT;
    363      1.16       wiz     int saveDIAG, saveIN, saveOUT, saveSTD;
    364       1.5   mycroft 
    365       1.1       cgd     if (chkstop == 0 && setintr)
    366       1.1       cgd 	panystop(0);
    367       1.5   mycroft     /*
    368       1.5   mycroft      * Hmm, we don't really want to do that now because we might
    369       1.5   mycroft      * fail, but what is the choice
    370       1.5   mycroft      */
    371       1.1       cgd     rechist();
    372       1.5   mycroft 
    373       1.5   mycroft     osigint  = signal(SIGINT, parintr);
    374       1.5   mycroft     osigquit = signal(SIGQUIT, parintr);
    375       1.5   mycroft     osigterm = signal(SIGTERM, parterm);
    376       1.5   mycroft 
    377       1.5   mycroft     odidfds = didfds;
    378       1.5   mycroft     oSHIN = SHIN;
    379       1.5   mycroft     oSHOUT = SHOUT;
    380       1.5   mycroft     oSHERR = SHERR;
    381       1.5   mycroft     oOLDSTD = OLDSTD;
    382       1.5   mycroft 
    383       1.5   mycroft     saveIN = dcopy(SHIN, -1);
    384       1.5   mycroft     saveOUT = dcopy(SHOUT, -1);
    385       1.5   mycroft     saveDIAG = dcopy(SHERR, -1);
    386       1.5   mycroft     saveSTD = dcopy(OLDSTD, -1);
    387       1.5   mycroft 
    388       1.1       cgd     lshift(kp->t_dcom, 1);
    389       1.5   mycroft 
    390       1.5   mycroft     getexit(osetexit);
    391       1.5   mycroft 
    392       1.5   mycroft     if ((my_reenter = setexit()) == 0) {
    393       1.5   mycroft 	SHIN = dcopy(0, -1);
    394       1.5   mycroft 	SHOUT = dcopy(1, -1);
    395       1.5   mycroft 	SHERR = dcopy(2, -1);
    396       1.5   mycroft 	didfds = 0;
    397       1.5   mycroft 	doexec(t, kp);
    398       1.5   mycroft     }
    399       1.5   mycroft 
    400      1.16       wiz     (void)signal(SIGINT, osigint);
    401      1.16       wiz     (void)signal(SIGQUIT, osigquit);
    402      1.16       wiz     (void)signal(SIGTERM, osigterm);
    403       1.5   mycroft 
    404       1.5   mycroft     doneinp = 0;
    405       1.5   mycroft     didfds = odidfds;
    406      1.16       wiz     (void)close(SHIN);
    407      1.16       wiz     (void)close(SHOUT);
    408      1.16       wiz     (void)close(SHERR);
    409      1.16       wiz     (void)close(OLDSTD);
    410       1.5   mycroft     SHIN = dmove(saveIN, oSHIN);
    411       1.5   mycroft     SHOUT = dmove(saveOUT, oSHOUT);
    412       1.5   mycroft     SHERR = dmove(saveDIAG, oSHERR);
    413       1.5   mycroft     OLDSTD = dmove(saveSTD, oOLDSTD);
    414       1.5   mycroft 
    415       1.5   mycroft     resexit(osetexit);
    416      1.15   mycroft     if (my_reenter)
    417       1.5   mycroft 	stderror(ERR_SILENT);
    418       1.1       cgd }
    419       1.1       cgd 
    420       1.1       cgd void
    421      1.16       wiz xechoit(Char **t)
    422       1.1       cgd {
    423       1.1       cgd     if (adrof(STRecho)) {
    424      1.18  christos 	int odidfds = didfds;
    425      1.16       wiz 	(void)fflush(csherr);
    426      1.18  christos 	odidfds = didfds;
    427      1.18  christos 	didfds = 0;
    428       1.5   mycroft 	blkpr(csherr, t);
    429      1.16       wiz 	(void)fputc('\n', csherr);
    430      1.18  christos 	(void)fflush(csherr);
    431      1.18  christos 	didfds = odidfds;
    432       1.1       cgd     }
    433       1.1       cgd }
    434       1.1       cgd 
    435       1.1       cgd void
    436       1.5   mycroft /*ARGSUSED*/
    437      1.16       wiz dohash(Char **v, struct command *t)
    438       1.1       cgd {
    439      1.10       tls     struct dirent *dp;
    440      1.16       wiz     struct varent *pathv;
    441      1.16       wiz     DIR *dirp;
    442      1.16       wiz     Char **pv;
    443      1.16       wiz     int cnt, hashval, i;
    444       1.1       cgd 
    445      1.16       wiz     i = 0;
    446       1.1       cgd     havhash = 1;
    447      1.16       wiz     pathv = adrof(STRpath);
    448      1.16       wiz 
    449       1.1       cgd     for (cnt = 0; cnt < sizeof xhash; cnt++)
    450       1.1       cgd 	xhash[cnt] = 0;
    451       1.5   mycroft     if (pathv == 0)
    452       1.1       cgd 	return;
    453       1.5   mycroft     for (pv = pathv->vec; *pv; pv++, i++) {
    454       1.1       cgd 	if (pv[0][0] != '/')
    455       1.1       cgd 	    continue;
    456       1.1       cgd 	dirp = opendir(short2str(*pv));
    457       1.1       cgd 	if (dirp == NULL)
    458       1.1       cgd 	    continue;
    459       1.1       cgd 	while ((dp = readdir(dirp)) != NULL) {
    460       1.1       cgd 	    if (dp->d_ino == 0)
    461       1.1       cgd 		continue;
    462       1.1       cgd 	    if (dp->d_name[0] == '.' &&
    463       1.1       cgd 		(dp->d_name[1] == '\0' ||
    464       1.5   mycroft 		 (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
    465       1.1       cgd 		continue;
    466       1.1       cgd 	    hashval = hash(hashname(str2short(dp->d_name)), i);
    467       1.1       cgd 	    bis(xhash, hashval);
    468       1.1       cgd 	    /* tw_add_comm_name (dp->d_name); */
    469       1.1       cgd 	}
    470       1.1       cgd 	(void) closedir(dirp);
    471       1.1       cgd     }
    472       1.1       cgd }
    473       1.1       cgd 
    474       1.1       cgd void
    475       1.5   mycroft /*ARGSUSED*/
    476      1.16       wiz dounhash(Char **v, struct command *t)
    477       1.1       cgd {
    478       1.1       cgd     havhash = 0;
    479       1.1       cgd }
    480       1.1       cgd 
    481       1.1       cgd void
    482       1.5   mycroft /*ARGSUSED*/
    483      1.16       wiz hashstat(Char **v, struct command *t)
    484       1.1       cgd {
    485       1.1       cgd     if (hits + misses)
    486      1.16       wiz 	(void)fprintf(cshout, "%d hits, %d misses, %d%%\n",
    487      1.16       wiz 	    hits, misses, 100 * hits / (hits + misses));
    488       1.1       cgd }
    489       1.1       cgd 
    490       1.1       cgd /*
    491       1.1       cgd  * Hash a command name.
    492       1.1       cgd  */
    493       1.1       cgd static int
    494      1.16       wiz hashname(Char *cp)
    495       1.1       cgd {
    496      1.10       tls     long h = 0;
    497       1.1       cgd 
    498       1.1       cgd     while (*cp)
    499       1.1       cgd 	h = hash(h, *cp++);
    500       1.1       cgd     return ((int) h);
    501       1.5   mycroft }
    502       1.5   mycroft 
    503       1.5   mycroft static int
    504      1.16       wiz iscommand(Char *name)
    505       1.5   mycroft {
    506      1.10       tls     struct varent *v;
    507      1.16       wiz     Char **pv, *sav;
    508      1.16       wiz     int hashval, hashval1, i;
    509      1.26  christos     int slash;
    510       1.5   mycroft 
    511      1.16       wiz     hashval = 0;
    512      1.16       wiz     slash = any(short2str(name), '/');
    513       1.5   mycroft     v = adrof(STRpath);
    514      1.16       wiz 
    515       1.5   mycroft     if (v == 0 || v->vec[0] == 0 || slash)
    516       1.5   mycroft 	pv = justabs;
    517       1.5   mycroft     else
    518       1.5   mycroft 	pv = v->vec;
    519       1.5   mycroft     sav = Strspl(STRslash, name);	/* / command name for postpending */
    520       1.5   mycroft     if (havhash)
    521       1.5   mycroft 	hashval = hashname(name);
    522       1.5   mycroft     i = 0;
    523       1.5   mycroft     do {
    524       1.5   mycroft 	if (!slash && pv[0][0] == '/' && havhash) {
    525       1.5   mycroft 	    hashval1 = hash(hashval, i);
    526       1.5   mycroft 	    if (!bit(xhash, hashval1))
    527       1.5   mycroft 		goto cont;
    528       1.5   mycroft 	}
    529       1.5   mycroft 	if (pv[0][0] == 0 || eq(pv[0], STRdot)) {	/* don't make ./xxx */
    530       1.5   mycroft 	    if (executable(NULL, name, 0)) {
    531       1.5   mycroft 		xfree((ptr_t) sav);
    532       1.5   mycroft 		return i + 1;
    533       1.5   mycroft 	    }
    534       1.5   mycroft 	}
    535       1.5   mycroft 	else {
    536       1.5   mycroft 	    if (executable(*pv, sav, 0)) {
    537       1.5   mycroft 		xfree((ptr_t) sav);
    538       1.5   mycroft 		return i + 1;
    539       1.5   mycroft 	    }
    540       1.5   mycroft 	}
    541       1.5   mycroft cont:
    542       1.5   mycroft 	pv++;
    543       1.5   mycroft 	i++;
    544       1.5   mycroft     } while (*pv);
    545       1.5   mycroft     xfree((ptr_t) sav);
    546       1.5   mycroft     return 0;
    547       1.5   mycroft }
    548       1.5   mycroft 
    549       1.5   mycroft /* Also by:
    550       1.5   mycroft  *  Andreas Luik <luik (at) isaak.isa.de>
    551       1.5   mycroft  *  I S A  GmbH - Informationssysteme fuer computerintegrierte Automatisierung
    552       1.5   mycroft  *  Azenberstr. 35
    553       1.5   mycroft  *  D-7000 Stuttgart 1
    554       1.5   mycroft  *  West-Germany
    555       1.5   mycroft  * is the executable() routine below and changes to iscommand().
    556       1.5   mycroft  * Thanks again!!
    557       1.5   mycroft  */
    558       1.5   mycroft 
    559       1.5   mycroft /*
    560       1.5   mycroft  * executable() examines the pathname obtained by concatenating dir and name
    561       1.5   mycroft  * (dir may be NULL), and returns 1 either if it is executable by us, or
    562       1.5   mycroft  * if dir_ok is set and the pathname refers to a directory.
    563       1.5   mycroft  * This is a bit kludgy, but in the name of optimization...
    564       1.5   mycroft  */
    565       1.5   mycroft static int
    566      1.26  christos executable(Char *dir, Char *name, int dir_ok)
    567       1.5   mycroft {
    568       1.5   mycroft     struct stat stbuf;
    569      1.16       wiz     Char path[MAXPATHLEN + 1], *dp, *sp;
    570      1.16       wiz     char *strname;
    571       1.5   mycroft 
    572       1.5   mycroft     if (dir && *dir) {
    573       1.5   mycroft 	for (dp = path, sp = dir; *sp; *dp++ = *sp++)
    574       1.5   mycroft 	    if (dp == &path[MAXPATHLEN + 1]) {
    575       1.5   mycroft 		*--dp = '\0';
    576       1.5   mycroft 		break;
    577       1.5   mycroft 	    }
    578       1.5   mycroft 	for (sp = name; *sp; *dp++ = *sp++)
    579       1.5   mycroft 	    if (dp == &path[MAXPATHLEN + 1]) {
    580       1.5   mycroft 		*--dp = '\0';
    581       1.5   mycroft 		break;
    582       1.5   mycroft 	    }
    583       1.5   mycroft 	*dp = '\0';
    584       1.5   mycroft 	strname = short2str(path);
    585       1.5   mycroft     }
    586       1.5   mycroft     else
    587       1.5   mycroft 	strname = short2str(name);
    588      1.16       wiz     return (stat(strname, &stbuf) != -1 && ((S_ISREG(stbuf.st_mode) &&
    589      1.16       wiz         /* save time by not calling access() in the hopeless case */
    590      1.16       wiz 	(stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) &&
    591      1.16       wiz 	access(strname, X_OK) == 0) || (dir_ok && S_ISDIR(stbuf.st_mode))));
    592       1.5   mycroft }
    593       1.5   mycroft 
    594       1.5   mycroft /* The dowhich() is by:
    595       1.5   mycroft  *  Andreas Luik <luik (at) isaak.isa.de>
    596       1.5   mycroft  *  I S A  GmbH - Informationssysteme fuer computerintegrierte Automatisierung
    597       1.5   mycroft  *  Azenberstr. 35
    598       1.5   mycroft  *  D-7000 Stuttgart 1
    599       1.5   mycroft  *  West-Germany
    600       1.5   mycroft  * Thanks!!
    601       1.5   mycroft  */
    602       1.5   mycroft /*ARGSUSED*/
    603       1.5   mycroft void
    604      1.16       wiz dowhich(Char **v, struct command *c)
    605       1.5   mycroft {
    606      1.17     lukem     struct wordent lexw[3];
    607       1.5   mycroft     struct varent *vp;
    608       1.5   mycroft 
    609      1.17     lukem     lexw[0].next = &lexw[1];
    610      1.17     lukem     lexw[1].next = &lexw[2];
    611      1.17     lukem     lexw[2].next = &lexw[0];
    612      1.17     lukem 
    613      1.17     lukem     lexw[0].prev = &lexw[2];
    614      1.17     lukem     lexw[1].prev = &lexw[0];
    615      1.17     lukem     lexw[2].prev = &lexw[1];
    616       1.5   mycroft 
    617      1.17     lukem     lexw[0].word = STRNULL;
    618      1.17     lukem     lexw[2].word = STRret;
    619       1.5   mycroft 
    620       1.5   mycroft     while (*++v) {
    621       1.5   mycroft 	if ((vp = adrof1(*v, &aliases)) != NULL) {
    622      1.16       wiz 	    (void)fprintf(cshout, "%s: \t aliased to ", vis_str(*v));
    623       1.5   mycroft 	    blkpr(cshout, vp->vec);
    624      1.16       wiz 	    (void)fputc('\n', cshout);
    625       1.9  christos 	    set(STRstatus, Strsave(STR0));
    626       1.5   mycroft 	}
    627       1.5   mycroft 	else {
    628      1.17     lukem 	    lexw[1].word = *v;
    629      1.17     lukem 	    set(STRstatus, Strsave(tellmewhat(lexw, NULL) ? STR0 : STR1));
    630       1.5   mycroft 	}
    631       1.5   mycroft     }
    632       1.5   mycroft }
    633       1.5   mycroft 
    634       1.9  christos static int
    635      1.16       wiz tellmewhat(struct wordent *lexp, Char *str)
    636       1.5   mycroft {
    637      1.16       wiz     struct biltins *bptr;
    638      1.16       wiz     struct wordent *sp;
    639      1.16       wiz     Char *cmd, *s0, *s1, *s2;
    640      1.10       tls     int i;
    641      1.26  christos     int aliased, found;
    642      1.16       wiz     Char qc;
    643      1.16       wiz 
    644      1.16       wiz     aliased = 0;
    645      1.16       wiz     sp = lexp->next;
    646       1.5   mycroft 
    647       1.5   mycroft     if (adrof1(sp->word, &aliases)) {
    648       1.9  christos 	alias(lexp);
    649       1.9  christos 	sp = lexp->next;
    650       1.5   mycroft 	aliased = 1;
    651       1.5   mycroft     }
    652       1.5   mycroft 
    653       1.5   mycroft     s0 = sp->word;		/* to get the memory freeing right... */
    654       1.5   mycroft 
    655       1.5   mycroft     /* handle quoted alias hack */
    656       1.5   mycroft     if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE)
    657       1.5   mycroft 	(sp->word)++;
    658       1.5   mycroft 
    659       1.5   mycroft     /* do quoting, if it hasn't been done */
    660       1.5   mycroft     s1 = s2 = sp->word;
    661       1.5   mycroft     while (*s2)
    662       1.5   mycroft 	switch (*s2) {
    663       1.5   mycroft 	case '\'':
    664       1.5   mycroft 	case '"':
    665       1.5   mycroft 	    qc = *s2++;
    666       1.5   mycroft 	    while (*s2 && *s2 != qc)
    667       1.5   mycroft 		*s1++ = *s2++ | QUOTE;
    668       1.5   mycroft 	    if (*s2)
    669       1.5   mycroft 		s2++;
    670       1.5   mycroft 	    break;
    671       1.5   mycroft 	case '\\':
    672       1.5   mycroft 	    if (*++s2)
    673       1.5   mycroft 		*s1++ = *s2++ | QUOTE;
    674       1.5   mycroft 	    break;
    675       1.5   mycroft 	default:
    676       1.5   mycroft 	    *s1++ = *s2++;
    677       1.5   mycroft 	}
    678       1.5   mycroft     *s1 = '\0';
    679       1.5   mycroft 
    680       1.5   mycroft     for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) {
    681       1.5   mycroft 	if (eq(sp->word, str2short(bptr->bname))) {
    682       1.9  christos 	    if (str == NULL) {
    683       1.9  christos 		if (aliased)
    684       1.9  christos 		    prlex(cshout, lexp);
    685      1.16       wiz 		(void)fprintf(cshout, "%s: shell built-in command.\n",
    686       1.9  christos 			       vis_str(sp->word));
    687       1.9  christos 	    }
    688       1.9  christos 	    else
    689      1.16       wiz 		(void)Strcpy(str, sp->word);
    690       1.5   mycroft 	    sp->word = s0;	/* we save and then restore this */
    691       1.9  christos 	    return 1;
    692       1.5   mycroft 	}
    693       1.5   mycroft     }
    694       1.5   mycroft 
    695       1.8  christos     sp->word = cmd = globone(sp->word, G_IGNORE);
    696       1.8  christos 
    697       1.9  christos     if ((i = iscommand(sp->word)) != 0) {
    698      1.10       tls 	Char **pv;
    699      1.10       tls 	struct varent *v;
    700      1.26  christos 	int    slash = any(short2str(sp->word), '/');
    701       1.5   mycroft 
    702       1.5   mycroft 	v = adrof(STRpath);
    703       1.5   mycroft 	if (v == 0 || v->vec[0] == 0 || slash)
    704       1.5   mycroft 	    pv = justabs;
    705       1.5   mycroft 	else
    706       1.5   mycroft 	    pv = v->vec;
    707       1.5   mycroft 
    708       1.5   mycroft 	while (--i)
    709       1.5   mycroft 	    pv++;
    710       1.5   mycroft 	if (pv[0][0] == 0 || eq(pv[0], STRdot)) {
    711       1.8  christos 	    if (!slash) {
    712       1.8  christos 		sp->word = Strspl(STRdotsl, sp->word);
    713       1.9  christos 		prlex(cshout, lexp);
    714       1.8  christos 		xfree((ptr_t) sp->word);
    715       1.8  christos 	    }
    716       1.8  christos 	    else
    717       1.9  christos 		prlex(cshout, lexp);
    718       1.9  christos 	}
    719       1.9  christos 	else {
    720       1.9  christos 	    s1 = Strspl(*pv, STRslash);
    721       1.9  christos 	    sp->word = Strspl(s1, sp->word);
    722       1.9  christos 	    xfree((ptr_t) s1);
    723       1.9  christos 	    if (str == NULL)
    724       1.9  christos 		prlex(cshout, lexp);
    725       1.9  christos 	    else
    726      1.16       wiz 		(void)Strcpy(str, sp->word);
    727       1.9  christos 	    xfree((ptr_t) sp->word);
    728       1.5   mycroft 	}
    729       1.9  christos 	found = 1;
    730       1.5   mycroft     }
    731       1.5   mycroft     else {
    732       1.9  christos  	if (str == NULL) {
    733       1.9  christos 	    if (aliased)
    734       1.9  christos 		prlex(cshout, lexp);
    735      1.16       wiz 	    (void)fprintf(csherr,
    736       1.9  christos 			   "%s: Command not found.\n", vis_str(sp->word));
    737       1.9  christos 	}
    738       1.9  christos 	else
    739      1.16       wiz 	    (void)Strcpy(str, sp->word);
    740       1.9  christos 	found = 0;
    741       1.5   mycroft     }
    742       1.5   mycroft     sp->word = s0;		/* we save and then restore this */
    743       1.8  christos     xfree((ptr_t) cmd);
    744       1.9  christos     return found;
    745       1.1       cgd }
    746