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