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