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