use the library globbing routines instead of rolling our own
[unix-history] / usr / src / bin / csh / exec.c
CommitLineData
b79f4fa9
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
094e80ed 3 * All rights reserved. The Berkeley Software License Agreement
b79f4fa9
DF
4 * specifies the terms and conditions for redistribution.
5 */
6
35371dec 7#ifndef lint
caa2918b 8static char *sccsid = "@(#)sh.exec.c 5.7 (Berkeley) 5/27/90";
094e80ed 9#endif
c5fd306c
BJ
10
11#include "sh.h"
657820b8 12#include <sys/dir.h>
ec705578 13#include <string.h>
c502712b 14#include "pathnames.h"
c5fd306c
BJ
15
16/*
17 * C shell
18 */
19
20/*
21 * System level search and execute of a command.
22 * We look in each directory for the specified command name.
23 * If the name contains a '/' then we execute only the full path name.
24 * If there is no search path then we execute only full path names.
25 */
26
27/*
28 * As we search for the command we note the first non-trivial error
29 * message for presentation to the user. This allows us often
30 * to show that a file has the wrong mode/no access when the file
31 * is not in the last component of the search path, so we must
32 * go on after first detecting the error.
33 */
34char *exerr; /* Execution error message */
35char *expath; /* Path for exerr */
36
37/*
35371dec
EW
38 * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used
39 * to hash execs. If it is allocated (havhash true), then to tell
40 * whether ``name'' is (possibly) present in the i'th component
41 * of the variable path, you look at the bit in xhash indexed by
42 * hash(hashname("name"), i). This is setup automatically
c5fd306c
BJ
43 * after .login is executed, and recomputed whenever ``path'' is
44 * changed.
35371dec
EW
45 * The two part hash function is designed to let texec() call the
46 * more expensive hashname() only once and the simple hash() several
47 * times (once for each path component checked).
48 * Byte size is assumed to be 8.
c5fd306c 49 */
35371dec
EW
50#define HSHSIZ 8192 /* 1k bytes */
51#define HSHMASK (HSHSIZ - 1)
52#define HSHMUL 243
53char xhash[HSHSIZ / 8];
54#define hash(a, b) ((a) * HSHMUL + (b) & HSHMASK)
55#define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */
56#define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */
c5fd306c
BJ
57#ifdef VFORK
58int hits, misses;
59#endif
60
61/* Dummy search path for just absolute search when no path */
62char *justabs[] = { "", 0 };
63
64doexec(t)
65 register struct command *t;
66{
67 char *sav;
68 register char *dp, **pv, **av;
69 register struct varent *v;
caa2918b 70 bool slash = (bool)index(t->t_dcom[0], '/');
35371dec 71 int hashval, hashval1, i;
c5fd306c
BJ
72 char *blk[2];
73
74 /*
75 * Glob the command name. If this does anything, then we
76 * will execute the command only relative to ".". One special
77 * case: if there is no PATH, then we execute only commands
78 * which start with '/'.
79 */
80 dp = globone(t->t_dcom[0]);
81 sav = t->t_dcom[0];
82 exerr = 0; expath = t->t_dcom[0] = dp;
83 xfree(sav);
84 v = adrof("path");
85 if (v == 0 && expath[0] != '/')
86 pexerr();
87 slash |= gflag;
88
89 /*
90 * Glob the argument list, if necessary.
91 * Otherwise trim off the quote bits.
92 */
93 gflag = 0; av = &t->t_dcom[1];
35371dec 94 tglob(av);
c5fd306c 95 if (gflag) {
caa2918b 96 av = globall(av);
c5fd306c
BJ
97 if (av == 0)
98 error("No match");
99 }
100 blk[0] = t->t_dcom[0];
101 blk[1] = 0;
102 av = blkspl(blk, av);
103#ifdef VFORK
104 Vav = av;
105#endif
35371dec 106 trim(av);
c5fd306c
BJ
107
108 xechoit(av); /* Echo command if -x */
35371dec
EW
109 /*
110 * Since all internal file descriptors are set to close on exec,
111 * we don't need to close them explicitly here. Just reorient
112 * ourselves for error messages.
113 */
114 SHIN = 0; SHOUT = 1; SHDIAG = 2; OLDSTD = 0;
c5fd306c
BJ
115
116 /*
ec1a81af 117 * We must do this AFTER any possible forking (like `foo`
c5fd306c
BJ
118 * in glob) so that this shell can still do subprocesses.
119 */
1f7b623f 120 (void) sigsetmask(0L);
c5fd306c
BJ
121
122 /*
123 * If no path, no words in path, or a / in the filename
124 * then restrict the command search.
125 */
126 if (v == 0 || v->vec[0] == 0 || slash)
127 pv = justabs;
128 else
129 pv = v->vec;
130 sav = strspl("/", *av); /* / command name for postpending */
131#ifdef VFORK
132 Vsav = sav;
133#endif
134 if (havhash)
35371dec 135 hashval = hashname(*av);
c5fd306c
BJ
136 i = 0;
137#ifdef VFORK
138 hits++;
139#endif
140 do {
35371dec
EW
141 if (!slash && pv[0][0] == '/' && havhash) {
142 hashval1 = hash(hashval, i);
143 if (!bit(xhash, hashval1))
144 goto cont;
145 }
c5fd306c
BJ
146 if (pv[0][0] == 0 || eq(pv[0], ".")) /* don't make ./xxx */
147 texec(*av, av);
148 else {
149 dp = strspl(*pv, sav);
150#ifdef VFORK
151 Vdp = dp;
152#endif
153 texec(dp, av);
154#ifdef VFORK
155 Vdp = 0;
156#endif
157 xfree(dp);
158 }
159#ifdef VFORK
160 misses++;
161#endif
162cont:
163 pv++;
164 i++;
165 } while (*pv);
166#ifdef VFORK
167 hits--;
168#endif
169#ifdef VFORK
170 Vsav = 0;
171 Vav = 0;
172#endif
173 xfree(sav);
35371dec 174 xfree((char *)av);
c5fd306c
BJ
175 pexerr();
176}
177
178pexerr()
179{
180
181 /* Couldn't find the damn thing */
182 setname(expath);
183 /* xfree(expath); */
184 if (exerr)
185 bferr(exerr);
186 bferr("Command not found");
187}
188
c5fd306c
BJ
189/*
190 * Execute command f, arg list t.
191 * Record error message if not found.
192 * Also do shell scripts here.
193 */
194texec(f, t)
195 char *f;
196 register char **t;
197{
198 register struct varent *v;
199 register char **vp;
35371dec 200 char *lastsh[2];
c5fd306c
BJ
201
202 execv(f, t);
203 switch (errno) {
204
205 case ENOEXEC:
206 /*
207 * If there is an alias for shell, then
208 * put the words of the alias in front of the
209 * argument list replacing the command name.
210 * Note no interpretation of the words at this point.
211 */
212 v = adrof1("shell", &aliases);
213 if (v == 0) {
c5fd306c
BJ
214 register int ff = open(f, 0);
215 char ch;
c5fd306c
BJ
216
217 vp = lastsh;
5fe577ad 218 vp[0] = adrof("shell") ? value("shell") : _PATH_CSHELL;
7cebe910 219 vp[1] = (char *) NULL;
c5fd306c 220 if (ff != -1 && read(ff, &ch, 1) == 1 && ch != '#')
5fe577ad 221 vp[0] = _PATH_BSHELL;
35371dec 222 (void) close(ff);
c5fd306c
BJ
223 } else
224 vp = v->vec;
225 t[0] = f;
226 t = blkspl(vp, t); /* Splice up the new arglst */
227 f = *t;
228 execv(f, t);
229 xfree((char *)t);
230 /* The sky is falling, the sky is falling! */
231
232 case ENOMEM:
233 Perror(f);
234
235 case ENOENT:
236 break;
237
238 default:
239 if (exerr == 0) {
ec705578 240 exerr = strerror(errno);
c5fd306c
BJ
241 expath = savestr(f);
242 }
243 }
244}
245
35371dec 246/*ARGSUSED*/
c5fd306c 247execash(t, kp)
35371dec 248 char **t;
c5fd306c
BJ
249 register struct command *kp;
250{
251
30211ec6 252 rechist();
35371dec
EW
253 (void) signal(SIGINT, parintr);
254 (void) signal(SIGQUIT, parintr);
255 (void) signal(SIGTERM, parterm); /* if doexec loses, screw */
c5fd306c
BJ
256 lshift(kp->t_dcom, 1);
257 exiterr++;
258 doexec(kp);
259 /*NOTREACHED*/
260}
261
262xechoit(t)
263 char **t;
264{
265
266 if (adrof("echo")) {
267 flush();
268 haderr = 1;
fad613b5 269 blkpr(t), cshputchar('\n');
c5fd306c
BJ
270 haderr = 0;
271 }
272}
273
35371dec 274/*VARARGS0*//*ARGSUSED*/
1f7b623f 275dohash()
c5fd306c
BJ
276{
277 struct stat stb;
9363f20d
KM
278 DIR *dirp;
279 register struct direct *dp;
280 register int cnt;
c5fd306c
BJ
281 int i = 0;
282 struct varent *v = adrof("path");
283 char **pv;
35371dec 284 int hashval;
c5fd306c
BJ
285
286 havhash = 1;
35371dec 287 for (cnt = 0; cnt < sizeof xhash; cnt++)
c5fd306c
BJ
288 xhash[cnt] = 0;
289 if (v == 0)
290 return;
35371dec 291 for (pv = v->vec; *pv; pv++, i++) {
c5fd306c
BJ
292 if (pv[0][0] != '/')
293 continue;
9363f20d
KM
294 dirp = opendir(*pv);
295 if (dirp == NULL)
c5fd306c 296 continue;
9363f20d
KM
297 if (fstat(dirp->dd_fd, &stb) < 0 || !isdir(stb)) {
298 closedir(dirp);
c5fd306c
BJ
299 continue;
300 }
9363f20d
KM
301 while ((dp = readdir(dirp)) != NULL) {
302 if (dp->d_ino == 0)
303 continue;
35371dec
EW
304 if (dp->d_name[0] == '.' &&
305 (dp->d_name[1] == '\0' ||
306 dp->d_name[1] == '.' && dp->d_name[2] == '\0'))
307 continue;
308 hashval = hash(hashname(dp->d_name), i);
309 bis(xhash, hashval);
c5fd306c 310 }
9363f20d 311 closedir(dirp);
c5fd306c
BJ
312 }
313}
314
315dounhash()
316{
317
318 havhash = 0;
319}
320
321#ifdef VFORK
322hashstat()
323{
324
325 if (hits+misses)
35371dec
EW
326 printf("%d hits, %d misses, %d%%\n",
327 hits, misses, 100 * hits / (hits + misses));
c5fd306c
BJ
328}
329#endif
330
35371dec
EW
331/*
332 * Hash a command name.
333 */
334hashname(cp)
c5fd306c
BJ
335 register char *cp;
336{
35371dec 337 register long h = 0;
c5fd306c
BJ
338
339 while (*cp)
35371dec
EW
340 h = hash(h, *cp++);
341 return ((int) h);
c5fd306c 342}