finally works (updated for 4.1c and merged with sun)
[unix-history] / usr / src / bin / csh / exec.c
CommitLineData
ea775389 1static char *sccsid = "@(#)exec.c 4.5 %G%";
c5fd306c
BJ
2
3#include "sh.h"
3d9f6a35 4#include <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 /*
93 * We must do this after any possible forking (like `foo`
94 * in glob) so that this shell can still do subprocesses.
95 */
96 sigsys(SIGCHLD, SIG_IGN); /* sigsys for vforks sake */
97
98 /*
99 * If no path, no words in path, or a / in the filename
100 * then restrict the command search.
101 */
102 if (v == 0 || v->vec[0] == 0 || slash)
103 pv = justabs;
104 else
105 pv = v->vec;
106 sav = strspl("/", *av); /* / command name for postpending */
107#ifdef VFORK
108 Vsav = sav;
109#endif
110 if (havhash)
111 hashval = xhash[hash(*av)];
112 i = 0;
113#ifdef VFORK
114 hits++;
115#endif
116 do {
117 if (!slash && pv[0][0] == '/' && havhash && (hashval & (1 << (i % 8))) == 0)
118 goto cont;
119 if (pv[0][0] == 0 || eq(pv[0], ".")) /* don't make ./xxx */
120 texec(*av, av);
121 else {
122 dp = strspl(*pv, sav);
123#ifdef VFORK
124 Vdp = dp;
125#endif
126 texec(dp, av);
127#ifdef VFORK
128 Vdp = 0;
129#endif
130 xfree(dp);
131 }
132#ifdef VFORK
133 misses++;
134#endif
135cont:
136 pv++;
137 i++;
138 } while (*pv);
139#ifdef VFORK
140 hits--;
141#endif
142#ifdef VFORK
143 Vsav = 0;
144 Vav = 0;
145#endif
146 xfree(sav);
147 xfree(av);
148 pexerr();
149}
150
151pexerr()
152{
153
154 /* Couldn't find the damn thing */
155 setname(expath);
156 /* xfree(expath); */
157 if (exerr)
158 bferr(exerr);
159 bferr("Command not found");
160}
161
162/* Last resort shell */
163char *lastsh[] = { SHELLPATH, 0 };
164
165/*
166 * Execute command f, arg list t.
167 * Record error message if not found.
168 * Also do shell scripts here.
169 */
170texec(f, t)
171 char *f;
172 register char **t;
173{
174 register struct varent *v;
175 register char **vp;
176 extern char *sys_errlist[];
177
178 execv(f, t);
179 switch (errno) {
180
181 case ENOEXEC:
182 /*
183 * If there is an alias for shell, then
184 * put the words of the alias in front of the
185 * argument list replacing the command name.
186 * Note no interpretation of the words at this point.
187 */
188 v = adrof1("shell", &aliases);
189 if (v == 0) {
190#ifdef OTHERSH
191 register int ff = open(f, 0);
192 char ch;
193#endif
194
195 vp = lastsh;
196 vp[0] = adrof("shell") ? value("shell") : SHELLPATH;
197#ifdef OTHERSH
198 if (ff != -1 && read(ff, &ch, 1) == 1 && ch != '#')
199 vp[0] = OTHERSH;
200 close(ff);
201#endif
202 } else
203 vp = v->vec;
204 t[0] = f;
205 t = blkspl(vp, t); /* Splice up the new arglst */
206 f = *t;
207 execv(f, t);
208 xfree((char *)t);
209 /* The sky is falling, the sky is falling! */
210
211 case ENOMEM:
212 Perror(f);
213
214 case ENOENT:
215 break;
216
217 default:
218 if (exerr == 0) {
219 exerr = sys_errlist[errno];
220 expath = savestr(f);
221 }
222 }
223}
224
225execash(t, kp)
226 register struct command *kp;
227{
228
229 didcch++;
30211ec6 230 rechist();
c5fd306c
BJ
231 signal(SIGINT, parintr);
232 signal(SIGQUIT, parintr);
233 signal(SIGTERM, parterm); /* if doexec loses, screw */
234 lshift(kp->t_dcom, 1);
235 exiterr++;
236 doexec(kp);
237 /*NOTREACHED*/
238}
239
240xechoit(t)
241 char **t;
242{
243
244 if (adrof("echo")) {
245 flush();
246 haderr = 1;
247 blkpr(t), printf("\n");
248 haderr = 0;
249 }
250}
251
252dohash()
253{
254 struct stat stb;
9363f20d
KM
255 DIR *dirp;
256 register struct direct *dp;
257 register int cnt;
c5fd306c
BJ
258 int i = 0;
259 struct varent *v = adrof("path");
260 char **pv;
261
262 havhash = 1;
263 for (cnt = 0; cnt < HSHSIZ; cnt++)
264 xhash[cnt] = 0;
265 if (v == 0)
266 return;
267 for (pv = v->vec; *pv; pv++, i = (i + 1) % 8) {
268 if (pv[0][0] != '/')
269 continue;
9363f20d
KM
270 dirp = opendir(*pv);
271 if (dirp == NULL)
c5fd306c 272 continue;
9363f20d
KM
273 if (fstat(dirp->dd_fd, &stb) < 0 || !isdir(stb)) {
274 closedir(dirp);
c5fd306c
BJ
275 continue;
276 }
9363f20d
KM
277 while ((dp = readdir(dirp)) != NULL) {
278 if (dp->d_ino == 0)
279 continue;
280 xhash[hash(dp->d_name)] |= (1 << i);
c5fd306c 281 }
9363f20d 282 closedir(dirp);
c5fd306c
BJ
283 }
284}
285
286dounhash()
287{
288
289 havhash = 0;
290}
291
292#ifdef VFORK
293hashstat()
294{
295
296 if (hits+misses)
297 printf("%d hits, %d misses, %2d%%\n", hits, misses, 100 * hits / (hits + misses));
298}
299#endif
300
301hash(cp)
302 register char *cp;
303{
304 register long hash = 0;
305 int retval;
306
307 while (*cp)
308 hash += hash + *cp++;
309 if (hash < 0)
310 hash = -hash;
311 retval = hash % HSHSIZ;
312 return (retval);
313}