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