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