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