1*1767ce60Schristos /* $NetBSD: exec.c,v 1.33 2019/01/05 16:54:00 christos Exp $ */
249f0ad86Scgd
361f28255Scgd /*-
4cee2bad8Smycroft * Copyright (c) 1980, 1991, 1993
5cee2bad8Smycroft * The Regents of the University of California. All rights reserved.
661f28255Scgd *
761f28255Scgd * Redistribution and use in source and binary forms, with or without
861f28255Scgd * modification, are permitted provided that the following conditions
961f28255Scgd * are met:
1061f28255Scgd * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd * notice, this list of conditions and the following disclaimer.
1261f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd * notice, this list of conditions and the following disclaimer in the
1461f28255Scgd * documentation and/or other materials provided with the distribution.
15b5b29542Sagc * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd * may be used to endorse or promote products derived from this software
1761f28255Scgd * without specific prior written permission.
1861f28255Scgd *
1961f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd * SUCH DAMAGE.
3061f28255Scgd */
3161f28255Scgd
328ea378c6Schristos #include <sys/cdefs.h>
3361f28255Scgd #ifndef lint
3449f0ad86Scgd #if 0
35ec16f0d3Schristos static char sccsid[] = "@(#)exec.c 8.3 (Berkeley) 5/23/95";
3649f0ad86Scgd #else
37*1767ce60Schristos __RCSID("$NetBSD: exec.c,v 1.33 2019/01/05 16:54:00 christos Exp $");
3849f0ad86Scgd #endif
3961f28255Scgd #endif /* not lint */
4061f28255Scgd
41cee2bad8Smycroft #include <sys/param.h>
42cee2bad8Smycroft #include <sys/stat.h>
43b771e65bSwiz #include <sys/types.h>
44b771e65bSwiz
45b771e65bSwiz #include <dirent.h>
4661f28255Scgd #include <errno.h>
47b771e65bSwiz #include <fcntl.h>
4818158540Swiz #include <stdarg.h>
4961f28255Scgd #include <stdlib.h>
5061f28255Scgd #include <string.h>
5161f28255Scgd #include <unistd.h>
52b771e65bSwiz
5361f28255Scgd #include "csh.h"
5461f28255Scgd #include "extern.h"
5561f28255Scgd
5661f28255Scgd /*
5761f28255Scgd * System level search and execute of a command. We look in each directory
5861f28255Scgd * for the specified command name. If the name contains a '/' then we
5961f28255Scgd * execute only the full path name. If there is no search path then we
6061f28255Scgd * execute only full path names.
6161f28255Scgd */
6261f28255Scgd extern char **environ;
6361f28255Scgd
6461f28255Scgd /*
6561f28255Scgd * As we search for the command we note the first non-trivial error
6661f28255Scgd * message for presentation to the user. This allows us often
6761f28255Scgd * to show that a file has the wrong mode/no access when the file
6861f28255Scgd * is not in the last component of the search path, so we must
6961f28255Scgd * go on after first detecting the error.
7061f28255Scgd */
71be432ed4Smycroft static const char *exerr; /* Execution error message */
7261f28255Scgd static Char *expath; /* Path for exerr */
7361f28255Scgd
7461f28255Scgd /*
7561f28255Scgd * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used
7661f28255Scgd * to hash execs. If it is allocated (havhash true), then to tell
7761f28255Scgd * whether ``name'' is (possibly) present in the i'th component
7861f28255Scgd * of the variable path, you look at the bit in xhash indexed by
7961f28255Scgd * hash(hashname("name"), i). This is setup automatically
8061f28255Scgd * after .login is executed, and recomputed whenever ``path'' is
8161f28255Scgd * changed.
8261f28255Scgd * The two part hash function is designed to let texec() call the
8361f28255Scgd * more expensive hashname() only once and the simple hash() several
8461f28255Scgd * times (once for each path component checked).
8561f28255Scgd * Byte size is assumed to be 8.
8661f28255Scgd */
8761f28255Scgd #define HSHSIZ 8192 /* 1k bytes */
8861f28255Scgd #define HSHMASK (HSHSIZ - 1)
8961f28255Scgd #define HSHMUL 243
9037e39248Schristos static unsigned char xhash[HSHSIZ / 8];
9161f28255Scgd
92cee2bad8Smycroft #define hash(a, b) (((a) * HSHMUL + (b)) & HSHMASK)
93c1d7b11eSchristos /* these macros eval their arguments multiple times, so be careful */
9461f28255Scgd #define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */
95b4f0f90aSchristos #define bis(h, b) ((h)[(b) >> 3] = \
96b4f0f90aSchristos (unsigned char)((1 << ((b) & 7)) | (h)[(b) >> 3]))/* bit set */
9761f28255Scgd static int hits, misses;
9861f28255Scgd
9961f28255Scgd /* Dummy search path for just absolute search when no path */
10061f28255Scgd static Char *justabs[] = {STRNULL, 0};
10161f28255Scgd
1028b0f9554Sperry static void pexerr(void) __dead;
103b771e65bSwiz static void texec(Char *, Char **);
104b771e65bSwiz static int hashname(Char *);
105b771e65bSwiz static int tellmewhat(struct wordent *, Char *);
106b79c2ef2Schristos static int executable(Char *, Char *, int);
107b771e65bSwiz static int iscommand(Char *);
10861f28255Scgd
10961f28255Scgd void
110cee2bad8Smycroft /*ARGSUSED*/
doexec(Char ** v,struct command * t)111b771e65bSwiz doexec(Char **v, struct command *t)
11261f28255Scgd {
11376adbe2bStls struct varent *pathv;
114b771e65bSwiz Char *blk[2], **av, *dp, **pv, *sav;
115b771e65bSwiz int i, hashval, hashval1;
116b3df6303Skleink sigset_t nsigset;
117b79c2ef2Schristos int slash;
11861f28255Scgd
119b771e65bSwiz hashval = 0;
12061f28255Scgd /*
12161f28255Scgd * Glob the command name. We will search $path even if this does something,
12261f28255Scgd * as in sh but not in csh. One special case: if there is no PATH, then we
12361f28255Scgd * execute only commands which start with '/'.
12461f28255Scgd */
12561f28255Scgd blk[0] = t->t_dcom[0];
12661f28255Scgd blk[1] = 0;
12761f28255Scgd gflag = 0, tglob(blk);
12861f28255Scgd if (gflag) {
12961f28255Scgd pv = globall(blk);
13061f28255Scgd if (pv == 0) {
131cee2bad8Smycroft setname(vis_str(blk[0]));
13261f28255Scgd stderror(ERR_NAME | ERR_NOMATCH);
13361f28255Scgd }
13461f28255Scgd gargv = 0;
13561f28255Scgd }
13661f28255Scgd else
13761f28255Scgd pv = saveblk(blk);
13861f28255Scgd
13961f28255Scgd trim(pv);
14061f28255Scgd
14161f28255Scgd exerr = 0;
14261f28255Scgd expath = Strsave(pv[0]);
14361f28255Scgd Vexpath = expath;
14461f28255Scgd
145cee2bad8Smycroft pathv = adrof(STRpath);
146cee2bad8Smycroft if (pathv == 0 && expath[0] != '/') {
14761f28255Scgd blkfree(pv);
14861f28255Scgd pexerr();
14961f28255Scgd }
15061f28255Scgd slash = any(short2str(expath), '/');
15161f28255Scgd
15261f28255Scgd /*
15361f28255Scgd * Glob the argument list, if necessary. Otherwise trim off the quote bits.
15461f28255Scgd */
15561f28255Scgd gflag = 0;
15661f28255Scgd av = &t->t_dcom[1];
15761f28255Scgd tglob(av);
15861f28255Scgd if (gflag) {
15961f28255Scgd av = globall(av);
16061f28255Scgd if (av == 0) {
16161f28255Scgd blkfree(pv);
162cee2bad8Smycroft setname(vis_str(expath));
16361f28255Scgd stderror(ERR_NAME | ERR_NOMATCH);
16461f28255Scgd }
16561f28255Scgd gargv = 0;
16661f28255Scgd }
16761f28255Scgd else
16861f28255Scgd av = saveblk(av);
16961f28255Scgd
17061f28255Scgd blkfree(t->t_dcom);
17161f28255Scgd t->t_dcom = blkspl(pv, av);
172*1767ce60Schristos free(pv);
173*1767ce60Schristos free(av);
17461f28255Scgd av = t->t_dcom;
17561f28255Scgd trim(av);
17661f28255Scgd
17761f28255Scgd if (*av == NULL || **av == '\0')
17861f28255Scgd pexerr();
17961f28255Scgd
18061f28255Scgd xechoit(av); /* Echo command if -x */
18161f28255Scgd /*
18261f28255Scgd * Since all internal file descriptors are set to close on exec, we don't
18361f28255Scgd * need to close them explicitly here. Just reorient ourselves for error
18461f28255Scgd * messages.
18561f28255Scgd */
18661f28255Scgd SHIN = 0;
18761f28255Scgd SHOUT = 1;
188cee2bad8Smycroft SHERR = 2;
18961f28255Scgd OLDSTD = 0;
19061f28255Scgd /*
19161f28255Scgd * We must do this AFTER any possible forking (like `foo` in glob) so that
19261f28255Scgd * this shell can still do subprocesses.
19361f28255Scgd */
194b3df6303Skleink sigemptyset(&nsigset);
195b3df6303Skleink (void)sigprocmask(SIG_SETMASK, &nsigset, NULL);
19661f28255Scgd /*
19761f28255Scgd * If no path, no words in path, or a / in the filename then restrict the
19861f28255Scgd * command search.
19961f28255Scgd */
200cee2bad8Smycroft if (pathv == 0 || pathv->vec[0] == 0 || slash)
20161f28255Scgd pv = justabs;
20261f28255Scgd else
203cee2bad8Smycroft pv = pathv->vec;
20461f28255Scgd sav = Strspl(STRslash, *av); /* / command name for postpending */
20561f28255Scgd Vsav = sav;
20661f28255Scgd if (havhash)
20761f28255Scgd hashval = hashname(*av);
20861f28255Scgd i = 0;
20961f28255Scgd hits++;
21061f28255Scgd do {
21161f28255Scgd /*
21261f28255Scgd * Try to save time by looking at the hash table for where this command
21361f28255Scgd * could be. If we are doing delayed hashing, then we put the names in
21461f28255Scgd * one at a time, as the user enters them. This is kinda like Korn
21561f28255Scgd * Shell's "tracked aliases".
21661f28255Scgd */
21761f28255Scgd if (!slash && pv[0][0] == '/' && havhash) {
21861f28255Scgd hashval1 = hash(hashval, i);
21961f28255Scgd if (!bit(xhash, hashval1))
22061f28255Scgd goto cont;
22161f28255Scgd }
22261f28255Scgd if (pv[0][0] == 0 || eq(pv[0], STRdot)) /* don't make ./xxx */
22361f28255Scgd texec(*av, av);
22461f28255Scgd else {
22561f28255Scgd dp = Strspl(*pv, sav);
22661f28255Scgd Vdp = dp;
22761f28255Scgd texec(dp, av);
22861f28255Scgd Vdp = 0;
229*1767ce60Schristos free(dp);
23061f28255Scgd }
23161f28255Scgd misses++;
23261f28255Scgd cont:
23361f28255Scgd pv++;
23461f28255Scgd i++;
23561f28255Scgd } while (*pv);
23661f28255Scgd hits--;
23761f28255Scgd Vsav = 0;
238*1767ce60Schristos free(sav);
23961f28255Scgd pexerr();
240ee9e50eaSmycroft /* NOTREACHED */
24161f28255Scgd }
24261f28255Scgd
24361f28255Scgd static void
pexerr(void)244b771e65bSwiz pexerr(void)
24561f28255Scgd {
24661f28255Scgd /* Couldn't find the damn thing */
24761f28255Scgd if (expath) {
248cee2bad8Smycroft setname(vis_str(expath));
24961f28255Scgd Vexpath = 0;
250*1767ce60Schristos free(expath);
25161f28255Scgd expath = 0;
25261f28255Scgd }
25361f28255Scgd else
25461f28255Scgd setname("");
25561f28255Scgd if (exerr)
25661f28255Scgd stderror(ERR_NAME | ERR_STRING, exerr);
257cdbd74daSmycroft else
25861f28255Scgd stderror(ERR_NAME | ERR_COMMAND);
259cdbd74daSmycroft /* NOTREACHED */
26061f28255Scgd }
26161f28255Scgd
26261f28255Scgd /*
26361f28255Scgd * Execute command f, arg list t.
26461f28255Scgd * Record error message if not found.
26561f28255Scgd * Also do shell scripts here.
26661f28255Scgd */
26761f28255Scgd static void
texec(Char * sf,Char ** st)268b771e65bSwiz texec(Char *sf, Char **st)
26961f28255Scgd {
27076adbe2bStls struct varent *v;
271b771e65bSwiz Char *lastsh[2], **vp, *st0, **ost;
272b771e65bSwiz char *f, **t;
27361f28255Scgd int fd;
2742701e5b9Schristos unsigned char c = '\0';
27561f28255Scgd
27661f28255Scgd /* The order for the conversions is significant */
27761f28255Scgd t = short2blk(st);
27861f28255Scgd f = short2str(sf);
27961f28255Scgd Vt = t;
28061f28255Scgd errno = 0; /* don't use a previous error */
28161f28255Scgd (void)execve(f, t, environ);
28261f28255Scgd Vt = 0;
28361f28255Scgd blkfree((Char **)t);
28461f28255Scgd switch (errno) {
28561f28255Scgd
28661f28255Scgd case ENOEXEC:
28761f28255Scgd /*
28861f28255Scgd * From: casper@fwi.uva.nl (Casper H.S. Dik) If we could not execute
28961f28255Scgd * it, don't feed it to the shell if it looks like a binary!
29061f28255Scgd */
29161f28255Scgd if ((fd = open(f, O_RDONLY)) != -1) {
29261f28255Scgd if (read(fd, (char *)&c, 1) == 1) {
29361f28255Scgd if (!Isprint(c) && (c != '\n' && c != '\t')) {
29461f28255Scgd (void)close(fd);
29561f28255Scgd /*
29661f28255Scgd * We *know* what ENOEXEC means.
29761f28255Scgd */
29861f28255Scgd stderror(ERR_ARCH, f, strerror(errno));
29961f28255Scgd }
30061f28255Scgd }
30161f28255Scgd #ifdef _PATH_BSHELL
30261f28255Scgd else
30361f28255Scgd c = '#';
30461f28255Scgd #endif
30561f28255Scgd (void)close(fd);
30661f28255Scgd }
30761f28255Scgd /*
30861f28255Scgd * If there is an alias for shell, then put the words of the alias in
30961f28255Scgd * front of the argument list replacing the command name. Note no
31061f28255Scgd * interpretation of the words at this point.
31161f28255Scgd */
31261f28255Scgd v = adrof1(STRshell, &aliases);
31361f28255Scgd if (v == 0) {
31461f28255Scgd vp = lastsh;
31561f28255Scgd vp[0] = adrof(STRshell) ? value(STRshell) : STR_SHELLPATH;
31661f28255Scgd vp[1] = NULL;
31761f28255Scgd #ifdef _PATH_BSHELL
31861f28255Scgd if (fd != -1 && c != '#')
31961f28255Scgd vp[0] = STR_BSHELL;
32061f28255Scgd #endif
32161f28255Scgd }
32261f28255Scgd else
32361f28255Scgd vp = v->vec;
32461f28255Scgd st0 = st[0];
32561f28255Scgd st[0] = sf;
32661f28255Scgd ost = st;
32761f28255Scgd st = blkspl(vp, st); /* Splice up the new arglst */
32861f28255Scgd ost[0] = st0;
32961f28255Scgd sf = *st;
33061f28255Scgd /* The order for the conversions is significant */
33161f28255Scgd t = short2blk(st);
33261f28255Scgd f = short2str(sf);
333*1767ce60Schristos free(st);
33461f28255Scgd Vt = t;
33561f28255Scgd (void)execve(f, t, environ);
33661f28255Scgd Vt = 0;
33761f28255Scgd blkfree((Char **)t);
338cdbd74daSmycroft /* FALLTHROUGH */
33961f28255Scgd
34061f28255Scgd case ENOMEM:
34161f28255Scgd stderror(ERR_SYSTEM, f, strerror(errno));
342cdbd74daSmycroft /* NOTREACHED */
34361f28255Scgd
34461f28255Scgd case ENOENT:
34561f28255Scgd break;
34661f28255Scgd
34761f28255Scgd default:
34861f28255Scgd if (exerr == 0) {
34961f28255Scgd exerr = strerror(errno);
35061f28255Scgd if (expath)
351*1767ce60Schristos free(expath);
35261f28255Scgd expath = Strsave(sf);
35361f28255Scgd Vexpath = expath;
35461f28255Scgd }
35561f28255Scgd }
35661f28255Scgd }
35761f28255Scgd
35861f28255Scgd /*ARGSUSED*/
35961f28255Scgd void
execash(Char ** t,struct command * kp)360b771e65bSwiz execash(Char **t, struct command *kp)
36161f28255Scgd {
362cee2bad8Smycroft jmp_buf osetexit;
363cee2bad8Smycroft sig_t osigint, osigquit, osigterm;
364b771e65bSwiz int my_reenter, odidfds, oOLDSTD, oSHERR, oSHIN, oSHOUT;
365b771e65bSwiz int saveDIAG, saveIN, saveOUT, saveSTD;
366cee2bad8Smycroft
36761f28255Scgd if (chkstop == 0 && setintr)
36861f28255Scgd panystop(0);
369cee2bad8Smycroft /*
370cee2bad8Smycroft * Hmm, we don't really want to do that now because we might
371cee2bad8Smycroft * fail, but what is the choice
372cee2bad8Smycroft */
37361f28255Scgd rechist();
374cee2bad8Smycroft
375cee2bad8Smycroft osigint = signal(SIGINT, parintr);
376cee2bad8Smycroft osigquit = signal(SIGQUIT, parintr);
377cee2bad8Smycroft osigterm = signal(SIGTERM, parterm);
378cee2bad8Smycroft
379cee2bad8Smycroft odidfds = didfds;
380cee2bad8Smycroft oSHIN = SHIN;
381cee2bad8Smycroft oSHOUT = SHOUT;
382cee2bad8Smycroft oSHERR = SHERR;
383cee2bad8Smycroft oOLDSTD = OLDSTD;
384cee2bad8Smycroft
385cee2bad8Smycroft saveIN = dcopy(SHIN, -1);
386cee2bad8Smycroft saveOUT = dcopy(SHOUT, -1);
387cee2bad8Smycroft saveDIAG = dcopy(SHERR, -1);
388cee2bad8Smycroft saveSTD = dcopy(OLDSTD, -1);
389cee2bad8Smycroft
39061f28255Scgd lshift(kp->t_dcom, 1);
391cee2bad8Smycroft
392cee2bad8Smycroft getexit(osetexit);
393cee2bad8Smycroft
394cee2bad8Smycroft if ((my_reenter = setexit()) == 0) {
395cee2bad8Smycroft SHIN = dcopy(0, -1);
396cee2bad8Smycroft SHOUT = dcopy(1, -1);
397cee2bad8Smycroft SHERR = dcopy(2, -1);
398cee2bad8Smycroft didfds = 0;
399cee2bad8Smycroft doexec(t, kp);
400cee2bad8Smycroft }
401cee2bad8Smycroft
402cee2bad8Smycroft (void)signal(SIGINT, osigint);
403cee2bad8Smycroft (void)signal(SIGQUIT, osigquit);
404cee2bad8Smycroft (void)signal(SIGTERM, osigterm);
405cee2bad8Smycroft
406cee2bad8Smycroft doneinp = 0;
407cee2bad8Smycroft didfds = odidfds;
408cee2bad8Smycroft (void)close(SHIN);
409cee2bad8Smycroft (void)close(SHOUT);
410cee2bad8Smycroft (void)close(SHERR);
411cee2bad8Smycroft (void)close(OLDSTD);
412cee2bad8Smycroft SHIN = dmove(saveIN, oSHIN);
413cee2bad8Smycroft SHOUT = dmove(saveOUT, oSHOUT);
414cee2bad8Smycroft SHERR = dmove(saveDIAG, oSHERR);
415cee2bad8Smycroft OLDSTD = dmove(saveSTD, oOLDSTD);
416cee2bad8Smycroft
417cee2bad8Smycroft resexit(osetexit);
418ee9e50eaSmycroft if (my_reenter)
419cee2bad8Smycroft stderror(ERR_SILENT);
42061f28255Scgd }
42161f28255Scgd
42261f28255Scgd void
xechoit(Char ** t)423b771e65bSwiz xechoit(Char **t)
42461f28255Scgd {
42561f28255Scgd if (adrof(STRecho)) {
426971f3382Schristos int odidfds = didfds;
427cee2bad8Smycroft (void)fflush(csherr);
428971f3382Schristos odidfds = didfds;
429971f3382Schristos didfds = 0;
430cee2bad8Smycroft blkpr(csherr, t);
431cee2bad8Smycroft (void)fputc('\n', csherr);
432971f3382Schristos (void)fflush(csherr);
433971f3382Schristos didfds = odidfds;
43461f28255Scgd }
43561f28255Scgd }
43661f28255Scgd
43761f28255Scgd void
438cee2bad8Smycroft /*ARGSUSED*/
dohash(Char ** v,struct command * t)439b771e65bSwiz dohash(Char **v, struct command *t)
44061f28255Scgd {
44176adbe2bStls struct dirent *dp;
442b771e65bSwiz struct varent *pathv;
443b771e65bSwiz DIR *dirp;
44461f28255Scgd Char **pv;
4459050ab5cSlukem size_t cnt;
4469050ab5cSlukem int hashval, i;
44761f28255Scgd
448b771e65bSwiz i = 0;
44961f28255Scgd havhash = 1;
450b771e65bSwiz pathv = adrof(STRpath);
451b771e65bSwiz
45261f28255Scgd for (cnt = 0; cnt < sizeof xhash; cnt++)
45361f28255Scgd xhash[cnt] = 0;
454cee2bad8Smycroft if (pathv == 0)
45561f28255Scgd return;
456cee2bad8Smycroft for (pv = pathv->vec; *pv; pv++, i++) {
45761f28255Scgd if (pv[0][0] != '/')
45861f28255Scgd continue;
45961f28255Scgd dirp = opendir(short2str(*pv));
46061f28255Scgd if (dirp == NULL)
46161f28255Scgd continue;
46261f28255Scgd while ((dp = readdir(dirp)) != NULL) {
46361f28255Scgd if (dp->d_ino == 0)
46461f28255Scgd continue;
46561f28255Scgd if (dp->d_name[0] == '.' &&
46661f28255Scgd (dp->d_name[1] == '\0' ||
467cee2bad8Smycroft (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
46861f28255Scgd continue;
46961f28255Scgd hashval = hash(hashname(str2short(dp->d_name)), i);
47061f28255Scgd bis(xhash, hashval);
47161f28255Scgd /* tw_add_comm_name (dp->d_name); */
47261f28255Scgd }
47361f28255Scgd (void) closedir(dirp);
47461f28255Scgd }
47561f28255Scgd }
47661f28255Scgd
47761f28255Scgd void
478cee2bad8Smycroft /*ARGSUSED*/
dounhash(Char ** v,struct command * t)479b771e65bSwiz dounhash(Char **v, struct command *t)
48061f28255Scgd {
48161f28255Scgd havhash = 0;
48261f28255Scgd }
48361f28255Scgd
48461f28255Scgd void
485cee2bad8Smycroft /*ARGSUSED*/
hashstat(Char ** v,struct command * t)486b771e65bSwiz hashstat(Char **v, struct command *t)
48761f28255Scgd {
48861f28255Scgd if (hits + misses)
489cee2bad8Smycroft (void)fprintf(cshout, "%d hits, %d misses, %d%%\n",
49061f28255Scgd hits, misses, 100 * hits / (hits + misses));
49161f28255Scgd }
49261f28255Scgd
49361f28255Scgd /*
49461f28255Scgd * Hash a command name.
49561f28255Scgd */
49661f28255Scgd static int
hashname(Char * cp)497b771e65bSwiz hashname(Char *cp)
49861f28255Scgd {
49976adbe2bStls long h = 0;
50061f28255Scgd
50161f28255Scgd while (*cp)
50261f28255Scgd h = hash(h, *cp++);
50361f28255Scgd return ((int) h);
50461f28255Scgd }
505cee2bad8Smycroft
506cee2bad8Smycroft static int
iscommand(Char * name)507b771e65bSwiz iscommand(Char *name)
508cee2bad8Smycroft {
50976adbe2bStls struct varent *v;
510b771e65bSwiz Char **pv, *sav;
511b771e65bSwiz int hashval, hashval1, i;
512b79c2ef2Schristos int slash;
513cee2bad8Smycroft
514b771e65bSwiz hashval = 0;
515b771e65bSwiz slash = any(short2str(name), '/');
516cee2bad8Smycroft v = adrof(STRpath);
517b771e65bSwiz
518cee2bad8Smycroft if (v == 0 || v->vec[0] == 0 || slash)
519cee2bad8Smycroft pv = justabs;
520cee2bad8Smycroft else
521cee2bad8Smycroft pv = v->vec;
522cee2bad8Smycroft sav = Strspl(STRslash, name); /* / command name for postpending */
523cee2bad8Smycroft if (havhash)
524cee2bad8Smycroft hashval = hashname(name);
525cee2bad8Smycroft i = 0;
526cee2bad8Smycroft do {
527cee2bad8Smycroft if (!slash && pv[0][0] == '/' && havhash) {
528cee2bad8Smycroft hashval1 = hash(hashval, i);
529cee2bad8Smycroft if (!bit(xhash, hashval1))
530cee2bad8Smycroft goto cont;
531cee2bad8Smycroft }
532cee2bad8Smycroft if (pv[0][0] == 0 || eq(pv[0], STRdot)) { /* don't make ./xxx */
533cee2bad8Smycroft if (executable(NULL, name, 0)) {
534*1767ce60Schristos free(sav);
535cee2bad8Smycroft return i + 1;
536cee2bad8Smycroft }
537cee2bad8Smycroft }
538cee2bad8Smycroft else {
539cee2bad8Smycroft if (executable(*pv, sav, 0)) {
540*1767ce60Schristos free(sav);
541cee2bad8Smycroft return i + 1;
542cee2bad8Smycroft }
543cee2bad8Smycroft }
544cee2bad8Smycroft cont:
545cee2bad8Smycroft pv++;
546cee2bad8Smycroft i++;
547cee2bad8Smycroft } while (*pv);
548*1767ce60Schristos free(sav);
549cee2bad8Smycroft return 0;
550cee2bad8Smycroft }
551cee2bad8Smycroft
552cee2bad8Smycroft /* Also by:
553cee2bad8Smycroft * Andreas Luik <luik@isaak.isa.de>
554cee2bad8Smycroft * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung
555cee2bad8Smycroft * Azenberstr. 35
556cee2bad8Smycroft * D-7000 Stuttgart 1
557cee2bad8Smycroft * West-Germany
558cee2bad8Smycroft * is the executable() routine below and changes to iscommand().
559cee2bad8Smycroft * Thanks again!!
560cee2bad8Smycroft */
561cee2bad8Smycroft
562cee2bad8Smycroft /*
563cee2bad8Smycroft * executable() examines the pathname obtained by concatenating dir and name
564cee2bad8Smycroft * (dir may be NULL), and returns 1 either if it is executable by us, or
565cee2bad8Smycroft * if dir_ok is set and the pathname refers to a directory.
566cee2bad8Smycroft * This is a bit kludgy, but in the name of optimization...
567cee2bad8Smycroft */
568cee2bad8Smycroft static int
executable(Char * dir,Char * name,int dir_ok)569b79c2ef2Schristos executable(Char *dir, Char *name, int dir_ok)
570cee2bad8Smycroft {
571cee2bad8Smycroft struct stat stbuf;
572cee2bad8Smycroft Char path[MAXPATHLEN + 1], *dp, *sp;
573cee2bad8Smycroft char *strname;
574cee2bad8Smycroft
575cee2bad8Smycroft if (dir && *dir) {
576cee2bad8Smycroft for (dp = path, sp = dir; *sp; *dp++ = *sp++)
577cee2bad8Smycroft if (dp == &path[MAXPATHLEN + 1]) {
578cee2bad8Smycroft *--dp = '\0';
579cee2bad8Smycroft break;
580cee2bad8Smycroft }
581cee2bad8Smycroft for (sp = name; *sp; *dp++ = *sp++)
582cee2bad8Smycroft if (dp == &path[MAXPATHLEN + 1]) {
583cee2bad8Smycroft *--dp = '\0';
584cee2bad8Smycroft break;
585cee2bad8Smycroft }
586cee2bad8Smycroft *dp = '\0';
587cee2bad8Smycroft strname = short2str(path);
588cee2bad8Smycroft }
589cee2bad8Smycroft else
590cee2bad8Smycroft strname = short2str(name);
591b771e65bSwiz return (stat(strname, &stbuf) != -1 && ((S_ISREG(stbuf.st_mode) &&
592cee2bad8Smycroft /* save time by not calling access() in the hopeless case */
593cee2bad8Smycroft (stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) &&
594b771e65bSwiz access(strname, X_OK) == 0) || (dir_ok && S_ISDIR(stbuf.st_mode))));
595cee2bad8Smycroft }
596cee2bad8Smycroft
597cee2bad8Smycroft /* The dowhich() is by:
598cee2bad8Smycroft * Andreas Luik <luik@isaak.isa.de>
599cee2bad8Smycroft * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung
600cee2bad8Smycroft * Azenberstr. 35
601cee2bad8Smycroft * D-7000 Stuttgart 1
602cee2bad8Smycroft * West-Germany
603cee2bad8Smycroft * Thanks!!
604cee2bad8Smycroft */
605cee2bad8Smycroft /*ARGSUSED*/
606cee2bad8Smycroft void
dowhich(Char ** v,struct command * c)607b771e65bSwiz dowhich(Char **v, struct command *c)
608cee2bad8Smycroft {
609537f55c6Slukem struct wordent lexw[3];
610cee2bad8Smycroft struct varent *vp;
611cee2bad8Smycroft
612537f55c6Slukem lexw[0].next = &lexw[1];
613537f55c6Slukem lexw[1].next = &lexw[2];
614537f55c6Slukem lexw[2].next = &lexw[0];
615cee2bad8Smycroft
616537f55c6Slukem lexw[0].prev = &lexw[2];
617537f55c6Slukem lexw[1].prev = &lexw[0];
618537f55c6Slukem lexw[2].prev = &lexw[1];
619cee2bad8Smycroft
620537f55c6Slukem lexw[0].word = STRNULL;
621537f55c6Slukem lexw[2].word = STRret;
622cee2bad8Smycroft
623cee2bad8Smycroft while (*++v) {
624cee2bad8Smycroft if ((vp = adrof1(*v, &aliases)) != NULL) {
625cee2bad8Smycroft (void)fprintf(cshout, "%s: \t aliased to ", vis_str(*v));
626cee2bad8Smycroft blkpr(cshout, vp->vec);
627cee2bad8Smycroft (void)fputc('\n', cshout);
6280c750830Schristos set(STRstatus, Strsave(STR0));
629cee2bad8Smycroft }
630cee2bad8Smycroft else {
631537f55c6Slukem lexw[1].word = *v;
632537f55c6Slukem set(STRstatus, Strsave(tellmewhat(lexw, NULL) ? STR0 : STR1));
633cee2bad8Smycroft }
634cee2bad8Smycroft }
635cee2bad8Smycroft }
636cee2bad8Smycroft
6370c750830Schristos static int
tellmewhat(struct wordent * lexp,Char * str)638b771e65bSwiz tellmewhat(struct wordent *lexp, Char *str)
639cee2bad8Smycroft {
64076adbe2bStls struct biltins *bptr;
641b771e65bSwiz struct wordent *sp;
642b771e65bSwiz Char *cmd, *s0, *s1, *s2;
643b771e65bSwiz int i;
644b79c2ef2Schristos int aliased, found;
645cee2bad8Smycroft Char qc;
646cee2bad8Smycroft
647b771e65bSwiz aliased = 0;
648b771e65bSwiz sp = lexp->next;
649b771e65bSwiz
650cee2bad8Smycroft if (adrof1(sp->word, &aliases)) {
6510c750830Schristos alias(lexp);
6520c750830Schristos sp = lexp->next;
653cee2bad8Smycroft aliased = 1;
654cee2bad8Smycroft }
655cee2bad8Smycroft
656cee2bad8Smycroft s0 = sp->word; /* to get the memory freeing right... */
657cee2bad8Smycroft
658cee2bad8Smycroft /* handle quoted alias hack */
659cee2bad8Smycroft if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE)
660cee2bad8Smycroft (sp->word)++;
661cee2bad8Smycroft
662cee2bad8Smycroft /* do quoting, if it hasn't been done */
663cee2bad8Smycroft s1 = s2 = sp->word;
664cee2bad8Smycroft while (*s2)
665cee2bad8Smycroft switch (*s2) {
666cee2bad8Smycroft case '\'':
667cee2bad8Smycroft case '"':
668cee2bad8Smycroft qc = *s2++;
669cee2bad8Smycroft while (*s2 && *s2 != qc)
67037e39248Schristos *s1++ = (Char)(*s2++ | QUOTE);
671cee2bad8Smycroft if (*s2)
672cee2bad8Smycroft s2++;
673cee2bad8Smycroft break;
674cee2bad8Smycroft case '\\':
675cee2bad8Smycroft if (*++s2)
67637e39248Schristos *s1++ = (Char)(*s2++ | QUOTE);
677cee2bad8Smycroft break;
678cee2bad8Smycroft default:
679cee2bad8Smycroft *s1++ = *s2++;
680cee2bad8Smycroft }
681cee2bad8Smycroft *s1 = '\0';
682cee2bad8Smycroft
683cee2bad8Smycroft for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) {
684cee2bad8Smycroft if (eq(sp->word, str2short(bptr->bname))) {
6850c750830Schristos if (str == NULL) {
686cee2bad8Smycroft if (aliased)
6870c750830Schristos prlex(cshout, lexp);
688cee2bad8Smycroft (void)fprintf(cshout, "%s: shell built-in command.\n",
689cee2bad8Smycroft vis_str(sp->word));
6900c750830Schristos }
6910c750830Schristos else
6920c750830Schristos (void)Strcpy(str, sp->word);
693cee2bad8Smycroft sp->word = s0; /* we save and then restore this */
6940c750830Schristos return 1;
695cee2bad8Smycroft }
696cee2bad8Smycroft }
697cee2bad8Smycroft
698ec16f0d3Schristos sp->word = cmd = globone(sp->word, G_IGNORE);
699ec16f0d3Schristos
7000c750830Schristos if ((i = iscommand(sp->word)) != 0) {
70176adbe2bStls Char **pv;
70276adbe2bStls struct varent *v;
703b79c2ef2Schristos int slash = any(short2str(sp->word), '/');
704cee2bad8Smycroft
705cee2bad8Smycroft v = adrof(STRpath);
706cee2bad8Smycroft if (v == 0 || v->vec[0] == 0 || slash)
707cee2bad8Smycroft pv = justabs;
708cee2bad8Smycroft else
709cee2bad8Smycroft pv = v->vec;
710cee2bad8Smycroft
711cee2bad8Smycroft while (--i)
712cee2bad8Smycroft pv++;
713cee2bad8Smycroft if (pv[0][0] == 0 || eq(pv[0], STRdot)) {
714ec16f0d3Schristos if (!slash) {
715cee2bad8Smycroft sp->word = Strspl(STRdotsl, sp->word);
7160c750830Schristos prlex(cshout, lexp);
717*1767ce60Schristos free(sp->word);
718ec16f0d3Schristos }
719ec16f0d3Schristos else
7200c750830Schristos prlex(cshout, lexp);
721cee2bad8Smycroft }
7220c750830Schristos else {
723cee2bad8Smycroft s1 = Strspl(*pv, STRslash);
724cee2bad8Smycroft sp->word = Strspl(s1, sp->word);
725*1767ce60Schristos free(s1);
7260c750830Schristos if (str == NULL)
7270c750830Schristos prlex(cshout, lexp);
7280c750830Schristos else
7290c750830Schristos (void)Strcpy(str, sp->word);
730*1767ce60Schristos free(sp->word);
731cee2bad8Smycroft }
7320c750830Schristos found = 1;
7330c750830Schristos }
734cee2bad8Smycroft else {
7350c750830Schristos if (str == NULL) {
736cee2bad8Smycroft if (aliased)
7370c750830Schristos prlex(cshout, lexp);
7380c750830Schristos (void)fprintf(csherr,
7390c750830Schristos "%s: Command not found.\n", vis_str(sp->word));
7400c750830Schristos }
7410c750830Schristos else
7420c750830Schristos (void)Strcpy(str, sp->word);
7430c750830Schristos found = 0;
744cee2bad8Smycroft }
745cee2bad8Smycroft sp->word = s0; /* we save and then restore this */
746*1767ce60Schristos free(cmd);
7470c750830Schristos return found;
748cee2bad8Smycroft }
749