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