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