1c80476e4SDavid E. O'Brien /*
2c80476e4SDavid E. O'Brien * sh.exec.c: Search, find, and execute a command!
3c80476e4SDavid E. O'Brien */
4c80476e4SDavid E. O'Brien /*-
5c80476e4SDavid E. O'Brien * Copyright (c) 1980, 1991 The Regents of the University of California.
6c80476e4SDavid E. O'Brien * All rights reserved.
7c80476e4SDavid E. O'Brien *
8c80476e4SDavid E. O'Brien * Redistribution and use in source and binary forms, with or without
9c80476e4SDavid E. O'Brien * modification, are permitted provided that the following conditions
10c80476e4SDavid E. O'Brien * are met:
11c80476e4SDavid E. O'Brien * 1. Redistributions of source code must retain the above copyright
12c80476e4SDavid E. O'Brien * notice, this list of conditions and the following disclaimer.
13c80476e4SDavid E. O'Brien * 2. Redistributions in binary form must reproduce the above copyright
14c80476e4SDavid E. O'Brien * notice, this list of conditions and the following disclaimer in the
15c80476e4SDavid E. O'Brien * documentation and/or other materials provided with the distribution.
1629301572SMark Peek * 3. Neither the name of the University nor the names of its contributors
17c80476e4SDavid E. O'Brien * may be used to endorse or promote products derived from this software
18c80476e4SDavid E. O'Brien * without specific prior written permission.
19c80476e4SDavid E. O'Brien *
20c80476e4SDavid E. O'Brien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21c80476e4SDavid E. O'Brien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22c80476e4SDavid E. O'Brien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23c80476e4SDavid E. O'Brien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24c80476e4SDavid E. O'Brien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25c80476e4SDavid E. O'Brien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26c80476e4SDavid E. O'Brien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27c80476e4SDavid E. O'Brien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28c80476e4SDavid E. O'Brien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29c80476e4SDavid E. O'Brien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30c80476e4SDavid E. O'Brien * SUCH DAMAGE.
31c80476e4SDavid E. O'Brien */
32c80476e4SDavid E. O'Brien #include "sh.h"
33c80476e4SDavid E. O'Brien #include "tc.h"
34c80476e4SDavid E. O'Brien #include "tw.h"
353b6eaa7bSAndrey A. Chernov #ifdef WINNT_NATIVE
36c80476e4SDavid E. O'Brien #include <nt.const.h>
373b6eaa7bSAndrey A. Chernov #endif /*WINNT_NATIVE*/
38c80476e4SDavid E. O'Brien
39c80476e4SDavid E. O'Brien /*
40c80476e4SDavid E. O'Brien * C shell
41c80476e4SDavid E. O'Brien */
42c80476e4SDavid E. O'Brien
43c80476e4SDavid E. O'Brien #ifndef OLDHASH
44c80476e4SDavid E. O'Brien # define FASTHASH /* Fast hashing is the default */
45c80476e4SDavid E. O'Brien #endif /* OLDHASH */
46c80476e4SDavid E. O'Brien
47c80476e4SDavid E. O'Brien /*
48c80476e4SDavid E. O'Brien * System level search and execute of a command.
49c80476e4SDavid E. O'Brien * We look in each directory for the specified command name.
50c80476e4SDavid E. O'Brien * If the name contains a '/' then we execute only the full path name.
51c80476e4SDavid E. O'Brien * If there is no search path then we execute only full path names.
52c80476e4SDavid E. O'Brien */
53c80476e4SDavid E. O'Brien
54c80476e4SDavid E. O'Brien /*
55c80476e4SDavid E. O'Brien * As we search for the command we note the first non-trivial error
56c80476e4SDavid E. O'Brien * message for presentation to the user. This allows us often
57c80476e4SDavid E. O'Brien * to show that a file has the wrong mode/no access when the file
58c80476e4SDavid E. O'Brien * is not in the last component of the search path, so we must
59c80476e4SDavid E. O'Brien * go on after first detecting the error.
60c80476e4SDavid E. O'Brien */
61c80476e4SDavid E. O'Brien static char *exerr; /* Execution error message */
62c80476e4SDavid E. O'Brien static Char *expath; /* Path for exerr */
63c80476e4SDavid E. O'Brien
64c80476e4SDavid E. O'Brien /*
65c80476e4SDavid E. O'Brien * The two part hash function is designed to let texec() call the
66c80476e4SDavid E. O'Brien * more expensive hashname() only once and the simple hash() several
67c80476e4SDavid E. O'Brien * times (once for each path component checked).
68c80476e4SDavid E. O'Brien * Byte size is assumed to be 8.
69c80476e4SDavid E. O'Brien */
70c80476e4SDavid E. O'Brien #define BITS_PER_BYTE 8
71c80476e4SDavid E. O'Brien
72c80476e4SDavid E. O'Brien #ifdef FASTHASH
73c80476e4SDavid E. O'Brien /*
74c80476e4SDavid E. O'Brien * xhash is an array of hash buckets which are used to hash execs. If
75c80476e4SDavid E. O'Brien * it is allocated (havhash true), then to tell if ``name'' is
769ccc37e3SMark Peek * (possibly) present in the i'th component of the variable path, look
77c80476e4SDavid E. O'Brien * at the [hashname(name)] bucket of size [hashwidth] bytes, in the [i
78c80476e4SDavid E. O'Brien * mod size*8]'th bit. The cache size is defaults to a length of 1024
79c80476e4SDavid E. O'Brien * buckets, each 1 byte wide. This implementation guarantees that
80c80476e4SDavid E. O'Brien * objects n bytes wide will be aligned on n byte boundaries.
81c80476e4SDavid E. O'Brien */
82c80476e4SDavid E. O'Brien # define HSHMUL 241
83c80476e4SDavid E. O'Brien
84c80476e4SDavid E. O'Brien static unsigned long *xhash = NULL;
85c80476e4SDavid E. O'Brien static unsigned int hashlength = 0, uhashlength = 0;
86c80476e4SDavid E. O'Brien static unsigned int hashwidth = 0, uhashwidth = 0;
87c80476e4SDavid E. O'Brien static int hashdebug = 0;
88c80476e4SDavid E. O'Brien
89c80476e4SDavid E. O'Brien # define hash(a, b) (((a) * HSHMUL + (b)) % (hashlength))
90c80476e4SDavid E. O'Brien # define widthof(t) (sizeof(t) * BITS_PER_BYTE)
91c80476e4SDavid E. O'Brien # define tbit(f, i, t) (((t *) xhash)[(f)] & \
9223338178SMark Peek (1UL << (i & (widthof(t) - 1))))
93c80476e4SDavid E. O'Brien # define tbis(f, i, t) (((t *) xhash)[(f)] |= \
9423338178SMark Peek (1UL << (i & (widthof(t) - 1))))
95c80476e4SDavid E. O'Brien # define cbit(f, i) tbit(f, i, unsigned char)
96c80476e4SDavid E. O'Brien # define cbis(f, i) tbis(f, i, unsigned char)
97c80476e4SDavid E. O'Brien # define sbit(f, i) tbit(f, i, unsigned short)
98c80476e4SDavid E. O'Brien # define sbis(f, i) tbis(f, i, unsigned short)
99c80476e4SDavid E. O'Brien # define ibit(f, i) tbit(f, i, unsigned int)
100c80476e4SDavid E. O'Brien # define ibis(f, i) tbis(f, i, unsigned int)
101c80476e4SDavid E. O'Brien # define lbit(f, i) tbit(f, i, unsigned long)
102c80476e4SDavid E. O'Brien # define lbis(f, i) tbis(f, i, unsigned long)
103c80476e4SDavid E. O'Brien
104c80476e4SDavid E. O'Brien # define bit(f, i) (hashwidth==sizeof(unsigned char) ? cbit(f,i) : \
105c80476e4SDavid E. O'Brien ((hashwidth==sizeof(unsigned short) ? sbit(f,i) : \
106c80476e4SDavid E. O'Brien ((hashwidth==sizeof(unsigned int) ? ibit(f,i) : \
107c80476e4SDavid E. O'Brien lbit(f,i))))))
108c80476e4SDavid E. O'Brien # define bis(f, i) (hashwidth==sizeof(unsigned char) ? cbis(f,i) : \
109c80476e4SDavid E. O'Brien ((hashwidth==sizeof(unsigned short) ? sbis(f,i) : \
110c80476e4SDavid E. O'Brien ((hashwidth==sizeof(unsigned int) ? ibis(f,i) : \
111c80476e4SDavid E. O'Brien lbis(f,i))))))
112c80476e4SDavid E. O'Brien #else /* OLDHASH */
113c80476e4SDavid E. O'Brien /*
114c80476e4SDavid E. O'Brien * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used
115c80476e4SDavid E. O'Brien * to hash execs. If it is allocated (havhash true), then to tell
116c80476e4SDavid E. O'Brien * whether ``name'' is (possibly) present in the i'th component
117c80476e4SDavid E. O'Brien * of the variable path, you look at the bit in xhash indexed by
118c80476e4SDavid E. O'Brien * hash(hashname("name"), i). This is setup automatically
119c80476e4SDavid E. O'Brien * after .login is executed, and recomputed whenever ``path'' is
120c80476e4SDavid E. O'Brien * changed.
121c80476e4SDavid E. O'Brien */
122c80476e4SDavid E. O'Brien # define HSHSIZ 8192 /* 1k bytes */
123c80476e4SDavid E. O'Brien # define HSHMASK (HSHSIZ - 1)
124c80476e4SDavid E. O'Brien # define HSHMUL 243
125c80476e4SDavid E. O'Brien static char xhash[HSHSIZ / BITS_PER_BYTE];
126c80476e4SDavid E. O'Brien
127c80476e4SDavid E. O'Brien # define hash(a, b) (((a) * HSHMUL + (b)) & HSHMASK)
128c80476e4SDavid E. O'Brien # define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */
129c80476e4SDavid E. O'Brien # define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */
130c80476e4SDavid E. O'Brien
131c80476e4SDavid E. O'Brien #endif /* FASTHASH */
132c80476e4SDavid E. O'Brien
133c80476e4SDavid E. O'Brien #ifdef VFORK
134c80476e4SDavid E. O'Brien static int hits, misses;
135c80476e4SDavid E. O'Brien #endif /* VFORK */
136c80476e4SDavid E. O'Brien
137c80476e4SDavid E. O'Brien /* Dummy search path for just absolute search when no path */
138c80476e4SDavid E. O'Brien static Char *justabs[] = {STRNULL, 0};
139c80476e4SDavid E. O'Brien
1409ccc37e3SMark Peek static void pexerr (void) __attribute__((__noreturn__));
14145e5710bSMark Peek static void texec (Char *, Char **);
14245e5710bSMark Peek int hashname (Char *);
14345e5710bSMark Peek static int iscommand (Char *);
144c80476e4SDavid E. O'Brien
145c80476e4SDavid E. O'Brien void
doexec(struct command * t,int do_glob)14645e5710bSMark Peek doexec(struct command *t, int do_glob)
147c80476e4SDavid E. O'Brien {
1489ccc37e3SMark Peek Char *dp, **pv, **opv, **av, *sav;
14929301572SMark Peek struct varent *v;
1509ccc37e3SMark Peek int slash, gflag, rehashed;
15129301572SMark Peek int hashval, i;
152c80476e4SDavid E. O'Brien Char *blk[2];
153c80476e4SDavid E. O'Brien
154c80476e4SDavid E. O'Brien /*
155c80476e4SDavid E. O'Brien * Glob the command name. We will search $path even if this does something,
156c80476e4SDavid E. O'Brien * as in sh but not in csh. One special case: if there is no PATH, then we
157c80476e4SDavid E. O'Brien * execute only commands which start with '/'.
158c80476e4SDavid E. O'Brien */
159c80476e4SDavid E. O'Brien blk[0] = t->t_dcom[0];
160c80476e4SDavid E. O'Brien blk[1] = 0;
16129301572SMark Peek gflag = 0;
16229301572SMark Peek if (do_glob)
16345e5710bSMark Peek gflag = tglob(blk);
164c80476e4SDavid E. O'Brien if (gflag) {
16545e5710bSMark Peek pv = globall(blk, gflag);
166c80476e4SDavid E. O'Brien if (pv == 0) {
167c80476e4SDavid E. O'Brien setname(short2str(blk[0]));
168c80476e4SDavid E. O'Brien stderror(ERR_NAME | ERR_NOMATCH);
169c80476e4SDavid E. O'Brien }
170c80476e4SDavid E. O'Brien }
171c80476e4SDavid E. O'Brien else
172c80476e4SDavid E. O'Brien pv = saveblk(blk);
17345e5710bSMark Peek cleanup_push(pv, blk_cleanup);
174c80476e4SDavid E. O'Brien
175c80476e4SDavid E. O'Brien trim(pv);
176c80476e4SDavid E. O'Brien
177c80476e4SDavid E. O'Brien exerr = 0;
178c80476e4SDavid E. O'Brien expath = Strsave(pv[0]);
179c80476e4SDavid E. O'Brien #ifdef VFORK
180c80476e4SDavid E. O'Brien Vexpath = expath;
181c80476e4SDavid E. O'Brien #endif /* VFORK */
182c80476e4SDavid E. O'Brien
183c80476e4SDavid E. O'Brien v = adrof(STRpath);
18445e5710bSMark Peek if (v == 0 && expath[0] != '/' && expath[0] != '.')
185c80476e4SDavid E. O'Brien pexerr();
186c80476e4SDavid E. O'Brien slash = any(short2str(expath), '/');
187c80476e4SDavid E. O'Brien
188c80476e4SDavid E. O'Brien /*
189c80476e4SDavid E. O'Brien * Glob the argument list, if necessary. Otherwise trim off the quote bits.
190c80476e4SDavid E. O'Brien */
191c80476e4SDavid E. O'Brien gflag = 0;
192c80476e4SDavid E. O'Brien av = &t->t_dcom[1];
19329301572SMark Peek if (do_glob)
19445e5710bSMark Peek gflag = tglob(av);
195c80476e4SDavid E. O'Brien if (gflag) {
19645e5710bSMark Peek av = globall(av, gflag);
197c80476e4SDavid E. O'Brien if (av == 0) {
198c80476e4SDavid E. O'Brien setname(short2str(expath));
199c80476e4SDavid E. O'Brien stderror(ERR_NAME | ERR_NOMATCH);
200c80476e4SDavid E. O'Brien }
201c80476e4SDavid E. O'Brien }
202c80476e4SDavid E. O'Brien else
203c80476e4SDavid E. O'Brien av = saveblk(av);
204c80476e4SDavid E. O'Brien
205c80476e4SDavid E. O'Brien blkfree(t->t_dcom);
20645e5710bSMark Peek cleanup_ignore(pv);
20745e5710bSMark Peek cleanup_until(pv);
208c80476e4SDavid E. O'Brien t->t_dcom = blkspl(pv, av);
20945e5710bSMark Peek xfree(pv);
21045e5710bSMark Peek xfree(av);
211c80476e4SDavid E. O'Brien av = t->t_dcom;
212c80476e4SDavid E. O'Brien trim(av);
213c80476e4SDavid E. O'Brien
214c80476e4SDavid E. O'Brien if (*av == NULL || **av == '\0')
215c80476e4SDavid E. O'Brien pexerr();
216c80476e4SDavid E. O'Brien
217c80476e4SDavid E. O'Brien xechoit(av); /* Echo command if -x */
218c80476e4SDavid E. O'Brien #ifdef CLOSE_ON_EXEC
219c80476e4SDavid E. O'Brien /*
220c80476e4SDavid E. O'Brien * Since all internal file descriptors are set to close on exec, we don't
221c80476e4SDavid E. O'Brien * need to close them explicitly here. Just reorient ourselves for error
222c80476e4SDavid E. O'Brien * messages.
223c80476e4SDavid E. O'Brien */
224c80476e4SDavid E. O'Brien SHIN = 0;
225c80476e4SDavid E. O'Brien SHOUT = 1;
226c80476e4SDavid E. O'Brien SHDIAG = 2;
227c80476e4SDavid E. O'Brien OLDSTD = 0;
228c80476e4SDavid E. O'Brien isoutatty = isatty(SHOUT);
229c80476e4SDavid E. O'Brien isdiagatty = isatty(SHDIAG);
230c80476e4SDavid E. O'Brien #else
231c80476e4SDavid E. O'Brien closech(); /* Close random fd's */
232c80476e4SDavid E. O'Brien #endif
233c80476e4SDavid E. O'Brien /*
234c80476e4SDavid E. O'Brien * We must do this AFTER any possible forking (like `foo` in glob) so that
235c80476e4SDavid E. O'Brien * this shell can still do subprocesses.
236c80476e4SDavid E. O'Brien */
23745e5710bSMark Peek {
23845e5710bSMark Peek sigset_t set;
23945e5710bSMark Peek sigemptyset(&set);
24045e5710bSMark Peek sigaddset(&set, SIGINT);
24145e5710bSMark Peek sigaddset(&set, SIGCHLD);
24245e5710bSMark Peek sigprocmask(SIG_UNBLOCK, &set, NULL);
24345e5710bSMark Peek }
24445e5710bSMark Peek pintr_disabled = 0;
24545e5710bSMark Peek pchild_disabled = 0;
246c80476e4SDavid E. O'Brien
247c80476e4SDavid E. O'Brien /*
248c80476e4SDavid E. O'Brien * If no path, no words in path, or a / in the filename then restrict the
249c80476e4SDavid E. O'Brien * command search.
250c80476e4SDavid E. O'Brien */
25129301572SMark Peek if (v == NULL || v->vec == NULL || v->vec[0] == NULL || slash)
2529ccc37e3SMark Peek opv = justabs;
253c80476e4SDavid E. O'Brien else
2549ccc37e3SMark Peek opv = v->vec;
255c80476e4SDavid E. O'Brien sav = Strspl(STRslash, *av);/* / command name for postpending */
25645e5710bSMark Peek #ifndef VFORK
25745e5710bSMark Peek cleanup_push(sav, xfree);
25845e5710bSMark Peek #else /* VFORK */
259c80476e4SDavid E. O'Brien Vsav = sav;
260c80476e4SDavid E. O'Brien #endif /* VFORK */
261c80476e4SDavid E. O'Brien hashval = havhash ? hashname(*av) : 0;
262c80476e4SDavid E. O'Brien
2639ccc37e3SMark Peek rehashed = 0;
2649ccc37e3SMark Peek retry:
2659ccc37e3SMark Peek pv = opv;
266c80476e4SDavid E. O'Brien i = 0;
267c80476e4SDavid E. O'Brien #ifdef VFORK
268c80476e4SDavid E. O'Brien hits++;
269c80476e4SDavid E. O'Brien #endif /* VFORK */
270c80476e4SDavid E. O'Brien do {
271c80476e4SDavid E. O'Brien /*
272c80476e4SDavid E. O'Brien * Try to save time by looking at the hash table for where this command
273c80476e4SDavid E. O'Brien * could be. If we are doing delayed hashing, then we put the names in
274c80476e4SDavid E. O'Brien * one at a time, as the user enters them. This is kinda like Korn
275c80476e4SDavid E. O'Brien * Shell's "tracked aliases".
276c80476e4SDavid E. O'Brien */
277c80476e4SDavid E. O'Brien if (!slash && ABSOLUTEP(pv[0]) && havhash) {
278c80476e4SDavid E. O'Brien #ifdef FASTHASH
279c80476e4SDavid E. O'Brien if (!bit(hashval, i))
280c80476e4SDavid E. O'Brien goto cont;
281c80476e4SDavid E. O'Brien #else /* OLDHASH */
282c80476e4SDavid E. O'Brien int hashval1 = hash(hashval, i);
283c80476e4SDavid E. O'Brien if (!bit(xhash, hashval1))
284c80476e4SDavid E. O'Brien goto cont;
285c80476e4SDavid E. O'Brien #endif /* FASTHASH */
286c80476e4SDavid E. O'Brien }
287c80476e4SDavid E. O'Brien if (pv[0][0] == 0 || eq(pv[0], STRdot)) /* don't make ./xxx */
288c80476e4SDavid E. O'Brien texec(*av, av);
289c80476e4SDavid E. O'Brien else {
290c80476e4SDavid E. O'Brien dp = Strspl(*pv, sav);
29145e5710bSMark Peek #ifndef VFORK
29245e5710bSMark Peek cleanup_push(dp, xfree);
29345e5710bSMark Peek #else /* VFORK */
294c80476e4SDavid E. O'Brien Vdp = dp;
295c80476e4SDavid E. O'Brien #endif /* VFORK */
296c80476e4SDavid E. O'Brien
297c80476e4SDavid E. O'Brien texec(dp, av);
29845e5710bSMark Peek #ifndef VFORK
29945e5710bSMark Peek cleanup_until(dp);
30045e5710bSMark Peek #else /* VFORK */
301c80476e4SDavid E. O'Brien Vdp = 0;
30245e5710bSMark Peek xfree(dp);
303c80476e4SDavid E. O'Brien #endif /* VFORK */
304c80476e4SDavid E. O'Brien }
305c80476e4SDavid E. O'Brien #ifdef VFORK
306c80476e4SDavid E. O'Brien misses++;
307c80476e4SDavid E. O'Brien #endif /* VFORK */
308c80476e4SDavid E. O'Brien cont:
309c80476e4SDavid E. O'Brien pv++;
310c80476e4SDavid E. O'Brien i++;
311c80476e4SDavid E. O'Brien } while (*pv);
312c80476e4SDavid E. O'Brien #ifdef VFORK
313c80476e4SDavid E. O'Brien hits--;
314c80476e4SDavid E. O'Brien #endif /* VFORK */
3159ccc37e3SMark Peek if (adrof(STRautorehash) && !rehashed && havhash && opv != justabs) {
3169ccc37e3SMark Peek dohash(NULL, NULL);
3179ccc37e3SMark Peek rehashed = 1;
3189ccc37e3SMark Peek goto retry;
3199ccc37e3SMark Peek }
32045e5710bSMark Peek #ifndef VFORK
32145e5710bSMark Peek cleanup_until(sav);
32245e5710bSMark Peek #else /* VFORK */
32345e5710bSMark Peek Vsav = 0;
32445e5710bSMark Peek xfree(sav);
32545e5710bSMark Peek #endif /* VFORK */
326c80476e4SDavid E. O'Brien pexerr();
327c80476e4SDavid E. O'Brien }
328c80476e4SDavid E. O'Brien
329c80476e4SDavid E. O'Brien static void
pexerr(void)33045e5710bSMark Peek pexerr(void)
331c80476e4SDavid E. O'Brien {
332c80476e4SDavid E. O'Brien /* Couldn't find the damn thing */
333c80476e4SDavid E. O'Brien if (expath) {
334c80476e4SDavid E. O'Brien setname(short2str(expath));
335c80476e4SDavid E. O'Brien #ifdef VFORK
336c80476e4SDavid E. O'Brien Vexpath = 0;
337c80476e4SDavid E. O'Brien #endif /* VFORK */
33845e5710bSMark Peek xfree(expath);
339c80476e4SDavid E. O'Brien expath = 0;
340c80476e4SDavid E. O'Brien }
341c80476e4SDavid E. O'Brien else
342c80476e4SDavid E. O'Brien setname("");
343c80476e4SDavid E. O'Brien if (exerr)
344c80476e4SDavid E. O'Brien stderror(ERR_NAME | ERR_STRING, exerr);
345c80476e4SDavid E. O'Brien stderror(ERR_NAME | ERR_COMMAND);
346c80476e4SDavid E. O'Brien }
347c80476e4SDavid E. O'Brien
348c80476e4SDavid E. O'Brien /*
349c80476e4SDavid E. O'Brien * Execute command f, arg list t.
350c80476e4SDavid E. O'Brien * Record error message if not found.
351c80476e4SDavid E. O'Brien * Also do shell scripts here.
352c80476e4SDavid E. O'Brien */
353c80476e4SDavid E. O'Brien static void
texec(Char * sf,Char ** st)35445e5710bSMark Peek texec(Char *sf, Char **st)
355c80476e4SDavid E. O'Brien {
35623338178SMark Peek char **t;
35723338178SMark Peek char *f;
35823338178SMark Peek struct varent *v;
359c80476e4SDavid E. O'Brien Char **vp;
360c80476e4SDavid E. O'Brien Char *lastsh[2];
361c80476e4SDavid E. O'Brien char pref[2];
362c80476e4SDavid E. O'Brien int fd;
363c80476e4SDavid E. O'Brien Char *st0, **ost;
364c80476e4SDavid E. O'Brien
365c80476e4SDavid E. O'Brien /* The order for the conversions is significant */
366c80476e4SDavid E. O'Brien t = short2blk(st);
367c80476e4SDavid E. O'Brien f = short2str(sf);
368c80476e4SDavid E. O'Brien #ifdef VFORK
369c80476e4SDavid E. O'Brien Vt = t;
370c80476e4SDavid E. O'Brien #endif /* VFORK */
371c80476e4SDavid E. O'Brien errno = 0; /* don't use a previous error */
372c80476e4SDavid E. O'Brien #ifdef apollo
373c80476e4SDavid E. O'Brien /*
374c80476e4SDavid E. O'Brien * If we try to execute an nfs mounted directory on the apollo, we
375c80476e4SDavid E. O'Brien * hang forever. So until apollo fixes that..
376c80476e4SDavid E. O'Brien */
377c80476e4SDavid E. O'Brien {
378c80476e4SDavid E. O'Brien struct stat stb;
379c80476e4SDavid E. O'Brien if (stat(f, &stb) == 0 && S_ISDIR(stb.st_mode))
380c80476e4SDavid E. O'Brien errno = EISDIR;
381c80476e4SDavid E. O'Brien }
382c80476e4SDavid E. O'Brien if (errno == 0)
383c80476e4SDavid E. O'Brien #endif /* apollo */
384c80476e4SDavid E. O'Brien {
385c80476e4SDavid E. O'Brien #ifdef ISC_POSIX_EXEC_BUG
386c80476e4SDavid E. O'Brien __setostype(0); /* "0" is "__OS_SYSV" in <sys/user.h> */
387c80476e4SDavid E. O'Brien #endif /* ISC_POSIX_EXEC_BUG */
388c80476e4SDavid E. O'Brien (void) execv(f, t);
389c80476e4SDavid E. O'Brien #ifdef ISC_POSIX_EXEC_BUG
390c80476e4SDavid E. O'Brien __setostype(1); /* "1" is "__OS_POSIX" in <sys/user.h> */
391c80476e4SDavid E. O'Brien #endif /* ISC_POSIX_EXEC_BUG */
392c80476e4SDavid E. O'Brien }
393c80476e4SDavid E. O'Brien #ifdef VFORK
394c80476e4SDavid E. O'Brien Vt = 0;
395c80476e4SDavid E. O'Brien #endif /* VFORK */
396c80476e4SDavid E. O'Brien blkfree((Char **) t);
397c80476e4SDavid E. O'Brien switch (errno) {
398c80476e4SDavid E. O'Brien
399c80476e4SDavid E. O'Brien case ENOEXEC:
4003b6eaa7bSAndrey A. Chernov #ifdef WINNT_NATIVE
401c80476e4SDavid E. O'Brien nt_feed_to_cmd(f,t);
4023b6eaa7bSAndrey A. Chernov #endif /* WINNT_NATIVE */
403c80476e4SDavid E. O'Brien /*
404c80476e4SDavid E. O'Brien * From: casper@fwi.uva.nl (Casper H.S. Dik) If we could not execute
405c80476e4SDavid E. O'Brien * it, don't feed it to the shell if it looks like a binary!
406c80476e4SDavid E. O'Brien */
40745e5710bSMark Peek if ((fd = xopen(f, O_RDONLY|O_LARGEFILE)) != -1) {
408c80476e4SDavid E. O'Brien int nread;
40945e5710bSMark Peek if ((nread = xread(fd, pref, 2)) == 2) {
41023338178SMark Peek if (!isprint((unsigned char)pref[0]) &&
41123338178SMark Peek (pref[0] != '\n' && pref[0] != '\t')) {
41245e5710bSMark Peek int err;
41345e5710bSMark Peek
41445e5710bSMark Peek err = errno;
41545e5710bSMark Peek xclose(fd);
416c80476e4SDavid E. O'Brien /*
417c80476e4SDavid E. O'Brien * We *know* what ENOEXEC means.
418c80476e4SDavid E. O'Brien */
41945e5710bSMark Peek stderror(ERR_ARCH, f, strerror(err));
420c80476e4SDavid E. O'Brien }
421c80476e4SDavid E. O'Brien }
42245e5710bSMark Peek else if (nread < 0) {
423c80476e4SDavid E. O'Brien #ifdef convex
42445e5710bSMark Peek int err;
42545e5710bSMark Peek
42645e5710bSMark Peek err = errno;
42745e5710bSMark Peek xclose(fd);
428c80476e4SDavid E. O'Brien /* need to print error incase the file is migrated */
42945e5710bSMark Peek stderror(ERR_SYSTEM, f, strerror(err));
430c80476e4SDavid E. O'Brien #endif
431c80476e4SDavid E. O'Brien }
432c80476e4SDavid E. O'Brien #ifdef _PATH_BSHELL
433c80476e4SDavid E. O'Brien else {
434c80476e4SDavid E. O'Brien pref[0] = '#';
435c80476e4SDavid E. O'Brien pref[1] = '\0';
436c80476e4SDavid E. O'Brien }
437c80476e4SDavid E. O'Brien #endif
438c80476e4SDavid E. O'Brien }
439c80476e4SDavid E. O'Brien #ifdef HASHBANG
440c80476e4SDavid E. O'Brien if (fd == -1 ||
441c80476e4SDavid E. O'Brien pref[0] != '#' || pref[1] != '!' || hashbang(fd, &vp) == -1) {
442c80476e4SDavid E. O'Brien #endif /* HASHBANG */
443c80476e4SDavid E. O'Brien /*
444c80476e4SDavid E. O'Brien * If there is an alias for shell, then put the words of the alias in
445c80476e4SDavid E. O'Brien * front of the argument list replacing the command name. Note no
446c80476e4SDavid E. O'Brien * interpretation of the words at this point.
447c80476e4SDavid E. O'Brien */
448c80476e4SDavid E. O'Brien v = adrof1(STRshell, &aliases);
44929301572SMark Peek if (v == NULL || v->vec == NULL) {
450c80476e4SDavid E. O'Brien vp = lastsh;
451c80476e4SDavid E. O'Brien vp[0] = adrof(STRshell) ? varval(STRshell) : STR_SHELLPATH;
452c80476e4SDavid E. O'Brien vp[1] = NULL;
453c80476e4SDavid E. O'Brien #ifdef _PATH_BSHELL
454c80476e4SDavid E. O'Brien if (fd != -1
455c80476e4SDavid E. O'Brien # ifndef ISC /* Compatible with ISC's /bin/csh */
456c80476e4SDavid E. O'Brien && pref[0] != '#'
457c80476e4SDavid E. O'Brien # endif /* ISC */
458c80476e4SDavid E. O'Brien )
459c80476e4SDavid E. O'Brien vp[0] = STR_BSHELL;
460c80476e4SDavid E. O'Brien #endif
461c80476e4SDavid E. O'Brien vp = saveblk(vp);
462c80476e4SDavid E. O'Brien }
463c80476e4SDavid E. O'Brien else
464c80476e4SDavid E. O'Brien vp = saveblk(v->vec);
465c80476e4SDavid E. O'Brien #ifdef HASHBANG
466c80476e4SDavid E. O'Brien }
467c80476e4SDavid E. O'Brien #endif /* HASHBANG */
468c80476e4SDavid E. O'Brien if (fd != -1)
46945e5710bSMark Peek xclose(fd);
470c80476e4SDavid E. O'Brien
471c80476e4SDavid E. O'Brien st0 = st[0];
472c80476e4SDavid E. O'Brien st[0] = sf;
473c80476e4SDavid E. O'Brien ost = st;
474c80476e4SDavid E. O'Brien st = blkspl(vp, st); /* Splice up the new arglst */
475c80476e4SDavid E. O'Brien ost[0] = st0;
476c80476e4SDavid E. O'Brien sf = *st;
477c80476e4SDavid E. O'Brien /* The order for the conversions is significant */
478c80476e4SDavid E. O'Brien t = short2blk(st);
479c80476e4SDavid E. O'Brien f = short2str(sf);
48045e5710bSMark Peek xfree(st);
481c80476e4SDavid E. O'Brien blkfree((Char **) vp);
482c80476e4SDavid E. O'Brien #ifdef VFORK
483c80476e4SDavid E. O'Brien Vt = t;
484c80476e4SDavid E. O'Brien #endif /* VFORK */
485c80476e4SDavid E. O'Brien #ifdef ISC_POSIX_EXEC_BUG
486c80476e4SDavid E. O'Brien __setostype(0); /* "0" is "__OS_SYSV" in <sys/user.h> */
487c80476e4SDavid E. O'Brien #endif /* ISC_POSIX_EXEC_BUG */
488c80476e4SDavid E. O'Brien (void) execv(f, t);
489c80476e4SDavid E. O'Brien #ifdef ISC_POSIX_EXEC_BUG
490c80476e4SDavid E. O'Brien __setostype(1); /* "1" is "__OS_POSIX" in <sys/user.h> */
491c80476e4SDavid E. O'Brien #endif /* ISC_POSIX_EXEC_BUG */
492c80476e4SDavid E. O'Brien #ifdef VFORK
493c80476e4SDavid E. O'Brien Vt = 0;
494c80476e4SDavid E. O'Brien #endif /* VFORK */
495c80476e4SDavid E. O'Brien blkfree((Char **) t);
496c80476e4SDavid E. O'Brien /* The sky is falling, the sky is falling! */
497c80476e4SDavid E. O'Brien stderror(ERR_SYSTEM, f, strerror(errno));
498c80476e4SDavid E. O'Brien break;
499c80476e4SDavid E. O'Brien
500c80476e4SDavid E. O'Brien case ENOMEM:
501c80476e4SDavid E. O'Brien stderror(ERR_SYSTEM, f, strerror(errno));
502c80476e4SDavid E. O'Brien break;
503c80476e4SDavid E. O'Brien
504c80476e4SDavid E. O'Brien #ifdef _IBMR2
505c80476e4SDavid E. O'Brien case 0: /* execv fails and returns 0! */
506c80476e4SDavid E. O'Brien #endif /* _IBMR2 */
507c80476e4SDavid E. O'Brien case ENOENT:
508c80476e4SDavid E. O'Brien break;
509c80476e4SDavid E. O'Brien
510c80476e4SDavid E. O'Brien default:
511c80476e4SDavid E. O'Brien if (exerr == 0) {
512c80476e4SDavid E. O'Brien exerr = strerror(errno);
51345e5710bSMark Peek xfree(expath);
514c80476e4SDavid E. O'Brien expath = Strsave(sf);
515c80476e4SDavid E. O'Brien #ifdef VFORK
516c80476e4SDavid E. O'Brien Vexpath = expath;
517c80476e4SDavid E. O'Brien #endif /* VFORK */
518c80476e4SDavid E. O'Brien }
519c80476e4SDavid E. O'Brien break;
520c80476e4SDavid E. O'Brien }
521c80476e4SDavid E. O'Brien }
522c80476e4SDavid E. O'Brien
52345e5710bSMark Peek struct execash_state
524c80476e4SDavid E. O'Brien {
525c80476e4SDavid E. O'Brien int saveIN, saveOUT, saveDIAG, saveSTD;
52645e5710bSMark Peek int SHIN, SHOUT, SHDIAG, OLDSTD;
52745e5710bSMark Peek int didfds;
528c80476e4SDavid E. O'Brien #ifndef CLOSE_ON_EXEC
52945e5710bSMark Peek int didcch;
53045e5710bSMark Peek #endif
53145e5710bSMark Peek struct sigaction sigint, sigquit, sigterm;
53245e5710bSMark Peek };
53345e5710bSMark Peek
53445e5710bSMark Peek static void
execash_cleanup(void * xstate)53545e5710bSMark Peek execash_cleanup(void *xstate)
53645e5710bSMark Peek {
53745e5710bSMark Peek struct execash_state *state;
53845e5710bSMark Peek
53945e5710bSMark Peek state = xstate;
54045e5710bSMark Peek sigaction(SIGINT, &state->sigint, NULL);
54145e5710bSMark Peek sigaction(SIGQUIT, &state->sigquit, NULL);
54245e5710bSMark Peek sigaction(SIGTERM, &state->sigterm, NULL);
54345e5710bSMark Peek
54445e5710bSMark Peek doneinp = 0;
54545e5710bSMark Peek #ifndef CLOSE_ON_EXEC
54645e5710bSMark Peek didcch = state->didcch;
547c80476e4SDavid E. O'Brien #endif /* CLOSE_ON_EXEC */
54845e5710bSMark Peek didfds = state->didfds;
54945e5710bSMark Peek xclose(SHIN);
55045e5710bSMark Peek xclose(SHOUT);
55145e5710bSMark Peek xclose(SHDIAG);
55245e5710bSMark Peek xclose(OLDSTD);
55345e5710bSMark Peek close_on_exec(SHIN = dmove(state->saveIN, state->SHIN), 1);
55445e5710bSMark Peek close_on_exec(SHOUT = dmove(state->saveOUT, state->SHOUT), 1);
55545e5710bSMark Peek close_on_exec(SHDIAG = dmove(state->saveDIAG, state->SHDIAG), 1);
55645e5710bSMark Peek close_on_exec(OLDSTD = dmove(state->saveSTD, state->OLDSTD), 1);
55745e5710bSMark Peek }
55845e5710bSMark Peek
55945e5710bSMark Peek /*ARGSUSED*/
56045e5710bSMark Peek void
execash(Char ** t,struct command * kp)56145e5710bSMark Peek execash(Char **t, struct command *kp)
56245e5710bSMark Peek {
56345e5710bSMark Peek struct execash_state state;
564c80476e4SDavid E. O'Brien
565c80476e4SDavid E. O'Brien USE(t);
566c80476e4SDavid E. O'Brien if (chkstop == 0 && setintr)
567c80476e4SDavid E. O'Brien panystop(0);
568c80476e4SDavid E. O'Brien /*
569c80476e4SDavid E. O'Brien * Hmm, we don't really want to do that now because we might
570c80476e4SDavid E. O'Brien * fail, but what is the choice
571c80476e4SDavid E. O'Brien */
572c80476e4SDavid E. O'Brien rechist(NULL, adrof(STRsavehist) != NULL);
573c80476e4SDavid E. O'Brien
574c80476e4SDavid E. O'Brien
57545e5710bSMark Peek sigaction(SIGINT, &parintr, &state.sigint);
57645e5710bSMark Peek sigaction(SIGQUIT, &parintr, &state.sigquit);
57745e5710bSMark Peek sigaction(SIGTERM, &parterm, &state.sigterm);
578c80476e4SDavid E. O'Brien
57945e5710bSMark Peek state.didfds = didfds;
580c80476e4SDavid E. O'Brien #ifndef CLOSE_ON_EXEC
58145e5710bSMark Peek state.didcch = didcch;
582c80476e4SDavid E. O'Brien #endif /* CLOSE_ON_EXEC */
58345e5710bSMark Peek state.SHIN = SHIN;
58445e5710bSMark Peek state.SHOUT = SHOUT;
58545e5710bSMark Peek state.SHDIAG = SHDIAG;
58645e5710bSMark Peek state.OLDSTD = OLDSTD;
587c80476e4SDavid E. O'Brien
58845e5710bSMark Peek (void)close_on_exec (state.saveIN = dcopy(SHIN, -1), 1);
58945e5710bSMark Peek (void)close_on_exec (state.saveOUT = dcopy(SHOUT, -1), 1);
59045e5710bSMark Peek (void)close_on_exec (state.saveDIAG = dcopy(SHDIAG, -1), 1);
59145e5710bSMark Peek (void)close_on_exec (state.saveSTD = dcopy(OLDSTD, -1), 1);
592c80476e4SDavid E. O'Brien
593c80476e4SDavid E. O'Brien lshift(kp->t_dcom, 1);
594c80476e4SDavid E. O'Brien
59523338178SMark Peek (void)close_on_exec (SHIN = dcopy(0, -1), 1);
59623338178SMark Peek (void)close_on_exec (SHOUT = dcopy(1, -1), 1);
59723338178SMark Peek (void)close_on_exec (SHDIAG = dcopy(2, -1), 1);
598c80476e4SDavid E. O'Brien #ifndef CLOSE_ON_EXEC
599c80476e4SDavid E. O'Brien didcch = 0;
600c80476e4SDavid E. O'Brien #endif /* CLOSE_ON_EXEC */
601c80476e4SDavid E. O'Brien didfds = 0;
60245e5710bSMark Peek cleanup_push(&state, execash_cleanup);
60345e5710bSMark Peek
604c80476e4SDavid E. O'Brien /*
605*19d2e3deSDmitry Chagin * Decrement the shell level, if not in a subshell
606c80476e4SDavid E. O'Brien */
607*19d2e3deSDmitry Chagin if (mainpid == getpid())
608c80476e4SDavid E. O'Brien shlvl(-1);
6093b6eaa7bSAndrey A. Chernov #ifdef WINNT_NATIVE
610c80476e4SDavid E. O'Brien __nt_really_exec=1;
6113b6eaa7bSAndrey A. Chernov #endif /* WINNT_NATIVE */
61229301572SMark Peek doexec(kp, 1);
613c80476e4SDavid E. O'Brien
61445e5710bSMark Peek cleanup_until(&state);
615c80476e4SDavid E. O'Brien }
616c80476e4SDavid E. O'Brien
617c80476e4SDavid E. O'Brien void
xechoit(Char ** t)61845e5710bSMark Peek xechoit(Char **t)
619c80476e4SDavid E. O'Brien {
620c80476e4SDavid E. O'Brien if (adrof(STRecho)) {
62129301572SMark Peek int odidfds = didfds;
622c80476e4SDavid E. O'Brien flush();
623c80476e4SDavid E. O'Brien haderr = 1;
62429301572SMark Peek didfds = 0;
625c80476e4SDavid E. O'Brien blkpr(t), xputchar('\n');
62629301572SMark Peek flush();
62729301572SMark Peek didfds = odidfds;
628c80476e4SDavid E. O'Brien haderr = 0;
629c80476e4SDavid E. O'Brien }
630c80476e4SDavid E. O'Brien }
631c80476e4SDavid E. O'Brien
632c80476e4SDavid E. O'Brien /*ARGSUSED*/
633c80476e4SDavid E. O'Brien void
dohash(Char ** vv,struct command * c)63445e5710bSMark Peek dohash(Char **vv, struct command *c)
635c80476e4SDavid E. O'Brien {
636c80476e4SDavid E. O'Brien #ifdef COMMENT
637c80476e4SDavid E. O'Brien struct stat stb;
638c80476e4SDavid E. O'Brien #endif
639c80476e4SDavid E. O'Brien DIR *dirp;
64023338178SMark Peek struct dirent *dp;
641c80476e4SDavid E. O'Brien int i = 0;
642c80476e4SDavid E. O'Brien struct varent *v = adrof(STRpath);
643c80476e4SDavid E. O'Brien Char **pv;
644c80476e4SDavid E. O'Brien int hashval;
6453b6eaa7bSAndrey A. Chernov #ifdef WINNT_NATIVE
646c80476e4SDavid E. O'Brien int is_windir; /* check if it is the windows directory */
647c80476e4SDavid E. O'Brien USE(hashval);
6483b6eaa7bSAndrey A. Chernov #endif /* WINNT_NATIVE */
649c80476e4SDavid E. O'Brien
650c80476e4SDavid E. O'Brien USE(c);
651c80476e4SDavid E. O'Brien #ifdef FASTHASH
652c80476e4SDavid E. O'Brien if (vv && vv[1]) {
653c80476e4SDavid E. O'Brien uhashlength = atoi(short2str(vv[1]));
654c80476e4SDavid E. O'Brien if (vv[2]) {
655c80476e4SDavid E. O'Brien uhashwidth = atoi(short2str(vv[2]));
656c80476e4SDavid E. O'Brien if ((uhashwidth != sizeof(unsigned char)) &&
657c80476e4SDavid E. O'Brien (uhashwidth != sizeof(unsigned short)) &&
658c80476e4SDavid E. O'Brien (uhashwidth != sizeof(unsigned long)))
659c80476e4SDavid E. O'Brien uhashwidth = 0;
660c80476e4SDavid E. O'Brien if (vv[3])
661c80476e4SDavid E. O'Brien hashdebug = atoi(short2str(vv[3]));
662c80476e4SDavid E. O'Brien }
663c80476e4SDavid E. O'Brien }
664c80476e4SDavid E. O'Brien
665c80476e4SDavid E. O'Brien if (uhashwidth)
666c80476e4SDavid E. O'Brien hashwidth = uhashwidth;
667c80476e4SDavid E. O'Brien else {
668c80476e4SDavid E. O'Brien hashwidth = 0;
6693b6eaa7bSAndrey A. Chernov if (v == NULL)
6703b6eaa7bSAndrey A. Chernov return;
67129301572SMark Peek for (pv = v->vec; pv && *pv; pv++, hashwidth++)
672c80476e4SDavid E. O'Brien continue;
673c80476e4SDavid E. O'Brien if (hashwidth <= widthof(unsigned char))
674c80476e4SDavid E. O'Brien hashwidth = sizeof(unsigned char);
675c80476e4SDavid E. O'Brien else if (hashwidth <= widthof(unsigned short))
676c80476e4SDavid E. O'Brien hashwidth = sizeof(unsigned short);
677c80476e4SDavid E. O'Brien else if (hashwidth <= widthof(unsigned int))
678c80476e4SDavid E. O'Brien hashwidth = sizeof(unsigned int);
679c80476e4SDavid E. O'Brien else
680c80476e4SDavid E. O'Brien hashwidth = sizeof(unsigned long);
681c80476e4SDavid E. O'Brien }
682c80476e4SDavid E. O'Brien
683c80476e4SDavid E. O'Brien if (uhashlength)
684c80476e4SDavid E. O'Brien hashlength = uhashlength;
685c80476e4SDavid E. O'Brien else
686c80476e4SDavid E. O'Brien hashlength = hashwidth * (8*64);/* "average" files per dir in path */
687c80476e4SDavid E. O'Brien
68845e5710bSMark Peek xfree(xhash);
68945e5710bSMark Peek xhash = xcalloc(hashlength * hashwidth, 1);
690c80476e4SDavid E. O'Brien #endif /* FASTHASH */
691c80476e4SDavid E. O'Brien
692c80476e4SDavid E. O'Brien (void) getusername(NULL); /* flush the tilde cashe */
693c80476e4SDavid E. O'Brien tw_cmd_free();
694c80476e4SDavid E. O'Brien havhash = 1;
695c80476e4SDavid E. O'Brien if (v == NULL)
696c80476e4SDavid E. O'Brien return;
69729301572SMark Peek for (pv = v->vec; pv && *pv; pv++, i++) {
698c80476e4SDavid E. O'Brien if (!ABSOLUTEP(pv[0]))
699c80476e4SDavid E. O'Brien continue;
700c80476e4SDavid E. O'Brien dirp = opendir(short2str(*pv));
701c80476e4SDavid E. O'Brien if (dirp == NULL)
702c80476e4SDavid E. O'Brien continue;
70345e5710bSMark Peek cleanup_push(dirp, opendir_cleanup);
704c80476e4SDavid E. O'Brien #ifdef COMMENT /* this isn't needed. opendir won't open
705c80476e4SDavid E. O'Brien * non-dirs */
706c80476e4SDavid E. O'Brien if (fstat(dirp->dd_fd, &stb) < 0 || !S_ISDIR(stb.st_mode)) {
70745e5710bSMark Peek cleanup_until(dirp);
708c80476e4SDavid E. O'Brien continue;
709c80476e4SDavid E. O'Brien }
710c80476e4SDavid E. O'Brien #endif
7113b6eaa7bSAndrey A. Chernov #ifdef WINNT_NATIVE
712c80476e4SDavid E. O'Brien is_windir = nt_check_if_windir(short2str(*pv));
7133b6eaa7bSAndrey A. Chernov #endif /* WINNT_NATIVE */
714c80476e4SDavid E. O'Brien while ((dp = readdir(dirp)) != NULL) {
715c80476e4SDavid E. O'Brien if (dp->d_ino == 0)
716c80476e4SDavid E. O'Brien continue;
717c80476e4SDavid E. O'Brien if (dp->d_name[0] == '.' &&
718c80476e4SDavid E. O'Brien (dp->d_name[1] == '\0' ||
719c80476e4SDavid E. O'Brien (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
720c80476e4SDavid E. O'Brien continue;
7213b6eaa7bSAndrey A. Chernov #ifdef WINNT_NATIVE
722c80476e4SDavid E. O'Brien nt_check_name_and_hash(is_windir, dp->d_name, i);
7233b6eaa7bSAndrey A. Chernov #else /* !WINNT_NATIVE*/
7243b6eaa7bSAndrey A. Chernov #if defined(_UWIN) || defined(__CYGWIN__)
725c80476e4SDavid E. O'Brien /* Turn foo.{exe,com,bat} into foo since UWIN's readdir returns
726c80476e4SDavid E. O'Brien * the file with the .exe, .com, .bat extension
7279ccc37e3SMark Peek *
7289ccc37e3SMark Peek * Same for Cygwin, but only for .exe and .com extension.
729c80476e4SDavid E. O'Brien */
730c80476e4SDavid E. O'Brien {
73145e5710bSMark Peek ssize_t ext = strlen(dp->d_name) - 4;
732b2d5d167SMark Peek if ((ext > 0) && (strcasecmp(&dp->d_name[ext], ".exe") == 0 ||
7339ccc37e3SMark Peek #ifndef __CYGWIN__
734b2d5d167SMark Peek strcasecmp(&dp->d_name[ext], ".bat") == 0 ||
7359ccc37e3SMark Peek #endif
73645e5710bSMark Peek strcasecmp(&dp->d_name[ext], ".com") == 0)) {
73745e5710bSMark Peek #ifdef __CYGWIN__
73845e5710bSMark Peek /* Also store the variation with extension. */
73945e5710bSMark Peek hashval = hashname(str2short(dp->d_name));
74045e5710bSMark Peek bis(hashval, i);
741b2d5d167SMark Peek #endif /* __CYGWIN__ */
74245e5710bSMark Peek dp->d_name[ext] = '\0';
743b2d5d167SMark Peek }
744c80476e4SDavid E. O'Brien }
7453b6eaa7bSAndrey A. Chernov #endif /* _UWIN || __CYGWIN__ */
746c80476e4SDavid E. O'Brien # ifdef FASTHASH
747c80476e4SDavid E. O'Brien hashval = hashname(str2short(dp->d_name));
748c80476e4SDavid E. O'Brien bis(hashval, i);
749c80476e4SDavid E. O'Brien if (hashdebug & 1)
750c80476e4SDavid E. O'Brien xprintf(CGETS(13, 1, "hash=%-4d dir=%-2d prog=%s\n"),
751c80476e4SDavid E. O'Brien hashname(str2short(dp->d_name)), i, dp->d_name);
752c80476e4SDavid E. O'Brien # else /* OLD HASH */
753c80476e4SDavid E. O'Brien hashval = hash(hashname(str2short(dp->d_name)), i);
754c80476e4SDavid E. O'Brien bis(xhash, hashval);
755c80476e4SDavid E. O'Brien # endif /* FASTHASH */
756c80476e4SDavid E. O'Brien /* tw_add_comm_name (dp->d_name); */
7573b6eaa7bSAndrey A. Chernov #endif /* WINNT_NATIVE */
758c80476e4SDavid E. O'Brien }
75945e5710bSMark Peek cleanup_until(dirp);
760c80476e4SDavid E. O'Brien }
761c80476e4SDavid E. O'Brien }
762c80476e4SDavid E. O'Brien
763c80476e4SDavid E. O'Brien /*ARGSUSED*/
764c80476e4SDavid E. O'Brien void
dounhash(Char ** v,struct command * c)76545e5710bSMark Peek dounhash(Char **v, struct command *c)
766c80476e4SDavid E. O'Brien {
767c80476e4SDavid E. O'Brien USE(c);
768c80476e4SDavid E. O'Brien USE(v);
769c80476e4SDavid E. O'Brien havhash = 0;
770c80476e4SDavid E. O'Brien #ifdef FASTHASH
77145e5710bSMark Peek xfree(xhash);
772c80476e4SDavid E. O'Brien xhash = NULL;
773c80476e4SDavid E. O'Brien #endif /* FASTHASH */
774c80476e4SDavid E. O'Brien }
775c80476e4SDavid E. O'Brien
776c80476e4SDavid E. O'Brien /*ARGSUSED*/
777c80476e4SDavid E. O'Brien void
hashstat(Char ** v,struct command * c)77845e5710bSMark Peek hashstat(Char **v, struct command *c)
779c80476e4SDavid E. O'Brien {
780c80476e4SDavid E. O'Brien USE(c);
781c80476e4SDavid E. O'Brien USE(v);
782c80476e4SDavid E. O'Brien #ifdef FASTHASH
783c80476e4SDavid E. O'Brien if (havhash && hashlength && hashwidth)
784c80476e4SDavid E. O'Brien xprintf(CGETS(13, 2, "%d hash buckets of %d bits each\n"),
785c80476e4SDavid E. O'Brien hashlength, hashwidth*8);
786c80476e4SDavid E. O'Brien if (hashdebug)
787c80476e4SDavid E. O'Brien xprintf(CGETS(13, 3, "debug mask = 0x%08x\n"), hashdebug);
788c80476e4SDavid E. O'Brien #endif /* FASTHASH */
789c80476e4SDavid E. O'Brien #ifdef VFORK
790c80476e4SDavid E. O'Brien if (hits + misses)
791c80476e4SDavid E. O'Brien xprintf(CGETS(13, 4, "%d hits, %d misses, %d%%\n"),
792c80476e4SDavid E. O'Brien hits, misses, 100 * hits / (hits + misses));
793c80476e4SDavid E. O'Brien #endif
794c80476e4SDavid E. O'Brien }
795c80476e4SDavid E. O'Brien
796c80476e4SDavid E. O'Brien
797c80476e4SDavid E. O'Brien /*
798c80476e4SDavid E. O'Brien * Hash a command name.
799c80476e4SDavid E. O'Brien */
8003b6eaa7bSAndrey A. Chernov int
hashname(Char * cp)80145e5710bSMark Peek hashname(Char *cp)
802c80476e4SDavid E. O'Brien {
80323338178SMark Peek unsigned long h;
804c80476e4SDavid E. O'Brien
805c80476e4SDavid E. O'Brien for (h = 0; *cp; cp++)
806c80476e4SDavid E. O'Brien h = hash(h, *cp);
807c80476e4SDavid E. O'Brien return ((int) h);
808c80476e4SDavid E. O'Brien }
809c80476e4SDavid E. O'Brien
810c80476e4SDavid E. O'Brien static int
iscommand(Char * name)81145e5710bSMark Peek iscommand(Char *name)
812c80476e4SDavid E. O'Brien {
8139ccc37e3SMark Peek Char **opv, **pv;
81423338178SMark Peek Char *sav;
81523338178SMark Peek struct varent *v;
81623338178SMark Peek int slash = any(short2str(name), '/');
8179ccc37e3SMark Peek int hashval, rehashed, i;
818c80476e4SDavid E. O'Brien
819c80476e4SDavid E. O'Brien v = adrof(STRpath);
82029301572SMark Peek if (v == NULL || v->vec == NULL || v->vec[0] == NULL || slash)
8219ccc37e3SMark Peek opv = justabs;
822c80476e4SDavid E. O'Brien else
8239ccc37e3SMark Peek opv = v->vec;
824c80476e4SDavid E. O'Brien sav = Strspl(STRslash, name); /* / command name for postpending */
825c80476e4SDavid E. O'Brien hashval = havhash ? hashname(name) : 0;
8269ccc37e3SMark Peek
8279ccc37e3SMark Peek rehashed = 0;
8289ccc37e3SMark Peek retry:
8299ccc37e3SMark Peek pv = opv;
830c80476e4SDavid E. O'Brien i = 0;
831c80476e4SDavid E. O'Brien do {
832c80476e4SDavid E. O'Brien if (!slash && ABSOLUTEP(pv[0]) && havhash) {
833c80476e4SDavid E. O'Brien #ifdef FASTHASH
834c80476e4SDavid E. O'Brien if (!bit(hashval, i))
835c80476e4SDavid E. O'Brien goto cont;
836c80476e4SDavid E. O'Brien #else /* OLDHASH */
837c80476e4SDavid E. O'Brien int hashval1 = hash(hashval, i);
838c80476e4SDavid E. O'Brien if (!bit(xhash, hashval1))
839c80476e4SDavid E. O'Brien goto cont;
840c80476e4SDavid E. O'Brien #endif /* FASTHASH */
841c80476e4SDavid E. O'Brien }
842c80476e4SDavid E. O'Brien if (pv[0][0] == 0 || eq(pv[0], STRdot)) { /* don't make ./xxx */
843c80476e4SDavid E. O'Brien if (executable(NULL, name, 0)) {
84445e5710bSMark Peek xfree(sav);
845c80476e4SDavid E. O'Brien return i + 1;
846c80476e4SDavid E. O'Brien }
847c80476e4SDavid E. O'Brien }
848c80476e4SDavid E. O'Brien else {
849c80476e4SDavid E. O'Brien if (executable(*pv, sav, 0)) {
85045e5710bSMark Peek xfree(sav);
851c80476e4SDavid E. O'Brien return i + 1;
852c80476e4SDavid E. O'Brien }
853c80476e4SDavid E. O'Brien }
854c80476e4SDavid E. O'Brien cont:
855c80476e4SDavid E. O'Brien pv++;
856c80476e4SDavid E. O'Brien i++;
857c80476e4SDavid E. O'Brien } while (*pv);
8589ccc37e3SMark Peek if (adrof(STRautorehash) && !rehashed && havhash && opv != justabs) {
8599ccc37e3SMark Peek dohash(NULL, NULL);
8609ccc37e3SMark Peek rehashed = 1;
8619ccc37e3SMark Peek goto retry;
8629ccc37e3SMark Peek }
86345e5710bSMark Peek xfree(sav);
864c80476e4SDavid E. O'Brien return 0;
865c80476e4SDavid E. O'Brien }
866c80476e4SDavid E. O'Brien
867c80476e4SDavid E. O'Brien /* Also by:
868c80476e4SDavid E. O'Brien * Andreas Luik <luik@isaak.isa.de>
869c80476e4SDavid E. O'Brien * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung
870c80476e4SDavid E. O'Brien * Azenberstr. 35
871c80476e4SDavid E. O'Brien * D-7000 Stuttgart 1
872c80476e4SDavid E. O'Brien * West-Germany
873c80476e4SDavid E. O'Brien * is the executable() routine below and changes to iscommand().
874c80476e4SDavid E. O'Brien * Thanks again!!
875c80476e4SDavid E. O'Brien */
876c80476e4SDavid E. O'Brien
8773b6eaa7bSAndrey A. Chernov #ifndef WINNT_NATIVE
878c80476e4SDavid E. O'Brien /*
879c80476e4SDavid E. O'Brien * executable() examines the pathname obtained by concatenating dir and name
880c80476e4SDavid E. O'Brien * (dir may be NULL), and returns 1 either if it is executable by us, or
881c80476e4SDavid E. O'Brien * if dir_ok is set and the pathname refers to a directory.
882c80476e4SDavid E. O'Brien * This is a bit kludgy, but in the name of optimization...
883c80476e4SDavid E. O'Brien */
884c80476e4SDavid E. O'Brien int
executable(const Char * dir,const Char * name,int dir_ok)88545e5710bSMark Peek executable(const Char *dir, const Char *name, int dir_ok)
886c80476e4SDavid E. O'Brien {
887c80476e4SDavid E. O'Brien struct stat stbuf;
888c80476e4SDavid E. O'Brien char *strname;
889c80476e4SDavid E. O'Brien
890c80476e4SDavid E. O'Brien if (dir && *dir) {
89145e5710bSMark Peek Char *path;
89245e5710bSMark Peek
89345e5710bSMark Peek path = Strspl(dir, name);
894c80476e4SDavid E. O'Brien strname = short2str(path);
89545e5710bSMark Peek xfree(path);
896c80476e4SDavid E. O'Brien }
897c80476e4SDavid E. O'Brien else
898c80476e4SDavid E. O'Brien strname = short2str(name);
899c80476e4SDavid E. O'Brien
900c80476e4SDavid E. O'Brien return (stat(strname, &stbuf) != -1 &&
901c80476e4SDavid E. O'Brien ((dir_ok && S_ISDIR(stbuf.st_mode)) ||
902c80476e4SDavid E. O'Brien (S_ISREG(stbuf.st_mode) &&
903c80476e4SDavid E. O'Brien /* save time by not calling access() in the hopeless case */
904c80476e4SDavid E. O'Brien (stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) &&
905c80476e4SDavid E. O'Brien access(strname, X_OK) == 0
906c80476e4SDavid E. O'Brien )));
907c80476e4SDavid E. O'Brien }
9083b6eaa7bSAndrey A. Chernov #endif /*!WINNT_NATIVE*/
909c80476e4SDavid E. O'Brien
91045e5710bSMark Peek struct tellmewhat_s0_cleanup
911c80476e4SDavid E. O'Brien {
91245e5710bSMark Peek Char **dest, *val;
91345e5710bSMark Peek };
91445e5710bSMark Peek
91545e5710bSMark Peek static void
tellmewhat_s0_cleanup(void * xstate)91645e5710bSMark Peek tellmewhat_s0_cleanup(void *xstate)
91745e5710bSMark Peek {
91845e5710bSMark Peek struct tellmewhat_s0_cleanup *state;
91945e5710bSMark Peek
92045e5710bSMark Peek state = xstate;
92145e5710bSMark Peek *state->dest = state->val;
92245e5710bSMark Peek }
92345e5710bSMark Peek
92445e5710bSMark Peek int
tellmewhat(struct wordent * lexp,Char ** str)92545e5710bSMark Peek tellmewhat(struct wordent *lexp, Char **str)
92645e5710bSMark Peek {
92745e5710bSMark Peek struct tellmewhat_s0_cleanup s0;
92823338178SMark Peek int i;
92945e5710bSMark Peek const struct biltins *bptr;
93023338178SMark Peek struct wordent *sp = lexp->next;
93123338178SMark Peek int aliased = 0, found;
93245e5710bSMark Peek Char *s1, *s2, *cmd;
933c80476e4SDavid E. O'Brien Char qc;
934c80476e4SDavid E. O'Brien
935c80476e4SDavid E. O'Brien if (adrof1(sp->word, &aliases)) {
936c80476e4SDavid E. O'Brien alias(lexp);
937c80476e4SDavid E. O'Brien sp = lexp->next;
938c80476e4SDavid E. O'Brien aliased = 1;
939c80476e4SDavid E. O'Brien }
940c80476e4SDavid E. O'Brien
94145e5710bSMark Peek s0.dest = &sp->word; /* to get the memory freeing right... */
94245e5710bSMark Peek s0.val = sp->word;
94345e5710bSMark Peek cleanup_push(&s0, tellmewhat_s0_cleanup);
944c80476e4SDavid E. O'Brien
945c80476e4SDavid E. O'Brien /* handle quoted alias hack */
946c80476e4SDavid E. O'Brien if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE)
947c80476e4SDavid E. O'Brien (sp->word)++;
948c80476e4SDavid E. O'Brien
949c80476e4SDavid E. O'Brien /* do quoting, if it hasn't been done */
950c80476e4SDavid E. O'Brien s1 = s2 = sp->word;
951c80476e4SDavid E. O'Brien while (*s2)
952c80476e4SDavid E. O'Brien switch (*s2) {
953c80476e4SDavid E. O'Brien case '\'':
954c80476e4SDavid E. O'Brien case '"':
955c80476e4SDavid E. O'Brien qc = *s2++;
956c80476e4SDavid E. O'Brien while (*s2 && *s2 != qc)
957c80476e4SDavid E. O'Brien *s1++ = *s2++ | QUOTE;
958c80476e4SDavid E. O'Brien if (*s2)
959c80476e4SDavid E. O'Brien s2++;
960c80476e4SDavid E. O'Brien break;
961c80476e4SDavid E. O'Brien case '\\':
962c80476e4SDavid E. O'Brien if (*++s2)
963c80476e4SDavid E. O'Brien *s1++ = *s2++ | QUOTE;
964c80476e4SDavid E. O'Brien break;
965c80476e4SDavid E. O'Brien default:
966c80476e4SDavid E. O'Brien *s1++ = *s2++;
967c80476e4SDavid E. O'Brien }
968c80476e4SDavid E. O'Brien *s1 = '\0';
969c80476e4SDavid E. O'Brien
970c80476e4SDavid E. O'Brien for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) {
971c80476e4SDavid E. O'Brien if (eq(sp->word, str2short(bptr->bname))) {
972c80476e4SDavid E. O'Brien if (str == NULL) {
973c80476e4SDavid E. O'Brien if (aliased)
974c80476e4SDavid E. O'Brien prlex(lexp);
975c80476e4SDavid E. O'Brien xprintf(CGETS(13, 5, "%S: shell built-in command.\n"),
976c80476e4SDavid E. O'Brien sp->word);
977c80476e4SDavid E. O'Brien flush();
978c80476e4SDavid E. O'Brien }
979c80476e4SDavid E. O'Brien else
98045e5710bSMark Peek *str = Strsave(sp->word);
98145e5710bSMark Peek cleanup_until(&s0);
982c80476e4SDavid E. O'Brien return TRUE;
983c80476e4SDavid E. O'Brien }
984c80476e4SDavid E. O'Brien }
9853b6eaa7bSAndrey A. Chernov #ifdef WINNT_NATIVE
986c80476e4SDavid E. O'Brien for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++) {
987c80476e4SDavid E. O'Brien if (eq(sp->word, str2short(bptr->bname))) {
988c80476e4SDavid E. O'Brien if (str == NULL) {
989c80476e4SDavid E. O'Brien if (aliased)
990c80476e4SDavid E. O'Brien prlex(lexp);
991c80476e4SDavid E. O'Brien xprintf(CGETS(13, 5, "%S: shell built-in command.\n"),
992c80476e4SDavid E. O'Brien sp->word);
993c80476e4SDavid E. O'Brien flush();
994c80476e4SDavid E. O'Brien }
995c80476e4SDavid E. O'Brien else
99645e5710bSMark Peek *str = Strsave(sp->word);
99745e5710bSMark Peek cleanup_until(&s0);
998c80476e4SDavid E. O'Brien return TRUE;
999c80476e4SDavid E. O'Brien }
1000c80476e4SDavid E. O'Brien }
10013b6eaa7bSAndrey A. Chernov #endif /* WINNT_NATIVE*/
1002c80476e4SDavid E. O'Brien
1003c80476e4SDavid E. O'Brien sp->word = cmd = globone(sp->word, G_IGNORE);
100445e5710bSMark Peek cleanup_push(cmd, xfree);
1005c80476e4SDavid E. O'Brien
1006c80476e4SDavid E. O'Brien if ((i = iscommand(sp->word)) != 0) {
100723338178SMark Peek Char **pv;
100823338178SMark Peek struct varent *v;
100923338178SMark Peek int slash = any(short2str(sp->word), '/');
1010c80476e4SDavid E. O'Brien
1011c80476e4SDavid E. O'Brien v = adrof(STRpath);
101229301572SMark Peek if (v == NULL || v->vec == NULL || v->vec[0] == NULL || slash)
1013c80476e4SDavid E. O'Brien pv = justabs;
1014c80476e4SDavid E. O'Brien else
1015c80476e4SDavid E. O'Brien pv = v->vec;
1016c80476e4SDavid E. O'Brien
101745e5710bSMark Peek pv += i - 1;
1018c80476e4SDavid E. O'Brien if (pv[0][0] == 0 || eq(pv[0], STRdot)) {
1019c80476e4SDavid E. O'Brien if (!slash) {
1020c80476e4SDavid E. O'Brien sp->word = Strspl(STRdotsl, sp->word);
102145e5710bSMark Peek cleanup_push(sp->word, xfree);
1022c80476e4SDavid E. O'Brien prlex(lexp);
102345e5710bSMark Peek cleanup_until(sp->word);
1024c80476e4SDavid E. O'Brien }
1025c80476e4SDavid E. O'Brien else
1026c80476e4SDavid E. O'Brien prlex(lexp);
1027c80476e4SDavid E. O'Brien }
1028c80476e4SDavid E. O'Brien else {
1029c80476e4SDavid E. O'Brien s1 = Strspl(*pv, STRslash);
1030c80476e4SDavid E. O'Brien sp->word = Strspl(s1, sp->word);
103145e5710bSMark Peek xfree(s1);
103245e5710bSMark Peek cleanup_push(sp->word, xfree);
1033c80476e4SDavid E. O'Brien if (str == NULL)
1034c80476e4SDavid E. O'Brien prlex(lexp);
1035c80476e4SDavid E. O'Brien else
103645e5710bSMark Peek *str = Strsave(sp->word);
103745e5710bSMark Peek cleanup_until(sp->word);
1038c80476e4SDavid E. O'Brien }
1039c80476e4SDavid E. O'Brien found = 1;
1040c80476e4SDavid E. O'Brien }
1041c80476e4SDavid E. O'Brien else {
1042c80476e4SDavid E. O'Brien if (str == NULL) {
1043c80476e4SDavid E. O'Brien if (aliased)
1044c80476e4SDavid E. O'Brien prlex(lexp);
1045c80476e4SDavid E. O'Brien xprintf(CGETS(13, 6, "%S: Command not found.\n"), sp->word);
1046c80476e4SDavid E. O'Brien flush();
1047c80476e4SDavid E. O'Brien }
1048c80476e4SDavid E. O'Brien else
104945e5710bSMark Peek *str = Strsave(sp->word);
1050c80476e4SDavid E. O'Brien found = 0;
1051c80476e4SDavid E. O'Brien }
105245e5710bSMark Peek cleanup_until(&s0);
1053c80476e4SDavid E. O'Brien return found;
1054c80476e4SDavid E. O'Brien }
1055c80476e4SDavid E. O'Brien
1056c80476e4SDavid E. O'Brien /*
1057c80476e4SDavid E. O'Brien * Builtin to look at and list all places a command may be defined:
1058c80476e4SDavid E. O'Brien * aliases, shell builtins, and the path.
1059c80476e4SDavid E. O'Brien *
1060c80476e4SDavid E. O'Brien * Marc Horowitz <marc@mit.edu>
1061c80476e4SDavid E. O'Brien * MIT Student Information Processing Board
1062c80476e4SDavid E. O'Brien */
1063c80476e4SDavid E. O'Brien
1064c80476e4SDavid E. O'Brien /*ARGSUSED*/
1065c80476e4SDavid E. O'Brien void
dowhere(Char ** v,struct command * c)106645e5710bSMark Peek dowhere(Char **v, struct command *c)
1067c80476e4SDavid E. O'Brien {
1068c80476e4SDavid E. O'Brien int found = 1;
1069c80476e4SDavid E. O'Brien USE(c);
1070*19d2e3deSDmitry Chagin
1071*19d2e3deSDmitry Chagin if (adrof(STRautorehash))
1072*19d2e3deSDmitry Chagin dohash(NULL, NULL);
1073c80476e4SDavid E. O'Brien for (v++; *v; v++)
1074c80476e4SDavid E. O'Brien found &= find_cmd(*v, 1);
1075c80476e4SDavid E. O'Brien /* Make status nonzero if any command is not found. */
1076c80476e4SDavid E. O'Brien if (!found)
107745e5710bSMark Peek setcopy(STRstatus, STR1, VAR_READWRITE);
1078c80476e4SDavid E. O'Brien }
1079c80476e4SDavid E. O'Brien
1080c80476e4SDavid E. O'Brien int
find_cmd(Char * cmd,int prt)108145e5710bSMark Peek find_cmd(Char *cmd, int prt)
1082c80476e4SDavid E. O'Brien {
1083c80476e4SDavid E. O'Brien struct varent *var;
108445e5710bSMark Peek const struct biltins *bptr;
1085c80476e4SDavid E. O'Brien Char **pv;
1086c80476e4SDavid E. O'Brien Char *sv;
10879ccc37e3SMark Peek int hashval, rehashed, i, ex, rval = 0;
1088c80476e4SDavid E. O'Brien
1089c80476e4SDavid E. O'Brien if (prt && any(short2str(cmd), '/')) {
1090a15e6f9aSMark Peek xprintf("%s", CGETS(13, 7, "where: / in command makes no sense\n"));
1091c80476e4SDavid E. O'Brien return rval;
1092c80476e4SDavid E. O'Brien }
1093c80476e4SDavid E. O'Brien
1094c80476e4SDavid E. O'Brien /* first, look for an alias */
1095c80476e4SDavid E. O'Brien
1096c80476e4SDavid E. O'Brien if (prt && adrof1(cmd, &aliases)) {
1097c80476e4SDavid E. O'Brien if ((var = adrof1(cmd, &aliases)) != NULL) {
1098c80476e4SDavid E. O'Brien xprintf(CGETS(13, 8, "%S is aliased to "), cmd);
109929301572SMark Peek if (var->vec != NULL)
1100c80476e4SDavid E. O'Brien blkpr(var->vec);
1101c80476e4SDavid E. O'Brien xputchar('\n');
1102c80476e4SDavid E. O'Brien rval = 1;
1103c80476e4SDavid E. O'Brien }
1104c80476e4SDavid E. O'Brien }
1105c80476e4SDavid E. O'Brien
1106c80476e4SDavid E. O'Brien /* next, look for a shell builtin */
1107c80476e4SDavid E. O'Brien
1108c80476e4SDavid E. O'Brien for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) {
1109c80476e4SDavid E. O'Brien if (eq(cmd, str2short(bptr->bname))) {
1110c80476e4SDavid E. O'Brien rval = 1;
1111c80476e4SDavid E. O'Brien if (prt)
1112c80476e4SDavid E. O'Brien xprintf(CGETS(13, 9, "%S is a shell built-in\n"), cmd);
1113c80476e4SDavid E. O'Brien else
1114c80476e4SDavid E. O'Brien return rval;
1115c80476e4SDavid E. O'Brien }
1116c80476e4SDavid E. O'Brien }
11173b6eaa7bSAndrey A. Chernov #ifdef WINNT_NATIVE
1118c80476e4SDavid E. O'Brien for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++) {
1119c80476e4SDavid E. O'Brien if (eq(cmd, str2short(bptr->bname))) {
1120c80476e4SDavid E. O'Brien rval = 1;
1121c80476e4SDavid E. O'Brien if (prt)
1122c80476e4SDavid E. O'Brien xprintf(CGETS(13, 9, "%S is a shell built-in\n"), cmd);
1123c80476e4SDavid E. O'Brien else
1124c80476e4SDavid E. O'Brien return rval;
1125c80476e4SDavid E. O'Brien }
1126c80476e4SDavid E. O'Brien }
11273b6eaa7bSAndrey A. Chernov #endif /* WINNT_NATIVE*/
1128c80476e4SDavid E. O'Brien
1129c80476e4SDavid E. O'Brien /* last, look through the path for the command */
1130c80476e4SDavid E. O'Brien
1131c80476e4SDavid E. O'Brien if ((var = adrof(STRpath)) == NULL)
1132c80476e4SDavid E. O'Brien return rval;
1133c80476e4SDavid E. O'Brien
1134c80476e4SDavid E. O'Brien hashval = havhash ? hashname(cmd) : 0;
1135c80476e4SDavid E. O'Brien
1136c80476e4SDavid E. O'Brien sv = Strspl(STRslash, cmd);
113745e5710bSMark Peek cleanup_push(sv, xfree);
1138c80476e4SDavid E. O'Brien
11399ccc37e3SMark Peek rehashed = 0;
11409ccc37e3SMark Peek retry:
114129301572SMark Peek for (pv = var->vec, i = 0; pv && *pv; pv++, i++) {
1142c80476e4SDavid E. O'Brien if (havhash && !eq(*pv, STRdot)) {
1143c80476e4SDavid E. O'Brien #ifdef FASTHASH
1144c80476e4SDavid E. O'Brien if (!bit(hashval, i))
1145c80476e4SDavid E. O'Brien continue;
1146c80476e4SDavid E. O'Brien #else /* OLDHASH */
1147c80476e4SDavid E. O'Brien int hashval1 = hash(hashval, i);
1148c80476e4SDavid E. O'Brien if (!bit(xhash, hashval1))
1149c80476e4SDavid E. O'Brien continue;
1150c80476e4SDavid E. O'Brien #endif /* FASTHASH */
1151c80476e4SDavid E. O'Brien }
1152c80476e4SDavid E. O'Brien ex = executable(*pv, sv, 0);
1153c80476e4SDavid E. O'Brien #ifdef FASTHASH
1154c80476e4SDavid E. O'Brien if (!ex && (hashdebug & 2)) {
1155a15e6f9aSMark Peek xprintf("%s", CGETS(13, 10, "hash miss: "));
1156c80476e4SDavid E. O'Brien ex = 1; /* Force printing */
1157c80476e4SDavid E. O'Brien }
1158c80476e4SDavid E. O'Brien #endif /* FASTHASH */
1159c80476e4SDavid E. O'Brien if (ex) {
1160c80476e4SDavid E. O'Brien rval = 1;
1161c80476e4SDavid E. O'Brien if (prt) {
1162c80476e4SDavid E. O'Brien xprintf("%S/", *pv);
1163c80476e4SDavid E. O'Brien xprintf("%S\n", cmd);
1164c80476e4SDavid E. O'Brien }
1165c80476e4SDavid E. O'Brien else
1166c80476e4SDavid E. O'Brien return rval;
1167c80476e4SDavid E. O'Brien }
1168c80476e4SDavid E. O'Brien }
1169*19d2e3deSDmitry Chagin /*
1170*19d2e3deSDmitry Chagin * If we are printing, we are being called from dowhere() which it
1171*19d2e3deSDmitry Chagin * has rehashed already
1172*19d2e3deSDmitry Chagin */
1173*19d2e3deSDmitry Chagin if (!prt && adrof(STRautorehash) && !rehashed && havhash) {
11749ccc37e3SMark Peek dohash(NULL, NULL);
11759ccc37e3SMark Peek rehashed = 1;
11769ccc37e3SMark Peek goto retry;
11779ccc37e3SMark Peek }
117845e5710bSMark Peek cleanup_until(sv);
1179c80476e4SDavid E. O'Brien return rval;
1180c80476e4SDavid E. O'Brien }
11813b6eaa7bSAndrey A. Chernov #ifdef WINNT_NATIVE
hashval_extern(cp)1182c80476e4SDavid E. O'Brien int hashval_extern(cp)
1183c80476e4SDavid E. O'Brien Char *cp;
1184c80476e4SDavid E. O'Brien {
1185c80476e4SDavid E. O'Brien return havhash?hashname(cp):0;
1186c80476e4SDavid E. O'Brien }
bit_extern(val,i)1187c80476e4SDavid E. O'Brien int bit_extern(val,i)
1188c80476e4SDavid E. O'Brien int val;
1189c80476e4SDavid E. O'Brien int i;
1190c80476e4SDavid E. O'Brien {
1191c80476e4SDavid E. O'Brien return bit(val,i);
1192c80476e4SDavid E. O'Brien }
bis_extern(val,i)11933b6eaa7bSAndrey A. Chernov void bis_extern(val,i)
11943b6eaa7bSAndrey A. Chernov int val;
11953b6eaa7bSAndrey A. Chernov int i;
11963b6eaa7bSAndrey A. Chernov {
11973b6eaa7bSAndrey A. Chernov bis(val,i);
11983b6eaa7bSAndrey A. Chernov }
11993b6eaa7bSAndrey A. Chernov #endif /* WINNT_NATIVE */
12003b6eaa7bSAndrey A. Chernov
1201