xref: /titanic_52/usr/src/cmd/csh/sh.exec.c (revision 65b0c20e9bbaf87a200ce20a4decf18585e61a25)
17c478bd9Sstevel@tonic-gate /*
26c02b4a4Smuffin  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
77c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
87c478bd9Sstevel@tonic-gate 
97c478bd9Sstevel@tonic-gate /*
107c478bd9Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
117c478bd9Sstevel@tonic-gate  * All rights reserved.  The Berkeley Software License Agreement
127c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
137c478bd9Sstevel@tonic-gate  */
147c478bd9Sstevel@tonic-gate 
157c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
167c478bd9Sstevel@tonic-gate 
177c478bd9Sstevel@tonic-gate #include "sh.h"
187c478bd9Sstevel@tonic-gate #include <dirent.h>
197c478bd9Sstevel@tonic-gate #include <string.h>
207c478bd9Sstevel@tonic-gate #include "sh.tconst.h"
217c478bd9Sstevel@tonic-gate #include "sh_policy.h"
227c478bd9Sstevel@tonic-gate 
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate /*
257c478bd9Sstevel@tonic-gate  * C shell
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * System level search and execute of a command.
307c478bd9Sstevel@tonic-gate  * We look in each directory for the specified command name.
317c478bd9Sstevel@tonic-gate  * If the name contains a '/' then we execute only the full path name.
327c478bd9Sstevel@tonic-gate  * If there is no search path then we execute only full path names.
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate /*
367c478bd9Sstevel@tonic-gate  * As we search for the command we note the first non-trivial error
377c478bd9Sstevel@tonic-gate  * message for presentation to the user.  This allows us often
387c478bd9Sstevel@tonic-gate  * to show that a file has the wrong mode/no access when the file
397c478bd9Sstevel@tonic-gate  * is not in the last component of the search path, so we must
407c478bd9Sstevel@tonic-gate  * go on after first detecting the error.
417c478bd9Sstevel@tonic-gate  */
427c478bd9Sstevel@tonic-gate char *exerr;			/* Execution error message */
437c478bd9Sstevel@tonic-gate 
446c02b4a4Smuffin void	pexerr(void);
456c02b4a4Smuffin void	texec(struct command *, tchar *, tchar **);
466c02b4a4Smuffin void	xechoit(tchar **);
476c02b4a4Smuffin void	dohash(char []);
487c478bd9Sstevel@tonic-gate 
496c02b4a4Smuffin static void	tconvert(struct command *, tchar *, tchar **);
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate 
526c02b4a4Smuffin extern DIR *opendir_(tchar *);
536c02b4a4Smuffin 
546c02b4a4Smuffin void
556c02b4a4Smuffin doexec(struct command *t)
567c478bd9Sstevel@tonic-gate {
577c478bd9Sstevel@tonic-gate 	tchar *sav;
586c02b4a4Smuffin 	tchar *dp, **pv, **av;
596c02b4a4Smuffin 	struct varent *v;
607c478bd9Sstevel@tonic-gate 	bool slash;
617c478bd9Sstevel@tonic-gate 	int hashval, hashval1, i;
627c478bd9Sstevel@tonic-gate 	tchar *blk[2];
637c478bd9Sstevel@tonic-gate #ifdef TRACE
647c478bd9Sstevel@tonic-gate 	tprintf("TRACE- doexec()\n");
657c478bd9Sstevel@tonic-gate #endif
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate 	/*
687c478bd9Sstevel@tonic-gate 	 * Glob the command name.  If this does anything, then we
697c478bd9Sstevel@tonic-gate 	 * will execute the command only relative to ".".  One special
707c478bd9Sstevel@tonic-gate 	 * case: if there is no PATH, then we execute only commands
717c478bd9Sstevel@tonic-gate 	 * which start with '/'.
727c478bd9Sstevel@tonic-gate 	 */
737c478bd9Sstevel@tonic-gate 	dp = globone(t->t_dcom[0]);
747c478bd9Sstevel@tonic-gate 	sav = t->t_dcom[0];
757c478bd9Sstevel@tonic-gate 	exerr = 0; t->t_dcom[0] = dp;
767c478bd9Sstevel@tonic-gate 	setname(dp);
777c478bd9Sstevel@tonic-gate 	xfree(sav);
787c478bd9Sstevel@tonic-gate 	v = adrof(S_path /* "path" */);
797c478bd9Sstevel@tonic-gate 	if (v == 0 && dp[0] != '/') {
807c478bd9Sstevel@tonic-gate 		pexerr();
817c478bd9Sstevel@tonic-gate 	}
827c478bd9Sstevel@tonic-gate 	slash = gflag;
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 	/*
857c478bd9Sstevel@tonic-gate 	 * Glob the argument list, if necessary.
867c478bd9Sstevel@tonic-gate 	 * Otherwise trim off the quote bits.
877c478bd9Sstevel@tonic-gate 	 */
887c478bd9Sstevel@tonic-gate 	gflag = 0; av = &t->t_dcom[1];
897c478bd9Sstevel@tonic-gate 	tglob(av);
907c478bd9Sstevel@tonic-gate 	if (gflag) {
917c478bd9Sstevel@tonic-gate 		av = glob(av);
927c478bd9Sstevel@tonic-gate 		if (av == 0)
937c478bd9Sstevel@tonic-gate 			error("No match");
947c478bd9Sstevel@tonic-gate 	}
957c478bd9Sstevel@tonic-gate 	blk[0] = t->t_dcom[0];
967c478bd9Sstevel@tonic-gate 	blk[1] = 0;
977c478bd9Sstevel@tonic-gate 	av = blkspl(blk, av);
987c478bd9Sstevel@tonic-gate #ifdef VFORK
997c478bd9Sstevel@tonic-gate 	Vav = av;
1007c478bd9Sstevel@tonic-gate #endif
1017c478bd9Sstevel@tonic-gate 	trim(av);
1027c478bd9Sstevel@tonic-gate 	slash |= any('/', av[0]);
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	xechoit(av);		/* Echo command if -x */
1057c478bd9Sstevel@tonic-gate 	/*
1067c478bd9Sstevel@tonic-gate 	 * Since all internal file descriptors are set to close on exec,
1077c478bd9Sstevel@tonic-gate 	 * we don't need to close them explicitly here.  Just reorient
1087c478bd9Sstevel@tonic-gate 	 * ourselves for error messages.
1097c478bd9Sstevel@tonic-gate 	 */
1107c478bd9Sstevel@tonic-gate 	SHIN = 0; SHOUT = 1; SHDIAG = 2; OLDSTD = 0;
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	/*
1137c478bd9Sstevel@tonic-gate 	 * We must do this AFTER any possible forking (like `foo`
1147c478bd9Sstevel@tonic-gate 	 * in glob) so that this shell can still do subprocesses.
1157c478bd9Sstevel@tonic-gate 	 */
1167c478bd9Sstevel@tonic-gate 	(void) sigsetmask(0);
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 	/*
1197c478bd9Sstevel@tonic-gate 	 * If no path, no words in path, or a / in the filename
1207c478bd9Sstevel@tonic-gate 	 * then restrict the command search.
1217c478bd9Sstevel@tonic-gate 	 */
1227c478bd9Sstevel@tonic-gate 	if (v == 0 || v->vec[0] == 0 || slash)
1237c478bd9Sstevel@tonic-gate 		pv = justabs;
1247c478bd9Sstevel@tonic-gate 	else
1257c478bd9Sstevel@tonic-gate 		pv = v->vec;
1267c478bd9Sstevel@tonic-gate 	sav = strspl(S_SLASH /* "/" */, *av); /* / command name for postpending */
1277c478bd9Sstevel@tonic-gate #ifdef VFORK
1287c478bd9Sstevel@tonic-gate 	Vsav = sav;
1297c478bd9Sstevel@tonic-gate #endif
1307c478bd9Sstevel@tonic-gate 	if (havhash)
1317c478bd9Sstevel@tonic-gate 		hashval = hashname(*av);
1327c478bd9Sstevel@tonic-gate 	i = 0;
1337c478bd9Sstevel@tonic-gate #ifdef VFORK
1347c478bd9Sstevel@tonic-gate 	hits++;
1357c478bd9Sstevel@tonic-gate #endif
1367c478bd9Sstevel@tonic-gate 	do {
1377c478bd9Sstevel@tonic-gate 		if (!slash && pv[0][0] == '/' && havhash) {
1387c478bd9Sstevel@tonic-gate 			hashval1 = hash(hashval, i);
1397c478bd9Sstevel@tonic-gate 			if (!bit(xhash, hashval1))
1407c478bd9Sstevel@tonic-gate 				goto cont;
1417c478bd9Sstevel@tonic-gate 		}
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 		if (pv[0][0] == 0 || eq(pv[0], S_DOT /* "." */)) { /* don't make ./xxx */
1447c478bd9Sstevel@tonic-gate 			texec(t, *av, av);
1457c478bd9Sstevel@tonic-gate 		} else {
1467c478bd9Sstevel@tonic-gate 			dp = strspl(*pv, sav);
1477c478bd9Sstevel@tonic-gate #ifdef VFORK
1487c478bd9Sstevel@tonic-gate 			Vdp = dp;
1497c478bd9Sstevel@tonic-gate #endif
1507c478bd9Sstevel@tonic-gate 			texec(t, dp, av);
1517c478bd9Sstevel@tonic-gate #ifdef VFORK
1527c478bd9Sstevel@tonic-gate 			Vdp = 0;
1537c478bd9Sstevel@tonic-gate #endif
1547c478bd9Sstevel@tonic-gate 			xfree(dp);
1557c478bd9Sstevel@tonic-gate 		}
1567c478bd9Sstevel@tonic-gate #ifdef VFORK
1577c478bd9Sstevel@tonic-gate 		misses++;
1587c478bd9Sstevel@tonic-gate #endif
1597c478bd9Sstevel@tonic-gate cont:
1607c478bd9Sstevel@tonic-gate 		pv++;
1617c478bd9Sstevel@tonic-gate 		i++;
1627c478bd9Sstevel@tonic-gate 	} while (*pv);
1637c478bd9Sstevel@tonic-gate #ifdef VFORK
1647c478bd9Sstevel@tonic-gate 	hits--;
1657c478bd9Sstevel@tonic-gate #endif
1667c478bd9Sstevel@tonic-gate #ifdef VFORK
1677c478bd9Sstevel@tonic-gate 	Vsav = 0;
1687c478bd9Sstevel@tonic-gate 	Vav = 0;
1697c478bd9Sstevel@tonic-gate #endif
1707c478bd9Sstevel@tonic-gate 	xfree(sav);
1717c478bd9Sstevel@tonic-gate 	xfree((char *)av);
1727c478bd9Sstevel@tonic-gate 	pexerr();
1737c478bd9Sstevel@tonic-gate }
1747c478bd9Sstevel@tonic-gate 
1756c02b4a4Smuffin void
1766c02b4a4Smuffin pexerr(void)
1777c478bd9Sstevel@tonic-gate {
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate #ifdef TRACE
1807c478bd9Sstevel@tonic-gate 	tprintf("TRACE- pexerr()\n");
1817c478bd9Sstevel@tonic-gate #endif
1827c478bd9Sstevel@tonic-gate 	/* Couldn't find the damn thing */
1837c478bd9Sstevel@tonic-gate 	if (exerr)
1847c478bd9Sstevel@tonic-gate 		bferr(exerr);
1857c478bd9Sstevel@tonic-gate 	bferr("Command not found");
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate /*
1897c478bd9Sstevel@tonic-gate  * Execute command f, arg list t.
1907c478bd9Sstevel@tonic-gate  * Record error message if not found.
1917c478bd9Sstevel@tonic-gate  * Also do shell scripts here.
1927c478bd9Sstevel@tonic-gate  */
1936c02b4a4Smuffin void
1946c02b4a4Smuffin texec(struct command *cmd, tchar *f, tchar **t)
1957c478bd9Sstevel@tonic-gate {
1966c02b4a4Smuffin 	int	pfstatus = 0;
1976c02b4a4Smuffin 	struct	varent *v;
1986c02b4a4Smuffin 	tchar	**vp;
1997c478bd9Sstevel@tonic-gate 	tchar		*lastsh[2];
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate #ifdef TRACE
2027c478bd9Sstevel@tonic-gate 	tprintf("TRACE- texec()\n");
2037c478bd9Sstevel@tonic-gate #endif
2047c478bd9Sstevel@tonic-gate 	/* convert cfname and cargs from tchar to char */
2057c478bd9Sstevel@tonic-gate 	tconvert(cmd, f, t);
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	if (pfcshflag == 1) {
2087c478bd9Sstevel@tonic-gate 		pfstatus = secpolicy_pfexec((const char *)(cmd->cfname),
2097c478bd9Sstevel@tonic-gate 		    cmd->cargs, (const char **)NULL);
2107c478bd9Sstevel@tonic-gate 		if (pfstatus != NOATTRS) {
2117c478bd9Sstevel@tonic-gate 			errno = pfstatus;
2127c478bd9Sstevel@tonic-gate 		}
2137c478bd9Sstevel@tonic-gate 	}
2147c478bd9Sstevel@tonic-gate 	if ((pfcshflag == 0) || (pfstatus == NOATTRS)) {
2157c478bd9Sstevel@tonic-gate 		execv(cmd->cfname, cmd->cargs);
2167c478bd9Sstevel@tonic-gate 	}
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	/*
2197c478bd9Sstevel@tonic-gate 	 * exec returned, free up allocations from above
2207c478bd9Sstevel@tonic-gate 	 * tconvert(), zero cfname and cargs to prevent
2217c478bd9Sstevel@tonic-gate 	 * duplicate free() in freesyn()
2227c478bd9Sstevel@tonic-gate 	 */
2237c478bd9Sstevel@tonic-gate 	xfree(cmd->cfname);
2247c478bd9Sstevel@tonic-gate 	chr_blkfree(cmd->cargs);
2257c478bd9Sstevel@tonic-gate 	cmd->cfname = (char *)0;
2267c478bd9Sstevel@tonic-gate 	cmd->cargs = (char **)0;
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	switch (errno) {
2297c478bd9Sstevel@tonic-gate 	case ENOEXEC:
2307c478bd9Sstevel@tonic-gate 		/* check that this is not a binary file */
2317c478bd9Sstevel@tonic-gate 		{
2326c02b4a4Smuffin 			int ff = open_(f, 0);
233*65b0c20eSnakanon 			tchar ch[MB_LEN_MAX];
2347c478bd9Sstevel@tonic-gate 
235*65b0c20eSnakanon 			if (ff != -1 && read_(ff, ch, 1) == 1 &&
236*65b0c20eSnakanon 			    !isprint(ch[0]) && !isspace(ch[0])) {
2377c478bd9Sstevel@tonic-gate 				printf("Cannot execute binary file.\n");
2387c478bd9Sstevel@tonic-gate 				Perror(f);
2397c478bd9Sstevel@tonic-gate 				(void) close(ff);
2407c478bd9Sstevel@tonic-gate 				unsetfd(ff);
2417c478bd9Sstevel@tonic-gate 				return;
2427c478bd9Sstevel@tonic-gate 			}
2437c478bd9Sstevel@tonic-gate 			(void) close(ff);
2447c478bd9Sstevel@tonic-gate 			unsetfd(ff);
2457c478bd9Sstevel@tonic-gate 		}
2467c478bd9Sstevel@tonic-gate 		/*
2477c478bd9Sstevel@tonic-gate 		 * If there is an alias for shell, then
2487c478bd9Sstevel@tonic-gate 		 * put the words of the alias in front of the
2497c478bd9Sstevel@tonic-gate 		 * argument list replacing the command name.
2507c478bd9Sstevel@tonic-gate 		 * Note no interpretation of the words at this point.
2517c478bd9Sstevel@tonic-gate 		 */
2527c478bd9Sstevel@tonic-gate 		v = adrof1(S_shell /* "shell" */, &aliases);
2537c478bd9Sstevel@tonic-gate 		if (v == 0) {
2547c478bd9Sstevel@tonic-gate #ifdef OTHERSH
2556c02b4a4Smuffin 			int ff = open_(f, 0);
256*65b0c20eSnakanon 			tchar ch[MB_LEN_MAX];
2577c478bd9Sstevel@tonic-gate #endif
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 			vp = lastsh;
2607c478bd9Sstevel@tonic-gate 			vp[0] = adrof(S_shell /* "shell" */) ? value(S_shell /* "shell" */) : S_SHELLPATH /* SHELLPATH */;
2617c478bd9Sstevel@tonic-gate 			vp[1] =  (tchar *) NULL;
2627c478bd9Sstevel@tonic-gate #ifdef OTHERSH
263*65b0c20eSnakanon 			if (ff != -1 && read_(ff, ch, 1) == 1 && ch[0] != '#')
2647c478bd9Sstevel@tonic-gate 				vp[0] = S_OTHERSH /* OTHERSH */;
2657c478bd9Sstevel@tonic-gate 			(void) close(ff);
2667c478bd9Sstevel@tonic-gate 			unsetfd(ff);
2677c478bd9Sstevel@tonic-gate #endif
2687c478bd9Sstevel@tonic-gate 		} else
2697c478bd9Sstevel@tonic-gate 			vp = v->vec;
2707c478bd9Sstevel@tonic-gate 		t[0] = f;
2717c478bd9Sstevel@tonic-gate 		t = blkspl(vp, t);		/* Splice up the new arglst */
2727c478bd9Sstevel@tonic-gate 		f = *t;
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 		tconvert(cmd, f, t);		/* convert tchar to char */
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 		/*
2777c478bd9Sstevel@tonic-gate 		 * now done with tchar arg list t,
2787c478bd9Sstevel@tonic-gate 		 * free the space calloc'd by above blkspl()
2797c478bd9Sstevel@tonic-gate 		 */
2807c478bd9Sstevel@tonic-gate 		xfree((char *)t);
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 		execv(cmd->cfname, cmd->cargs);	/* exec the command */
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 		/* exec returned, same free'ing as above */
2857c478bd9Sstevel@tonic-gate 		xfree(cmd->cfname);
2867c478bd9Sstevel@tonic-gate 		chr_blkfree(cmd->cargs);
2877c478bd9Sstevel@tonic-gate 		cmd->cfname = (char *)0;
2887c478bd9Sstevel@tonic-gate 		cmd->cargs = (char **)0;
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 		/* The sky is falling, the sky is falling! */
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	case ENOMEM:
2937c478bd9Sstevel@tonic-gate 		Perror(f);
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	case ENOENT:
2967c478bd9Sstevel@tonic-gate 		break;
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	default:
2997c478bd9Sstevel@tonic-gate 		if (exerr == 0) {
3007c478bd9Sstevel@tonic-gate 			exerr = strerror(errno);
3017c478bd9Sstevel@tonic-gate 			setname(f);
3027c478bd9Sstevel@tonic-gate 		}
3037c478bd9Sstevel@tonic-gate 	}
3047c478bd9Sstevel@tonic-gate }
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 
3076c02b4a4Smuffin static void
3086c02b4a4Smuffin tconvert(struct command *cmd, tchar *fname, tchar **list)
3097c478bd9Sstevel@tonic-gate {
3106c02b4a4Smuffin 	char **rc;
3116c02b4a4Smuffin 	int len;
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	cmd->cfname = tstostr(NULL, fname);
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	len = blklen(list);
3167c478bd9Sstevel@tonic-gate 	rc = cmd->cargs = (char **)
317*65b0c20eSnakanon 		xcalloc((uint_t)(len + 1), sizeof (char **));
3187c478bd9Sstevel@tonic-gate 	while (len--)
3197c478bd9Sstevel@tonic-gate 		*rc++ = tstostr(NULL, *list++);
3207c478bd9Sstevel@tonic-gate 	*rc = NULL;
3217c478bd9Sstevel@tonic-gate }
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3256c02b4a4Smuffin void
3266c02b4a4Smuffin execash(tchar **t, struct command *kp)
3277c478bd9Sstevel@tonic-gate {
3287c478bd9Sstevel@tonic-gate #ifdef TRACE
3297c478bd9Sstevel@tonic-gate 	tprintf("TRACE- execash()\n");
3307c478bd9Sstevel@tonic-gate #endif
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	rechist();
3337c478bd9Sstevel@tonic-gate 	(void) signal(SIGINT, parintr);
3347c478bd9Sstevel@tonic-gate 	(void) signal(SIGQUIT, parintr);
3357c478bd9Sstevel@tonic-gate 	(void) signal(SIGTERM, parterm);	/* if doexec loses, screw */
3367c478bd9Sstevel@tonic-gate 	lshift(kp->t_dcom, 1);
3377c478bd9Sstevel@tonic-gate 	exiterr++;
3387c478bd9Sstevel@tonic-gate 	doexec(kp);
3397c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
3407c478bd9Sstevel@tonic-gate }
3417c478bd9Sstevel@tonic-gate 
3426c02b4a4Smuffin void
3436c02b4a4Smuffin xechoit(tchar **t)
3447c478bd9Sstevel@tonic-gate {
3457c478bd9Sstevel@tonic-gate #ifdef TRACE
3467c478bd9Sstevel@tonic-gate 	tprintf("TRACE- xechoit()\n");
3477c478bd9Sstevel@tonic-gate #endif
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	if (adrof(S_echo /* "echo" */)) {
3507c478bd9Sstevel@tonic-gate 		flush();
3517c478bd9Sstevel@tonic-gate 		haderr = 1;
3527c478bd9Sstevel@tonic-gate 		blkpr(t), Putchar('\n');
3537c478bd9Sstevel@tonic-gate 		haderr = 0;
3547c478bd9Sstevel@tonic-gate 	}
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate /*
3587c478bd9Sstevel@tonic-gate  * This routine called when user enters "rehash".
3597c478bd9Sstevel@tonic-gate  * Both the path and cdpath caching arrays will
3607c478bd9Sstevel@tonic-gate  * be rehashed, via calling dohash.  If either
3617c478bd9Sstevel@tonic-gate  * variable is not set with a value, then dohash
3627c478bd9Sstevel@tonic-gate  * just exits.
3637c478bd9Sstevel@tonic-gate  */
3646c02b4a4Smuffin void
3656c02b4a4Smuffin dorehash(void)
3667c478bd9Sstevel@tonic-gate {
3677c478bd9Sstevel@tonic-gate 	dohash(xhash);
3687c478bd9Sstevel@tonic-gate 	dohash(xhash2);
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate /*
3727c478bd9Sstevel@tonic-gate  * Fill up caching arrays for path and cdpath
3737c478bd9Sstevel@tonic-gate  */
3746c02b4a4Smuffin void
3756c02b4a4Smuffin dohash(char cachearray[])
3767c478bd9Sstevel@tonic-gate {
3777c478bd9Sstevel@tonic-gate 	struct stat stb;
3787c478bd9Sstevel@tonic-gate 	DIR *dirp;
3796c02b4a4Smuffin 	struct dirent *dp;
3806c02b4a4Smuffin 	int cnt;
3817c478bd9Sstevel@tonic-gate 	int i = 0;
3827c478bd9Sstevel@tonic-gate 	struct varent *v;
3837c478bd9Sstevel@tonic-gate 	tchar **pv;
3847c478bd9Sstevel@tonic-gate 	int hashval;
3857c478bd9Sstevel@tonic-gate 	tchar curdir_[MAXNAMLEN+1];
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate #ifdef TRACE
3887c478bd9Sstevel@tonic-gate 	tprintf("TRACE- dohash()\n");
3897c478bd9Sstevel@tonic-gate #endif
3907c478bd9Sstevel@tonic-gate 	/* Caching $path */
3917c478bd9Sstevel@tonic-gate 	if (cachearray == xhash) {
3927c478bd9Sstevel@tonic-gate 		havhash = 1;
3937c478bd9Sstevel@tonic-gate 		v = adrof(S_path /* "path" */);
3947c478bd9Sstevel@tonic-gate 	} else {    /* Caching $cdpath */
3957c478bd9Sstevel@tonic-gate 		havhash2 = 1;
3967c478bd9Sstevel@tonic-gate 		v = adrof(S_cdpath /* "cdpath" */);
3977c478bd9Sstevel@tonic-gate 	}
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	for (cnt = 0; cnt < (HSHSIZ / 8); cnt++)
4007c478bd9Sstevel@tonic-gate 		cachearray[cnt] = 0;
4017c478bd9Sstevel@tonic-gate 	if (v == 0)
4027c478bd9Sstevel@tonic-gate 		{
4037c478bd9Sstevel@tonic-gate 		return;
4047c478bd9Sstevel@tonic-gate 		}
4057c478bd9Sstevel@tonic-gate 	for (pv = v->vec; *pv; pv++, i++) {
4067c478bd9Sstevel@tonic-gate 		if (pv[0][0] != '/')
4077c478bd9Sstevel@tonic-gate 			continue;
4087c478bd9Sstevel@tonic-gate 		dirp = opendir_(*pv);
4097c478bd9Sstevel@tonic-gate 		if (dirp == NULL)
4107c478bd9Sstevel@tonic-gate 			continue;
4117c478bd9Sstevel@tonic-gate 		if (fstat(dirp->dd_fd, &stb) < 0 || !isdir(stb)) {
4127c478bd9Sstevel@tonic-gate 			unsetfd(dirp->dd_fd);
4137c478bd9Sstevel@tonic-gate 			closedir_(dirp);
4147c478bd9Sstevel@tonic-gate 			continue;
4157c478bd9Sstevel@tonic-gate 		}
4167c478bd9Sstevel@tonic-gate 		while ((dp = readdir(dirp)) != NULL) {
4177c478bd9Sstevel@tonic-gate 			if (dp->d_ino == 0)
4187c478bd9Sstevel@tonic-gate 				continue;
4197c478bd9Sstevel@tonic-gate 			if (dp->d_name[0] == '.' &&
4207c478bd9Sstevel@tonic-gate 			    (dp->d_name[1] == '\0' ||
4217c478bd9Sstevel@tonic-gate 			    dp->d_name[1] == '.' && dp->d_name[2] == '\0'))
4227c478bd9Sstevel@tonic-gate 				continue;
4237c478bd9Sstevel@tonic-gate 			hashval = hash(hashname(strtots(curdir_, dp->d_name)), i);
4247c478bd9Sstevel@tonic-gate 			bis(cachearray, hashval);
4257c478bd9Sstevel@tonic-gate 		}
4267c478bd9Sstevel@tonic-gate 		unsetfd(dirp->dd_fd);
4277c478bd9Sstevel@tonic-gate 		closedir_(dirp);
4287c478bd9Sstevel@tonic-gate 	}
4297c478bd9Sstevel@tonic-gate }
4307c478bd9Sstevel@tonic-gate 
4316c02b4a4Smuffin void
4326c02b4a4Smuffin dounhash(void)
4337c478bd9Sstevel@tonic-gate {
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate #ifdef TRACE
4367c478bd9Sstevel@tonic-gate 	tprintf("TRACE- dounhash()\n");
4377c478bd9Sstevel@tonic-gate #endif
4387c478bd9Sstevel@tonic-gate 	havhash = 0;
4397c478bd9Sstevel@tonic-gate 	havhash2 = 0;
4407c478bd9Sstevel@tonic-gate }
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate #ifdef VFORK
4436c02b4a4Smuffin void
4446c02b4a4Smuffin hashstat(void)
4457c478bd9Sstevel@tonic-gate {
4467c478bd9Sstevel@tonic-gate #ifdef TRACE
4477c478bd9Sstevel@tonic-gate 	tprintf("TRACE- hashstat_()\n");
4487c478bd9Sstevel@tonic-gate #endif
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	if (hits+misses)
4517c478bd9Sstevel@tonic-gate 		printf("%d hits, %d misses, %d%%\n",
4527c478bd9Sstevel@tonic-gate 			hits, misses, 100 * hits / (hits + misses));
4537c478bd9Sstevel@tonic-gate }
4547c478bd9Sstevel@tonic-gate #endif
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate /*
4577c478bd9Sstevel@tonic-gate  * Hash a command name.
4587c478bd9Sstevel@tonic-gate  */
4596c02b4a4Smuffin int
4606c02b4a4Smuffin hashname(tchar *cp)
4617c478bd9Sstevel@tonic-gate {
4626c02b4a4Smuffin 	long h = 0;
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate #ifdef TRACE
4657c478bd9Sstevel@tonic-gate 	tprintf("TRACE- hashname()\n");
4667c478bd9Sstevel@tonic-gate #endif
4677c478bd9Sstevel@tonic-gate 	while (*cp)
4687c478bd9Sstevel@tonic-gate 		h = hash(h, *cp++);
4697c478bd9Sstevel@tonic-gate 	return ((int)h);
4707c478bd9Sstevel@tonic-gate }
471