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