xref: /illumos-gate/usr/src/cmd/csh/sh.exec.c (revision 258f91c6)
17c478bd9Sstevel@tonic-gate /*
2134a1f4eSCasper H.S. Dik  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
37c478bd9Sstevel@tonic-gate  */
47c478bd9Sstevel@tonic-gate 
57c478bd9Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
67c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
77c478bd9Sstevel@tonic-gate 
87c478bd9Sstevel@tonic-gate /*
97c478bd9Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
107c478bd9Sstevel@tonic-gate  * All rights reserved.  The Berkeley Software License Agreement
117c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
127c478bd9Sstevel@tonic-gate  */
137c478bd9Sstevel@tonic-gate 
147c478bd9Sstevel@tonic-gate #include "sh.h"
157c478bd9Sstevel@tonic-gate #include <dirent.h>
167c478bd9Sstevel@tonic-gate #include <string.h>
177c478bd9Sstevel@tonic-gate #include "sh.tconst.h"
187c478bd9Sstevel@tonic-gate 
197c478bd9Sstevel@tonic-gate 
207c478bd9Sstevel@tonic-gate /*
217c478bd9Sstevel@tonic-gate  * C shell
227c478bd9Sstevel@tonic-gate  */
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate /*
257c478bd9Sstevel@tonic-gate  * System level search and execute of a command.
267c478bd9Sstevel@tonic-gate  * We look in each directory for the specified command name.
277c478bd9Sstevel@tonic-gate  * If the name contains a '/' then we execute only the full path name.
287c478bd9Sstevel@tonic-gate  * If there is no search path then we execute only full path names.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
31*258f91c6SToomas Soome char		xhash[HSHSIZ / 8];
32*258f91c6SToomas Soome tchar		**Vav;
33*258f91c6SToomas Soome tchar		*Vdp;
34*258f91c6SToomas Soome tchar		*Vsav;
35*258f91c6SToomas Soome 
36*258f91c6SToomas Soome struct varent	aliases;
37*258f91c6SToomas Soome bool		havhash;
38*258f91c6SToomas Soome static int	hits;
39*258f91c6SToomas Soome static int	misses;
40*258f91c6SToomas Soome short		SHOUT;
41*258f91c6SToomas Soome short		SHIN;
42*258f91c6SToomas Soome 
43*258f91c6SToomas Soome void		(*parintr)();
44*258f91c6SToomas Soome void		(*parterm)();
45*258f91c6SToomas Soome 
4665b0c20eSnakanon /*
477c478bd9Sstevel@tonic-gate  * As we search for the command we note the first non-trivial error
487c478bd9Sstevel@tonic-gate  * message for presentation to the user.  This allows us often
497c478bd9Sstevel@tonic-gate  * to show that a file has the wrong mode/no access when the file
507c478bd9Sstevel@tonic-gate  * is not in the last component of the search path, so we must
517c478bd9Sstevel@tonic-gate  * go on after first detecting the error.
527c478bd9Sstevel@tonic-gate  */
537c478bd9Sstevel@tonic-gate char *exerr;			/* Execution error message */
547c478bd9Sstevel@tonic-gate 
556c02b4a4Smuffin void	pexerr(void);
566c02b4a4Smuffin void	texec(struct command *, tchar *, tchar **);
576c02b4a4Smuffin void	xechoit(tchar **);
586c02b4a4Smuffin void	dohash(char []);
597c478bd9Sstevel@tonic-gate 
606c02b4a4Smuffin static void	tconvert(struct command *, tchar *, tchar **);
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate 
636c02b4a4Smuffin extern DIR *opendir_(tchar *);
646c02b4a4Smuffin 
656c02b4a4Smuffin void
doexec(struct command * t)666c02b4a4Smuffin doexec(struct command *t)
677c478bd9Sstevel@tonic-gate {
687c478bd9Sstevel@tonic-gate 	tchar *sav;
696c02b4a4Smuffin 	tchar *dp, **pv, **av;
706c02b4a4Smuffin 	struct varent *v;
717c478bd9Sstevel@tonic-gate 	bool slash;
727c478bd9Sstevel@tonic-gate 	int hashval, hashval1, i;
737c478bd9Sstevel@tonic-gate 	tchar *blk[2];
747c478bd9Sstevel@tonic-gate #ifdef TRACE
757c478bd9Sstevel@tonic-gate 	tprintf("TRACE- doexec()\n");
767c478bd9Sstevel@tonic-gate #endif
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate 	/*
797c478bd9Sstevel@tonic-gate 	 * Glob the command name.  If this does anything, then we
807c478bd9Sstevel@tonic-gate 	 * will execute the command only relative to ".".  One special
817c478bd9Sstevel@tonic-gate 	 * case: if there is no PATH, then we execute only commands
827c478bd9Sstevel@tonic-gate 	 * which start with '/'.
837c478bd9Sstevel@tonic-gate 	 */
847c478bd9Sstevel@tonic-gate 	dp = globone(t->t_dcom[0]);
857c478bd9Sstevel@tonic-gate 	sav = t->t_dcom[0];
867c478bd9Sstevel@tonic-gate 	exerr = 0; t->t_dcom[0] = dp;
877c478bd9Sstevel@tonic-gate 	setname(dp);
887c478bd9Sstevel@tonic-gate 	xfree(sav);
8965b0c20eSnakanon 	v = adrof(S_path /* "path" */);
907c478bd9Sstevel@tonic-gate 	if (v == 0 && dp[0] != '/') {
917c478bd9Sstevel@tonic-gate 		pexerr();
927c478bd9Sstevel@tonic-gate 	}
937c478bd9Sstevel@tonic-gate 	slash = gflag;
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	/*
967c478bd9Sstevel@tonic-gate 	 * Glob the argument list, if necessary.
977c478bd9Sstevel@tonic-gate 	 * Otherwise trim off the quote bits.
987c478bd9Sstevel@tonic-gate 	 */
997c478bd9Sstevel@tonic-gate 	gflag = 0; av = &t->t_dcom[1];
1007c478bd9Sstevel@tonic-gate 	tglob(av);
1017c478bd9Sstevel@tonic-gate 	if (gflag) {
1027c478bd9Sstevel@tonic-gate 		av = glob(av);
1037c478bd9Sstevel@tonic-gate 		if (av == 0)
1047c478bd9Sstevel@tonic-gate 			error("No match");
1057c478bd9Sstevel@tonic-gate 	}
1067c478bd9Sstevel@tonic-gate 	blk[0] = t->t_dcom[0];
1077c478bd9Sstevel@tonic-gate 	blk[1] = 0;
1087c478bd9Sstevel@tonic-gate 	av = blkspl(blk, av);
1097c478bd9Sstevel@tonic-gate #ifdef VFORK
1107c478bd9Sstevel@tonic-gate 	Vav = av;
1117c478bd9Sstevel@tonic-gate #endif
1127c478bd9Sstevel@tonic-gate 	trim(av);
1137c478bd9Sstevel@tonic-gate 	slash |= any('/', av[0]);
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 	xechoit(av);		/* Echo command if -x */
1167c478bd9Sstevel@tonic-gate 	/*
1177c478bd9Sstevel@tonic-gate 	 * Since all internal file descriptors are set to close on exec,
1187c478bd9Sstevel@tonic-gate 	 * we don't need to close them explicitly here.  Just reorient
1197c478bd9Sstevel@tonic-gate 	 * ourselves for error messages.
1207c478bd9Sstevel@tonic-gate 	 */
1217c478bd9Sstevel@tonic-gate 	SHIN = 0; SHOUT = 1; SHDIAG = 2; OLDSTD = 0;
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	/*
1247c478bd9Sstevel@tonic-gate 	 * We must do this AFTER any possible forking (like `foo`
1257c478bd9Sstevel@tonic-gate 	 * in glob) so that this shell can still do subprocesses.
1267c478bd9Sstevel@tonic-gate 	 */
1277c478bd9Sstevel@tonic-gate 	(void) sigsetmask(0);
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	/*
1307c478bd9Sstevel@tonic-gate 	 * If no path, no words in path, or a / in the filename
1317c478bd9Sstevel@tonic-gate 	 * then restrict the command search.
1327c478bd9Sstevel@tonic-gate 	 */
1337c478bd9Sstevel@tonic-gate 	if (v == 0 || v->vec[0] == 0 || slash)
1347c478bd9Sstevel@tonic-gate 		pv = justabs;
1357c478bd9Sstevel@tonic-gate 	else
1367c478bd9Sstevel@tonic-gate 		pv = v->vec;
137134a1f4eSCasper H.S. Dik 	/* / command name for postpending */
138134a1f4eSCasper H.S. Dik 	sav = strspl(S_SLASH /* "/" */, *av);
1397c478bd9Sstevel@tonic-gate #ifdef VFORK
1407c478bd9Sstevel@tonic-gate 	Vsav = sav;
1417c478bd9Sstevel@tonic-gate #endif
1427c478bd9Sstevel@tonic-gate 	if (havhash)
1437c478bd9Sstevel@tonic-gate 		hashval = hashname(*av);
1447c478bd9Sstevel@tonic-gate 	i = 0;
1457c478bd9Sstevel@tonic-gate #ifdef VFORK
1467c478bd9Sstevel@tonic-gate 	hits++;
1477c478bd9Sstevel@tonic-gate #endif
1487c478bd9Sstevel@tonic-gate 	do {
1497c478bd9Sstevel@tonic-gate 		if (!slash && pv[0][0] == '/' && havhash) {
1507c478bd9Sstevel@tonic-gate 			hashval1 = hash(hashval, i);
1517c478bd9Sstevel@tonic-gate 			if (!bit(xhash, hashval1))
1527c478bd9Sstevel@tonic-gate 				goto cont;
1537c478bd9Sstevel@tonic-gate 		}
1547c478bd9Sstevel@tonic-gate 
155134a1f4eSCasper H.S. Dik 		/* don't make ./xxx */
156134a1f4eSCasper H.S. Dik 		if (pv[0][0] == 0 || eq(pv[0], S_DOT /* "." */)) {
1577c478bd9Sstevel@tonic-gate 			texec(t, *av, av);
1587c478bd9Sstevel@tonic-gate 		} else {
1597c478bd9Sstevel@tonic-gate 			dp = strspl(*pv, sav);
1607c478bd9Sstevel@tonic-gate #ifdef VFORK
1617c478bd9Sstevel@tonic-gate 			Vdp = dp;
1627c478bd9Sstevel@tonic-gate #endif
1637c478bd9Sstevel@tonic-gate 			texec(t, dp, av);
1647c478bd9Sstevel@tonic-gate #ifdef VFORK
1657c478bd9Sstevel@tonic-gate 			Vdp = 0;
1667c478bd9Sstevel@tonic-gate #endif
1677c478bd9Sstevel@tonic-gate 			xfree(dp);
1687c478bd9Sstevel@tonic-gate 		}
1697c478bd9Sstevel@tonic-gate #ifdef VFORK
1707c478bd9Sstevel@tonic-gate 		misses++;
1717c478bd9Sstevel@tonic-gate #endif
1727c478bd9Sstevel@tonic-gate cont:
1737c478bd9Sstevel@tonic-gate 		pv++;
1747c478bd9Sstevel@tonic-gate 		i++;
1757c478bd9Sstevel@tonic-gate 	} while (*pv);
1767c478bd9Sstevel@tonic-gate #ifdef VFORK
1777c478bd9Sstevel@tonic-gate 	hits--;
1787c478bd9Sstevel@tonic-gate #endif
1797c478bd9Sstevel@tonic-gate #ifdef VFORK
1807c478bd9Sstevel@tonic-gate 	Vsav = 0;
1817c478bd9Sstevel@tonic-gate 	Vav = 0;
1827c478bd9Sstevel@tonic-gate #endif
1837c478bd9Sstevel@tonic-gate 	xfree(sav);
18465b0c20eSnakanon 	xfree((char *)av);
1857c478bd9Sstevel@tonic-gate 	pexerr();
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate 
1886c02b4a4Smuffin void
pexerr(void)1896c02b4a4Smuffin pexerr(void)
1907c478bd9Sstevel@tonic-gate {
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate #ifdef TRACE
1937c478bd9Sstevel@tonic-gate 	tprintf("TRACE- pexerr()\n");
1947c478bd9Sstevel@tonic-gate #endif
1957c478bd9Sstevel@tonic-gate 	/* Couldn't find the damn thing */
1967c478bd9Sstevel@tonic-gate 	if (exerr)
1977c478bd9Sstevel@tonic-gate 		bferr(exerr);
1987c478bd9Sstevel@tonic-gate 	bferr("Command not found");
1997c478bd9Sstevel@tonic-gate }
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate /*
2027c478bd9Sstevel@tonic-gate  * Execute command f, arg list t.
2037c478bd9Sstevel@tonic-gate  * Record error message if not found.
2047c478bd9Sstevel@tonic-gate  * Also do shell scripts here.
2057c478bd9Sstevel@tonic-gate  */
2066c02b4a4Smuffin void
texec(struct command * cmd,tchar * f,tchar ** t)2076c02b4a4Smuffin texec(struct command *cmd, tchar *f, tchar **t)
2087c478bd9Sstevel@tonic-gate {
2096c02b4a4Smuffin 	struct	varent *v;
2106c02b4a4Smuffin 	tchar	**vp;
2117c478bd9Sstevel@tonic-gate 	tchar		*lastsh[2];
21265b0c20eSnakanon 
2137c478bd9Sstevel@tonic-gate #ifdef TRACE
2147c478bd9Sstevel@tonic-gate 	tprintf("TRACE- texec()\n");
2157c478bd9Sstevel@tonic-gate #endif
2167c478bd9Sstevel@tonic-gate 	/* convert cfname and cargs from tchar to char */
2177c478bd9Sstevel@tonic-gate 	tconvert(cmd, f, t);
2187c478bd9Sstevel@tonic-gate 
219134a1f4eSCasper H.S. Dik 	execv(cmd->cfname, cmd->cargs);
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	/*
2227c478bd9Sstevel@tonic-gate 	 * exec returned, free up allocations from above
2237c478bd9Sstevel@tonic-gate 	 * tconvert(), zero cfname and cargs to prevent
2247c478bd9Sstevel@tonic-gate 	 * duplicate free() in freesyn()
2257c478bd9Sstevel@tonic-gate 	 */
2267c478bd9Sstevel@tonic-gate 	xfree(cmd->cfname);
2277c478bd9Sstevel@tonic-gate 	chr_blkfree(cmd->cargs);
22865b0c20eSnakanon 	cmd->cfname = (char *)0;
22965b0c20eSnakanon 	cmd->cargs = (char **)0;
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 	switch (errno) {
2327c478bd9Sstevel@tonic-gate 	case ENOEXEC:
2337c478bd9Sstevel@tonic-gate 		/* check that this is not a binary file */
23465b0c20eSnakanon 		{
2356c02b4a4Smuffin 			int ff = open_(f, 0);
23665b0c20eSnakanon 			tchar ch[MB_LEN_MAX];
2377c478bd9Sstevel@tonic-gate 
23865b0c20eSnakanon 			if (ff != -1 && read_(ff, ch, 1) == 1 &&
23965b0c20eSnakanon 			    !isprint(ch[0]) && !isspace(ch[0])) {
2407c478bd9Sstevel@tonic-gate 				printf("Cannot execute binary file.\n");
2417c478bd9Sstevel@tonic-gate 				Perror(f);
2427c478bd9Sstevel@tonic-gate 				(void) close(ff);
2437c478bd9Sstevel@tonic-gate 				unsetfd(ff);
2447c478bd9Sstevel@tonic-gate 				return;
24565b0c20eSnakanon 			}
2467c478bd9Sstevel@tonic-gate 			(void) close(ff);
2477c478bd9Sstevel@tonic-gate 			unsetfd(ff);
24865b0c20eSnakanon 		}
2497c478bd9Sstevel@tonic-gate 		/*
2507c478bd9Sstevel@tonic-gate 		 * If there is an alias for shell, then
2517c478bd9Sstevel@tonic-gate 		 * put the words of the alias in front of the
2527c478bd9Sstevel@tonic-gate 		 * argument list replacing the command name.
2537c478bd9Sstevel@tonic-gate 		 * Note no interpretation of the words at this point.
2547c478bd9Sstevel@tonic-gate 		 */
25565b0c20eSnakanon 		v = adrof1(S_shell /* "shell" */, &aliases);
2567c478bd9Sstevel@tonic-gate 		if (v == 0) {
2577c478bd9Sstevel@tonic-gate #ifdef OTHERSH
2586c02b4a4Smuffin 			int ff = open_(f, 0);
25965b0c20eSnakanon 			tchar ch[MB_LEN_MAX];
2607c478bd9Sstevel@tonic-gate #endif
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 			vp = lastsh;
263134a1f4eSCasper H.S. Dik 			vp[0] = adrof(S_shell /* "shell" */) ?
264134a1f4eSCasper H.S. Dik 			    value(S_shell /* "shell" */) :
265134a1f4eSCasper H.S. Dik 			    S_SHELLPATH /* SHELLPATH */;
2667c478bd9Sstevel@tonic-gate 			vp[1] =  (tchar *) NULL;
2677c478bd9Sstevel@tonic-gate #ifdef OTHERSH
26865b0c20eSnakanon 			if (ff != -1 && read_(ff, ch, 1) == 1 && ch[0] != '#')
26965b0c20eSnakanon 				vp[0] = S_OTHERSH /* OTHERSH */;
2707c478bd9Sstevel@tonic-gate 			(void) close(ff);
2717c478bd9Sstevel@tonic-gate 			unsetfd(ff);
2727c478bd9Sstevel@tonic-gate #endif
2737c478bd9Sstevel@tonic-gate 		} else
2747c478bd9Sstevel@tonic-gate 			vp = v->vec;
2757c478bd9Sstevel@tonic-gate 		t[0] = f;
2767c478bd9Sstevel@tonic-gate 		t = blkspl(vp, t);		/* Splice up the new arglst */
2777c478bd9Sstevel@tonic-gate 		f = *t;
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 		tconvert(cmd, f, t);		/* convert tchar to char */
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 		/*
2827c478bd9Sstevel@tonic-gate 		 * now done with tchar arg list t,
2837c478bd9Sstevel@tonic-gate 		 * free the space calloc'd by above blkspl()
2847c478bd9Sstevel@tonic-gate 		 */
28565b0c20eSnakanon 		xfree((char *)t);
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 		execv(cmd->cfname, cmd->cargs);	/* exec the command */
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 		/* exec returned, same free'ing as above */
2907c478bd9Sstevel@tonic-gate 		xfree(cmd->cfname);
2917c478bd9Sstevel@tonic-gate 		chr_blkfree(cmd->cargs);
29265b0c20eSnakanon 		cmd->cfname = (char *)0;
29365b0c20eSnakanon 		cmd->cargs = (char **)0;
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 		/* The sky is falling, the sky is falling! */
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	case ENOMEM:
2987c478bd9Sstevel@tonic-gate 		Perror(f);
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	case ENOENT:
3017c478bd9Sstevel@tonic-gate 		break;
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	default:
3047c478bd9Sstevel@tonic-gate 		if (exerr == 0) {
3057c478bd9Sstevel@tonic-gate 			exerr = strerror(errno);
3067c478bd9Sstevel@tonic-gate 			setname(f);
3077c478bd9Sstevel@tonic-gate 		}
3087c478bd9Sstevel@tonic-gate 	}
3097c478bd9Sstevel@tonic-gate }
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 
3126c02b4a4Smuffin static void
tconvert(struct command * cmd,tchar * fname,tchar ** list)3136c02b4a4Smuffin tconvert(struct command *cmd, tchar *fname, tchar **list)
3147c478bd9Sstevel@tonic-gate {
3156c02b4a4Smuffin 	char **rc;
3166c02b4a4Smuffin 	int len;
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	cmd->cfname = tstostr(NULL, fname);
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	len = blklen(list);
3217c478bd9Sstevel@tonic-gate 	rc = cmd->cargs = (char **)
322134a1f4eSCasper H.S. Dik 	    xcalloc((uint_t)(len + 1), sizeof (char **));
3237c478bd9Sstevel@tonic-gate 	while (len--)
3247c478bd9Sstevel@tonic-gate 		*rc++ = tstostr(NULL, *list++);
3257c478bd9Sstevel@tonic-gate 	*rc = NULL;
3267c478bd9Sstevel@tonic-gate }
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3306c02b4a4Smuffin void
execash(tchar ** t,struct command * kp)3316c02b4a4Smuffin execash(tchar **t, struct command *kp)
3327c478bd9Sstevel@tonic-gate {
3337c478bd9Sstevel@tonic-gate #ifdef TRACE
3347c478bd9Sstevel@tonic-gate 	tprintf("TRACE- execash()\n");
3357c478bd9Sstevel@tonic-gate #endif
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	rechist();
3387c478bd9Sstevel@tonic-gate 	(void) signal(SIGINT, parintr);
3397c478bd9Sstevel@tonic-gate 	(void) signal(SIGQUIT, parintr);
3407c478bd9Sstevel@tonic-gate 	(void) signal(SIGTERM, parterm);	/* if doexec loses, screw */
3417c478bd9Sstevel@tonic-gate 	lshift(kp->t_dcom, 1);
3427c478bd9Sstevel@tonic-gate 	exiterr++;
3437c478bd9Sstevel@tonic-gate 	doexec(kp);
3447c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
3457c478bd9Sstevel@tonic-gate }
3467c478bd9Sstevel@tonic-gate 
3476c02b4a4Smuffin void
xechoit(tchar ** t)3486c02b4a4Smuffin xechoit(tchar **t)
3497c478bd9Sstevel@tonic-gate {
3507c478bd9Sstevel@tonic-gate #ifdef TRACE
3517c478bd9Sstevel@tonic-gate 	tprintf("TRACE- xechoit()\n");
3527c478bd9Sstevel@tonic-gate #endif
3537c478bd9Sstevel@tonic-gate 
35465b0c20eSnakanon 	if (adrof(S_echo /* "echo" */)) {
3557c478bd9Sstevel@tonic-gate 		flush();
3567c478bd9Sstevel@tonic-gate 		haderr = 1;
3577c478bd9Sstevel@tonic-gate 		blkpr(t), Putchar('\n');
3587c478bd9Sstevel@tonic-gate 		haderr = 0;
3597c478bd9Sstevel@tonic-gate 	}
3607c478bd9Sstevel@tonic-gate }
3617c478bd9Sstevel@tonic-gate 
36265b0c20eSnakanon /*
3637c478bd9Sstevel@tonic-gate  * This routine called when user enters "rehash".
3647c478bd9Sstevel@tonic-gate  * Both the path and cdpath caching arrays will
3657c478bd9Sstevel@tonic-gate  * be rehashed, via calling dohash.  If either
3667c478bd9Sstevel@tonic-gate  * variable is not set with a value, then dohash
3677c478bd9Sstevel@tonic-gate  * just exits.
3687c478bd9Sstevel@tonic-gate  */
3696c02b4a4Smuffin void
dorehash(void)3706c02b4a4Smuffin dorehash(void)
3717c478bd9Sstevel@tonic-gate {
3727c478bd9Sstevel@tonic-gate 	dohash(xhash);
3737c478bd9Sstevel@tonic-gate 	dohash(xhash2);
3747c478bd9Sstevel@tonic-gate }
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate /*
3777c478bd9Sstevel@tonic-gate  * Fill up caching arrays for path and cdpath
3787c478bd9Sstevel@tonic-gate  */
3796c02b4a4Smuffin void
dohash(char cachearray[])3806c02b4a4Smuffin dohash(char cachearray[])
3817c478bd9Sstevel@tonic-gate {
3827c478bd9Sstevel@tonic-gate 	struct stat stb;
3837c478bd9Sstevel@tonic-gate 	DIR *dirp;
3846c02b4a4Smuffin 	struct dirent *dp;
3856c02b4a4Smuffin 	int cnt;
3867c478bd9Sstevel@tonic-gate 	int i = 0;
3877c478bd9Sstevel@tonic-gate 	struct varent *v;
3887c478bd9Sstevel@tonic-gate 	tchar **pv;
3897c478bd9Sstevel@tonic-gate 	int hashval;
3907c478bd9Sstevel@tonic-gate 	tchar curdir_[MAXNAMLEN+1];
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate #ifdef TRACE
3937c478bd9Sstevel@tonic-gate 	tprintf("TRACE- dohash()\n");
3947c478bd9Sstevel@tonic-gate #endif
3957c478bd9Sstevel@tonic-gate 	/* Caching $path */
39665b0c20eSnakanon 	if (cachearray == xhash) {
3977c478bd9Sstevel@tonic-gate 		havhash = 1;
39865b0c20eSnakanon 		v = adrof(S_path /* "path" */);
39965b0c20eSnakanon 	} else {    /* Caching $cdpath */
4007c478bd9Sstevel@tonic-gate 		havhash2 = 1;
40165b0c20eSnakanon 		v = adrof(S_cdpath /* "cdpath" */);
4027c478bd9Sstevel@tonic-gate 	}
4037c478bd9Sstevel@tonic-gate 
40465b0c20eSnakanon 	for (cnt = 0; cnt < (HSHSIZ / 8); cnt++)
4057c478bd9Sstevel@tonic-gate 		cachearray[cnt] = 0;
4067c478bd9Sstevel@tonic-gate 	if (v == 0)
4077c478bd9Sstevel@tonic-gate 		return;
4087c478bd9Sstevel@tonic-gate 	for (pv = v->vec; *pv; pv++, i++) {
4097c478bd9Sstevel@tonic-gate 		if (pv[0][0] != '/')
4107c478bd9Sstevel@tonic-gate 			continue;
4117c478bd9Sstevel@tonic-gate 		dirp = opendir_(*pv);
4127c478bd9Sstevel@tonic-gate 		if (dirp == NULL)
4137c478bd9Sstevel@tonic-gate 			continue;
4147c478bd9Sstevel@tonic-gate 		if (fstat(dirp->dd_fd, &stb) < 0 || !isdir(stb)) {
4157c478bd9Sstevel@tonic-gate 			unsetfd(dirp->dd_fd);
4167c478bd9Sstevel@tonic-gate 			closedir_(dirp);
4177c478bd9Sstevel@tonic-gate 			continue;
4187c478bd9Sstevel@tonic-gate 		}
4197c478bd9Sstevel@tonic-gate 		while ((dp = readdir(dirp)) != NULL) {
4207c478bd9Sstevel@tonic-gate 			if (dp->d_ino == 0)
4217c478bd9Sstevel@tonic-gate 				continue;
4227c478bd9Sstevel@tonic-gate 			if (dp->d_name[0] == '.' &&
4237c478bd9Sstevel@tonic-gate 			    (dp->d_name[1] == '\0' ||
42465b0c20eSnakanon 			    dp->d_name[1] == '.' && dp->d_name[2] == '\0'))
4257c478bd9Sstevel@tonic-gate 				continue;
426134a1f4eSCasper H.S. Dik 			hashval = hash(hashname(strtots(curdir_, dp->d_name)),
427134a1f4eSCasper H.S. Dik 			    i);
4287c478bd9Sstevel@tonic-gate 			bis(cachearray, hashval);
4297c478bd9Sstevel@tonic-gate 		}
4307c478bd9Sstevel@tonic-gate 		unsetfd(dirp->dd_fd);
4317c478bd9Sstevel@tonic-gate 		closedir_(dirp);
4327c478bd9Sstevel@tonic-gate 	}
4337c478bd9Sstevel@tonic-gate }
4347c478bd9Sstevel@tonic-gate 
4356c02b4a4Smuffin void
dounhash(void)4366c02b4a4Smuffin dounhash(void)
4377c478bd9Sstevel@tonic-gate {
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate #ifdef TRACE
4407c478bd9Sstevel@tonic-gate 	tprintf("TRACE- dounhash()\n");
4417c478bd9Sstevel@tonic-gate #endif
4427c478bd9Sstevel@tonic-gate 	havhash = 0;
4437c478bd9Sstevel@tonic-gate 	havhash2 = 0;
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate #ifdef VFORK
4476c02b4a4Smuffin void
hashstat(void)4486c02b4a4Smuffin hashstat(void)
4497c478bd9Sstevel@tonic-gate {
4507c478bd9Sstevel@tonic-gate #ifdef TRACE
4517c478bd9Sstevel@tonic-gate 	tprintf("TRACE- hashstat_()\n");
4527c478bd9Sstevel@tonic-gate #endif
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	if (hits+misses)
4557c478bd9Sstevel@tonic-gate 		printf("%d hits, %d misses, %d%%\n",
456134a1f4eSCasper H.S. Dik 		    hits, misses, 100 * hits / (hits + misses));
4577c478bd9Sstevel@tonic-gate }
4587c478bd9Sstevel@tonic-gate #endif
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate /*
4617c478bd9Sstevel@tonic-gate  * Hash a command name.
4627c478bd9Sstevel@tonic-gate  */
4636c02b4a4Smuffin int
hashname(tchar * cp)4646c02b4a4Smuffin hashname(tchar *cp)
4657c478bd9Sstevel@tonic-gate {
4666c02b4a4Smuffin 	long h = 0;
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate #ifdef TRACE
4697c478bd9Sstevel@tonic-gate 	tprintf("TRACE- hashname()\n");
4707c478bd9Sstevel@tonic-gate #endif
4717c478bd9Sstevel@tonic-gate 	while (*cp)
4727c478bd9Sstevel@tonic-gate 		h = hash(h, *cp++);
47365b0c20eSnakanon 	return ((int)h);
4747c478bd9Sstevel@tonic-gate }
475