xref: /onnv-gate/usr/src/lib/libshell/common/sh/path.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1982-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                  David Korn <dgk@research.att.com>                   *
184887Schin *                                                                      *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin  * David Korn
234887Schin  * AT&T Labs
244887Schin  *
254887Schin  */
264887Schin 
274887Schin #include	"defs.h"
284887Schin #include	<fcin.h>
294887Schin #include	<ls.h>
304887Schin #include	<nval.h>
314887Schin #include	"variables.h"
324887Schin #include	"path.h"
334887Schin #include	"io.h"
344887Schin #include	"jobs.h"
354887Schin #include	"history.h"
364887Schin #include	"test.h"
378462SApril.Chin@Sun.COM #include	"FEATURE/dynamic"
384887Schin #include	"FEATURE/externs"
394887Schin #if SHOPT_PFSH
404887Schin #   ifdef _hdr_exec_attr
414887Schin #	include	<exec_attr.h>
424887Schin #   endif
438462SApril.Chin@Sun.COM #   if     _lib_vfork
448462SApril.Chin@Sun.COM #	include     <ast_vfork.h>
458462SApril.Chin@Sun.COM #   else
468462SApril.Chin@Sun.COM #	define vfork()      fork()
478462SApril.Chin@Sun.COM #   endif
484887Schin #endif
494887Schin 
504887Schin #define RW_ALL	(S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH)
514887Schin #define LIBCMD	"cmd"
524887Schin 
534887Schin 
544887Schin static int		canexecute(char*,int);
554887Schin static void		funload(Shell_t*,int,const char*);
564887Schin static void		exscript(Shell_t*,char*, char*[], char**);
574887Schin static int		path_chkpaths(Pathcomp_t*,Pathcomp_t*,Pathcomp_t*,int);
5810898Sroland.mainz@nrubsig.org static void		path_checkdup(register Pathcomp_t*);
594887Schin 
604887Schin static const char	*std_path;
614887Schin 
onstdpath(const char * name)624887Schin static int onstdpath(const char *name)
634887Schin {
644887Schin 	register const char *cp = std_path, *sp;
654887Schin 	if(cp)
664887Schin 		while(*cp)
674887Schin 		{
684887Schin 			for(sp=name; *sp && (*cp == *sp); sp++,cp++);
694887Schin 			if(*sp==0 && (*cp==0 || *cp==':'))
704887Schin 				return(1);
714887Schin 			while(*cp && *cp++!=':');
724887Schin 		}
734887Schin 	return(0);
744887Schin }
754887Schin 
path_pfexecve(const char * path,char * argv[],char * const envp[],int spawn)768462SApril.Chin@Sun.COM static pid_t path_pfexecve(const char *path, char *argv[],char *const envp[],int spawn)
774887Schin {
784887Schin #if SHOPT_PFSH
798462SApril.Chin@Sun.COM 	pid_t	pid;
804887Schin 	char  resolvedpath[PATH_MAX + 1];
818462SApril.Chin@Sun.COM 	if(spawn)
828462SApril.Chin@Sun.COM 	{
838462SApril.Chin@Sun.COM 		while((pid = vfork()) < 0)
848462SApril.Chin@Sun.COM 			_sh_fork(pid, 0, (int*)0);
858462SApril.Chin@Sun.COM 		if(pid)
868462SApril.Chin@Sun.COM 			return(pid);
878462SApril.Chin@Sun.COM 	}
884887Schin 	if(!sh_isoption(SH_PFSH))
894887Schin 		return(execve(path, argv, envp));
904887Schin 	/* Solaris implements realpath(3C) using the resolvepath(2) */
914887Schin 	/* system call so we can save us to call access(2) first */
924887Schin 	if (!realpath(path, resolvedpath))
934887Schin 		return -1;
944887Schin 
954887Schin 	/* we can exec the command directly instead of via pfexec(1) if */
964887Schin 	/* there is a matching entry without attributes in exec_attr(4) */
974887Schin 	if (sh.user && *sh.user)
984887Schin 	{
994887Schin 		execattr_t *pf;
1004887Schin 		if(pf=getexecuser(sh.user, KV_COMMAND, resolvedpath, GET_ONE))
1014887Schin 		{
1024887Schin 			if (!pf->attr || pf->attr->length == 0)
1034887Schin 			{
1044887Schin 				int r = execve(path, argv, envp);
1054887Schin 				free_execattr(pf);
1064887Schin 				return r;
1074887Schin 			}
1084887Schin 			free_execattr(pf);
1094887Schin 		}
1104887Schin 		else
1114887Schin 		{
1124887Schin 			errno = ENOENT;
1134887Schin 			return -1;
1144887Schin 		}
1154887Schin 	}
1164887Schin 	--argv;
1174887Schin 	argv[0] = argv[1];
1184887Schin 	argv[1] = resolvedpath;
1194887Schin 	return(execve("/usr/bin/pfexec", argv, envp));
1204887Schin #else
1214887Schin 	return(execve(path, argv, envp));
1224887Schin #endif
1234887Schin }
1244887Schin 
1254887Schin 
_spawnveg(const char * path,char * const argv[],char * const envp[],pid_t pgid)1268462SApril.Chin@Sun.COM static pid_t _spawnveg(const char *path, char* const argv[], char* const envp[], pid_t pgid)
1274887Schin {
1284887Schin 	int waitsafe = job.waitsafe;
1298462SApril.Chin@Sun.COM 	pid_t pid;
1304887Schin 	job_lock();
1318462SApril.Chin@Sun.COM 	while(1)
1328462SApril.Chin@Sun.COM 	{
1338462SApril.Chin@Sun.COM 		sh_stats(STAT_SPAWN);
1348462SApril.Chin@Sun.COM 		pid = spawnveg(path,argv,envp,pgid);
1358462SApril.Chin@Sun.COM 		if(pid>=0 || errno!=EAGAIN)
1368462SApril.Chin@Sun.COM 			break;
1378462SApril.Chin@Sun.COM 		_sh_fork(pid, 0, (int*)0);
1388462SApril.Chin@Sun.COM 	}
1394887Schin 	job.waitsafe = waitsafe;
140*12068SRoger.Faulkner@Oracle.COM 	if(pid>0)
141*12068SRoger.Faulkner@Oracle.COM 		job_fork(pid);
142*12068SRoger.Faulkner@Oracle.COM 	else
143*12068SRoger.Faulkner@Oracle.COM 		job_unlock();
1444887Schin 	return(pid);
1454887Schin }
1464887Schin /*
1474887Schin  * used with command -x to run the command in multiple passes
1484887Schin  * spawn is non-zero when invoked via spawn
1494887Schin  * the exitval is set to the maximum for each execution
1504887Schin  */
path_xargs(const char * path,char * argv[],char * const envp[],int spawn)1514887Schin static pid_t path_xargs(const char *path, char *argv[],char *const envp[], int spawn)
1524887Schin {
1534887Schin 	register char *cp, **av, **xv;
1544887Schin 	char **avlast= &argv[sh.xargmax], **saveargs=0;
1554887Schin 	char *const *ev;
1564887Schin 	long size, left;
1574887Schin 	int nlast=1,n,exitval=0;
1584887Schin 	pid_t pid;
1594887Schin 	if(sh.xargmin < 0)
1604887Schin 		return((pid_t)-1);
1614887Schin 	size = sh.lim.arg_max-1024;
1624887Schin 	for(ev=envp; cp= *ev; ev++)
1634887Schin 		size -= strlen(cp)-1;
1644887Schin 	for(av=argv; (cp= *av) && av< &argv[sh.xargmin]; av++)
1654887Schin 		size -= strlen(cp)-1;
1664887Schin 	for(av=avlast; cp= *av; av++,nlast++)
1674887Schin 		size -= strlen(cp)-1;
1684887Schin 	av =  &argv[sh.xargmin];
1694887Schin 	if(!spawn)
1704887Schin 		job_clear();
1714887Schin 	sh.exitval = 0;
1724887Schin 	while(av<avlast)
1734887Schin 	{
1744887Schin 		for(xv=av,left=size; left>0 && av<avlast;)
1754887Schin 			left -= strlen(*av++)+1;
1764887Schin 		/* leave at least two for last */
1774887Schin 		if(left<0 && (avlast-av)<2)
1784887Schin 			av--;
1794887Schin 		if(xv==&argv[sh.xargmin])
1804887Schin 		{
1814887Schin 			n = nlast*sizeof(char*);
1824887Schin 			saveargs = (char**)malloc(n);
1834887Schin 			memcpy((void*)saveargs, (void*)av, n);
1844887Schin 			memcpy((void*)av,(void*)avlast,n);
1854887Schin 		}
1864887Schin 		else
1874887Schin 		{
1884887Schin 			for(n=sh.xargmin; xv < av; xv++)
1894887Schin 				argv[n++] = *xv;
1904887Schin 			for(xv=avlast; cp=  *xv; xv++)
1914887Schin 				argv[n++] = cp;
1924887Schin 			argv[n] = 0;
1934887Schin 		}
1944887Schin 		if(saveargs || av<avlast || (exitval && !spawn))
1954887Schin 		{
1964887Schin 			if((pid=_spawnveg(path,argv,envp,0)) < 0)
1974887Schin 				return(-1);
1984887Schin 			job_post(pid,0);
1994887Schin 			job_wait(pid);
2004887Schin 			if(sh.exitval>exitval)
2014887Schin 				exitval = sh.exitval;
2024887Schin 			if(saveargs)
2034887Schin 			{
2044887Schin 				memcpy((void*)av,saveargs,n);
2054887Schin 				free((void*)saveargs);
2064887Schin 				saveargs = 0;
2074887Schin 			}
2084887Schin 		}
2094887Schin 		else if(spawn && !sh_isoption(SH_PFSH))
2104887Schin 		{
2114887Schin 			sh.xargexit = exitval;
2124887Schin 			return(_spawnveg(path,argv,envp,spawn>>1));
2134887Schin 		}
2144887Schin 		else
2158462SApril.Chin@Sun.COM 			return(path_pfexecve(path,argv,envp,spawn));
2164887Schin 	}
2174887Schin 	if(!spawn)
2184887Schin 		exit(exitval);
2194887Schin 	return((pid_t)-1);
2204887Schin }
2214887Schin 
2224887Schin /*
2234887Schin  * make sure PWD is set up correctly
2244887Schin  * Return the present working directory
2254887Schin  * Invokes getcwd() if flag==0 and if necessary
2264887Schin  * Sets the PWD variable to this value
2274887Schin  */
path_pwd(int flag)2284887Schin char *path_pwd(int flag)
2294887Schin {
2304887Schin 	register char *cp;
2314887Schin 	register char *dfault = (char*)e_dot;
2324887Schin 	register int count = 0;
2334887Schin 	Shell_t *shp = &sh;
2344887Schin 	if(shp->pwd)
2354887Schin 		return((char*)shp->pwd);
2364887Schin 	while(1)
2374887Schin 	{
2384887Schin 		/* try from lowest to highest */
2394887Schin 		switch(count++)
2404887Schin 		{
2414887Schin 			case 0:
2424887Schin 				cp = nv_getval(PWDNOD);
2434887Schin 				break;
2444887Schin 			case 1:
2454887Schin 				cp = nv_getval(HOME);
2464887Schin 				break;
2474887Schin 			case 2:
2484887Schin 				cp = "/";
2494887Schin 				break;
2504887Schin 			case 3:
2514887Schin 				cp = (char*)e_crondir;
2524887Schin 				if(flag) /* skip next case when non-zero flag */
2534887Schin 					++count;
2544887Schin 				break;
2554887Schin 			case 4:
2564887Schin 			{
2574887Schin 				if(cp=getcwd(NIL(char*),0))
2584887Schin 				{
2594887Schin 					nv_offattr(PWDNOD,NV_NOFREE);
2604887Schin 					nv_unset(PWDNOD);
2614887Schin 					PWDNOD->nvalue.cp = cp;
2624887Schin 					goto skip;
2634887Schin 				}
2644887Schin 				break;
2654887Schin 			}
2664887Schin 			case 5:
2674887Schin 				return(dfault);
2684887Schin 		}
2694887Schin 		if(cp && *cp=='/' && test_inode(cp,e_dot))
2704887Schin 			break;
2714887Schin 	}
2724887Schin 	if(count>1)
2734887Schin 	{
2744887Schin 		nv_offattr(PWDNOD,NV_NOFREE);
2754887Schin 		nv_putval(PWDNOD,cp,NV_RDONLY);
2764887Schin 	}
2774887Schin skip:
2784887Schin 	nv_onattr(PWDNOD,NV_NOFREE|NV_EXPORT);
2794887Schin 	shp->pwd = (char*)(PWDNOD->nvalue.cp);
2804887Schin 	return(cp);
2814887Schin }
2824887Schin 
free_bltin(Namval_t * np,void * data)2834887Schin static void free_bltin(Namval_t *np,void *data)
2844887Schin {
2854887Schin 	register Pathcomp_t *pp= (Pathcomp_t*)data;
2864887Schin 	if(pp->flags&PATH_STD_DIR)
2874887Schin 	{
2884887Schin 		int offset=staktell();;
2894887Schin 		if(strcmp(pp->name,"/bin")==0 || memcmp(pp->name,np->nvname,pp->len) || np->nvname[pp->len]!='/')
2904887Schin 			return;
2914887Schin 		stakputs("/bin");
2924887Schin 		stakputs(np->nvname+pp->len+1);
2934887Schin 		stakputc(0);
2944887Schin 		sh_addbuiltin(stakptr(offset),np->nvalue.bfp,NiL);
2954887Schin 		stakseek(offset);
2964887Schin 		return;
2974887Schin 	}
2984887Schin 	if((void*)np->nvenv==pp->bltin_lib)
2998462SApril.Chin@Sun.COM 		nv_delete(np,sh_bltin_tree(),NV_NOFREE);
3004887Schin }
3014887Schin 
3024887Schin /*
3034887Schin  * delete current Pathcomp_t structure
3044887Schin  */
path_delete(Pathcomp_t * first)3054887Schin void  path_delete(Pathcomp_t *first)
3064887Schin {
3074887Schin 	register Pathcomp_t *pp=first, *old=0, *ppnext;
3084887Schin 	while(pp)
3094887Schin 	{
3104887Schin 		ppnext = pp->next;
3114887Schin 		if(--pp->refcount<=0)
3124887Schin 		{
3134887Schin 			if(pp->lib)
3144887Schin 				free((void*)pp->lib);
3154887Schin 			if(pp->blib)
3164887Schin 				free((void*)pp->blib);
3174887Schin 			if(pp->bltin_lib || (pp->flags&PATH_STD_DIR))
3184887Schin 			{
3194887Schin 				nv_scan(sh_bltin_tree(),free_bltin,pp,0,0);
3208462SApril.Chin@Sun.COM #if SHOPT_DYNAMIC
3214887Schin 				if(pp->bltin_lib)
3224887Schin 					dlclose(pp->bltin_lib);
3238462SApril.Chin@Sun.COM #endif /* SHOPT_DYNAMIC */
3244887Schin 			}
3254887Schin 			free((void*)pp);
3264887Schin 			if(old)
3274887Schin 				old->next = ppnext;
3284887Schin 		}
3294887Schin 		else
3304887Schin 			old = pp;
3314887Schin 		pp = ppnext;
3324887Schin 	}
3334887Schin }
3344887Schin 
3354887Schin /*
3364887Schin  * returns library variable from .paths
3374887Schin  * The value might be returned on the stack overwriting path
3384887Schin  */
path_lib(Pathcomp_t * pp,char * path)3394887Schin static char *path_lib(Pathcomp_t *pp, char *path)
3404887Schin {
3414887Schin 	register char *last = strrchr(path,'/');
3424887Schin 	register int r;
3434887Schin 	struct stat statb;
3444887Schin 	if(last)
3454887Schin 		*last = 0;
3464887Schin 	else
3474887Schin 		path = ".";
3484887Schin 	r = stat(path,&statb);
3494887Schin 	if(last)
3504887Schin 		*last = '/';
3514887Schin 	if(r>=0)
3524887Schin 	{
3534887Schin 		Pathcomp_t pcomp;
3544887Schin 		char save[8];
3554887Schin 		for( ;pp; pp=pp->next)
3564887Schin 		{
35710898Sroland.mainz@nrubsig.org 			path_checkdup(pp);
3588462SApril.Chin@Sun.COM 			if(pp->ino==statb.st_ino && pp->dev==statb.st_dev && pp->mtime==statb.st_mtime)
3594887Schin 				return(pp->lib);
3604887Schin 		}
3614887Schin 		pcomp.len = 0;
3624887Schin 		if(last)
3634887Schin 			pcomp.len = last-path;
3644887Schin 		memcpy((void*)save, (void*)stakptr(PATH_OFFSET+pcomp.len),sizeof(save));
3654887Schin 		if(path_chkpaths((Pathcomp_t*)0,(Pathcomp_t*)0,&pcomp,PATH_OFFSET))
3664887Schin 			return(stakfreeze(1));
3674887Schin 		memcpy((void*)stakptr(PATH_OFFSET+pcomp.len),(void*)save,sizeof(save));
3684887Schin 	}
3694887Schin 	return(0);
3704887Schin }
3714887Schin 
3724887Schin #if 0
3734887Schin void path_dump(register Pathcomp_t *pp)
3744887Schin {
3754887Schin 	sfprintf(sfstderr,"dump\n");
3764887Schin 	while(pp)
3774887Schin 	{
3784887Schin 		sfprintf(sfstderr,"pp=%x dev=%d ino=%d len=%d flags=%o name=%.*s\n",
3794887Schin 			pp,pp->dev,pp->ino,pp->len,pp->flags,pp->len,pp->name);
3804887Schin 		pp = pp->next;
3814887Schin 	}
3824887Schin }
3834887Schin #endif
3844887Schin 
3854887Schin /*
38610898Sroland.mainz@nrubsig.org  * check for duplicate directories on PATH
38710898Sroland.mainz@nrubsig.org  */
path_checkdup(register Pathcomp_t * pp)38810898Sroland.mainz@nrubsig.org static void path_checkdup(register Pathcomp_t *pp)
38910898Sroland.mainz@nrubsig.org {
39010898Sroland.mainz@nrubsig.org 	register char		*name = pp->name;
39110898Sroland.mainz@nrubsig.org 	register Pathcomp_t	*oldpp,*first;
39210898Sroland.mainz@nrubsig.org 	register int		flag=0;
39310898Sroland.mainz@nrubsig.org 	struct stat 		statb;
39410898Sroland.mainz@nrubsig.org 	if(stat(name,&statb)<0 || !S_ISDIR(statb.st_mode))
39510898Sroland.mainz@nrubsig.org 	{
39610898Sroland.mainz@nrubsig.org 		pp->flags |= PATH_SKIP;
39710898Sroland.mainz@nrubsig.org 		pp->dev = *name=='/';
39810898Sroland.mainz@nrubsig.org 		return;
39910898Sroland.mainz@nrubsig.org 	}
40010898Sroland.mainz@nrubsig.org 	pp->mtime = statb.st_mtime;
40110898Sroland.mainz@nrubsig.org 	pp->ino = statb.st_ino;
40210898Sroland.mainz@nrubsig.org 	pp->dev = statb.st_dev;
40310898Sroland.mainz@nrubsig.org 	if(*name=='/' && onstdpath(name))
40410898Sroland.mainz@nrubsig.org 		flag = PATH_STD_DIR;
40510898Sroland.mainz@nrubsig.org 	first = (pp->flags&PATH_CDPATH)?pp->shp->cdpathlist:path_get("");
40610898Sroland.mainz@nrubsig.org 	for(oldpp=first; oldpp && oldpp!=pp; oldpp=oldpp->next)
40710898Sroland.mainz@nrubsig.org 	{
40810898Sroland.mainz@nrubsig.org 		if(pp->ino==oldpp->ino && pp->dev==oldpp->dev && pp->mtime==oldpp->mtime)
40910898Sroland.mainz@nrubsig.org 		{
41010898Sroland.mainz@nrubsig.org 			flag |= PATH_SKIP;
41110898Sroland.mainz@nrubsig.org 			break;
41210898Sroland.mainz@nrubsig.org 		}
41310898Sroland.mainz@nrubsig.org 	}
41410898Sroland.mainz@nrubsig.org 	pp->flags |= flag;
41510898Sroland.mainz@nrubsig.org 	if(((pp->flags&(PATH_PATH|PATH_SKIP))==PATH_PATH))
41610898Sroland.mainz@nrubsig.org 	{
41710898Sroland.mainz@nrubsig.org 		int offset = staktell();
41810898Sroland.mainz@nrubsig.org 		stakputs(name);
41910898Sroland.mainz@nrubsig.org 		path_chkpaths(first,0,pp,offset);
42010898Sroland.mainz@nrubsig.org 		stakseek(offset);
42110898Sroland.mainz@nrubsig.org 	}
42210898Sroland.mainz@nrubsig.org }
42310898Sroland.mainz@nrubsig.org 
42410898Sroland.mainz@nrubsig.org /*
4254887Schin  * write the next path to search on the current stack
4264887Schin  * if last is given, all paths that come before <last> are skipped
4274887Schin  * the next pathcomp is returned.
4284887Schin  */
path_nextcomp(register Pathcomp_t * pp,const char * name,Pathcomp_t * last)4294887Schin Pathcomp_t *path_nextcomp(register Pathcomp_t *pp, const char *name, Pathcomp_t *last)
4304887Schin {
43110898Sroland.mainz@nrubsig.org 	Pathcomp_t	*ppnext;
4324887Schin 	stakseek(PATH_OFFSET);
4334887Schin 	if(*name=='/')
4344887Schin 		pp = 0;
4354887Schin 	else
4364887Schin 	{
43710898Sroland.mainz@nrubsig.org 		for(;pp && pp!=last;pp=ppnext)
4384887Schin 		{
43910898Sroland.mainz@nrubsig.org 			if(ppnext=pp->next)
44010898Sroland.mainz@nrubsig.org 				ppnext->shp = pp->shp;
44110898Sroland.mainz@nrubsig.org 			if(!pp->dev && !pp->ino)
44210898Sroland.mainz@nrubsig.org 				path_checkdup(pp);
4434887Schin 			if(pp->flags&PATH_SKIP)
4444887Schin 				continue;
4454887Schin 			if(!last || *pp->name!='/')
4464887Schin 				break;
4474887Schin 		}
4484887Schin 		if(!pp)		/* this should not happen */
4494887Schin 			pp = last;
4504887Schin 	}
4514887Schin 	if(pp && (pp->name[0]!='.' || pp->name[1]))
4524887Schin 	{
4534887Schin 		if(*pp->name!='/')
4544887Schin 		{
4554887Schin 			stakputs(path_pwd(1));
4564887Schin 			if(*stakptr(staktell()-1)!='/')
4574887Schin 				stakputc('/');
4584887Schin 		}
4594887Schin 		stakwrite(pp->name,pp->len);
4604887Schin 		if(pp->name[pp->len-1]!='/')
4614887Schin 			stakputc('/');
4624887Schin 	}
4634887Schin 	stakputs(name);
4644887Schin 	stakputc(0);
4654887Schin 	while(pp && pp!=last && (pp=pp->next))
4664887Schin 	{
4674887Schin 		if(!(pp->flags&PATH_SKIP))
4684887Schin 			return(pp);
4694887Schin 	}
4704887Schin 	return((Pathcomp_t*)0);
4714887Schin }
4724887Schin 
defpath_init(Shell_t * shp)4734887Schin static Pathcomp_t* defpath_init(Shell_t *shp)
4744887Schin {
4754887Schin 	Pathcomp_t *pp = (void*)path_addpath((Pathcomp_t*)0,(std_path),PATH_PATH);
4764887Schin 	if(shp->defpathlist = (void*)pp)
4774887Schin 		pp->shp = shp;
4784887Schin 	return(pp);
4794887Schin }
4804887Schin 
path_init(Shell_t * shp)4814887Schin static void path_init(Shell_t *shp)
4824887Schin {
4834887Schin 	const char *val;
4844887Schin 	Pathcomp_t *pp;
4854887Schin 	if(!std_path && !(std_path=astconf("PATH",NIL(char*),NIL(char*))))
4864887Schin 		std_path = e_defpath;
4878462SApril.Chin@Sun.COM 	if(val=sh_scoped(shp,(PATHNOD))->nvalue.cp)
4884887Schin 	{
4894887Schin 		pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_PATH);
4904887Schin 		if(shp->pathlist = (void*)pp)
4914887Schin 			pp->shp = shp;
4924887Schin 	}
4934887Schin 	else
4944887Schin 	{
4954887Schin 		if(!(pp=(Pathcomp_t*)shp->defpathlist))
4964887Schin 			pp = defpath_init(shp);
4974887Schin 		shp->pathlist = (void*)path_dup(pp);
4984887Schin 	}
4998462SApril.Chin@Sun.COM 	if(val=sh_scoped(shp,(FPATHNOD))->nvalue.cp)
5004887Schin 	{
5014887Schin 		pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_FPATH);
5024887Schin 		if(shp->pathlist = (void*)pp)
5034887Schin 			pp->shp = shp;
5044887Schin 	}
5054887Schin }
5064887Schin 
5074887Schin /*
5084887Schin  * returns that pathlist to search
5094887Schin  */
path_get(register const char * name)5104887Schin Pathcomp_t *path_get(register const char *name)
5114887Schin {
5124887Schin 	register Shell_t *shp = &sh;
5134887Schin 	register Pathcomp_t *pp=0;
5144887Schin 	if(*name && strchr(name,'/'))
5154887Schin 		return(0);
5164887Schin 	if(!sh_isstate(SH_DEFPATH))
5174887Schin 	{
5184887Schin 		if(!shp->pathlist)
5194887Schin 			path_init(shp);
5204887Schin 		pp = (Pathcomp_t*)shp->pathlist;
5214887Schin 	}
5224887Schin 	if(!pp && (!(PATHNOD)->nvalue.cp) || sh_isstate(SH_DEFPATH))
5234887Schin 	{
5244887Schin 		if(!(pp=(Pathcomp_t*)shp->defpathlist))
5254887Schin 			pp = defpath_init(shp);
5264887Schin 	}
5274887Schin 	return(pp);
5284887Schin }
5294887Schin 
5304887Schin /*
5314887Schin  * open file corresponding to name using path give by <pp>
5324887Schin  */
path_opentype(const char * name,register Pathcomp_t * pp,int fun)5334887Schin static int	path_opentype(const char *name, register Pathcomp_t *pp, int fun)
5344887Schin {
5354887Schin 	register int fd= -1;
5364887Schin 	struct stat statb;
5374887Schin 	Pathcomp_t *oldpp;
5384887Schin 	Shell_t *shp;
5394887Schin 	if(pp)
5404887Schin 		shp = pp->shp;
5414887Schin 	else
5424887Schin 	{
5434887Schin 		shp = sh_getinterp();
5444887Schin 		if(!shp->pathlist)
5454887Schin 			path_init(shp);
5464887Schin 	}
5474887Schin 	if(!fun && strchr(name,'/'))
5484887Schin 	{
5494887Schin 		if(sh_isoption(SH_RESTRICTED))
5504887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_restricted,name);
5514887Schin 	}
5524887Schin 	do
5534887Schin 	{
5544887Schin 		pp = path_nextcomp(oldpp=pp,name,0);
5554887Schin 		while(oldpp && (oldpp->flags&PATH_SKIP))
5564887Schin 			oldpp = oldpp->next;
5574887Schin 		if(fun && (!oldpp || !(oldpp->flags&PATH_FPATH)))
5584887Schin 			continue;
5594887Schin 		if((fd = sh_open(path_relative(stakptr(PATH_OFFSET)),O_RDONLY,0)) >= 0)
5604887Schin 		{
5614887Schin 			if(fstat(fd,&statb)<0 || S_ISDIR(statb.st_mode))
5624887Schin 			{
5634887Schin 				errno = EISDIR;
5644887Schin 				sh_close(fd);
5654887Schin 				fd = -1;
5664887Schin 			}
5674887Schin 		}
5684887Schin 	}
5694887Schin 	while( fd<0 && pp);
5704887Schin 	if(fd>=0 && (fd = sh_iomovefd(fd)) > 0)
5714887Schin 	{
5724887Schin 		fcntl(fd,F_SETFD,FD_CLOEXEC);
57310898Sroland.mainz@nrubsig.org 		if(!shp)
57410898Sroland.mainz@nrubsig.org 		{
57510898Sroland.mainz@nrubsig.org 			shp = sh_getinterp();
57610898Sroland.mainz@nrubsig.org #if _UWIN
57710898Sroland.mainz@nrubsig.org 			close(0x10001); /* this results in a /var/log/uwin message with "0x10001" for debugging */
57810898Sroland.mainz@nrubsig.org #endif
57910898Sroland.mainz@nrubsig.org 		}
5804887Schin 		shp->fdstatus[fd] |= IOCLEX;
5814887Schin 	}
5824887Schin 	return(fd);
5834887Schin }
5844887Schin 
5854887Schin /*
5864887Schin  * open file corresponding to name using path give by <pp>
5874887Schin  */
path_open(const char * name,register Pathcomp_t * pp)5884887Schin int	path_open(const char *name, register Pathcomp_t *pp)
5894887Schin {
5904887Schin 	return(path_opentype(name,pp,0));
5914887Schin }
5924887Schin 
5934887Schin /*
5944887Schin  * given a pathname return the base name
5954887Schin  */
5964887Schin 
path_basename(register const char * name)5974887Schin char	*path_basename(register const char *name)
5984887Schin {
5994887Schin 	register const char *start = name;
6004887Schin 	while (*name)
6014887Schin 		if ((*name++ == '/') && *name)	/* don't trim trailing / */
6024887Schin 			start = name;
6034887Schin 	return ((char*)start);
6044887Schin }
6054887Schin 
path_fullname(const char * name)6064887Schin char *path_fullname(const char *name)
6074887Schin {
6084887Schin 	int len=strlen(name)+1,dirlen=0;
6094887Schin 	char *path,*pwd;
6104887Schin 	if(*name!='/')
6114887Schin 	{
6124887Schin 		pwd = path_pwd(1);
6134887Schin 		dirlen = strlen(pwd)+1;
6144887Schin 	}
6154887Schin 	path = (char*)malloc(len+dirlen);
6164887Schin 	if(dirlen)
6174887Schin 	{
6184887Schin 		memcpy((void*)path,(void*)pwd,dirlen);
6194887Schin 		path[dirlen-1] = '/';
6204887Schin 	}
6214887Schin 	memcpy((void*)&path[dirlen],(void*)name,len);
6224887Schin 	pathcanon(path,0);
6234887Schin 	return(path);
6244887Schin }
6254887Schin 
6264887Schin /*
6274887Schin  * load functions from file <fno>
6284887Schin  */
funload(Shell_t * shp,int fno,const char * name)6294887Schin static void funload(Shell_t *shp,int fno, const char *name)
6304887Schin {
6318462SApril.Chin@Sun.COM 	char		*pname,*oldname=shp->st.filename, buff[IOBSIZE+1];
6328462SApril.Chin@Sun.COM 	Namval_t	*np;
6338462SApril.Chin@Sun.COM 	struct Ufunction *rp;
6348462SApril.Chin@Sun.COM 	int		 savestates = sh_getstate(), oldload=shp->funload;
6358462SApril.Chin@Sun.COM 	pname = path_fullname(stakptr(PATH_OFFSET));
6368462SApril.Chin@Sun.COM 	if(shp->fpathdict && (rp = dtmatch(shp->fpathdict,(void*)pname)))
6378462SApril.Chin@Sun.COM 	{
63810898Sroland.mainz@nrubsig.org 		Dt_t	*funtree = sh_subfuntree(1);
6398462SApril.Chin@Sun.COM 		do
6408462SApril.Chin@Sun.COM 		{
64110898Sroland.mainz@nrubsig.org 			if((np = dtsearch(funtree,rp->np)) && is_afunction(np))
6428462SApril.Chin@Sun.COM 			{
6438462SApril.Chin@Sun.COM 				if(np->nvalue.rp)
6448462SApril.Chin@Sun.COM 					np->nvalue.rp->fdict = 0;
64510898Sroland.mainz@nrubsig.org 				nv_delete(np,funtree,NV_NOFREE);
6468462SApril.Chin@Sun.COM 			}
64710898Sroland.mainz@nrubsig.org 			dtinsert(funtree,rp->np);
64810898Sroland.mainz@nrubsig.org 			rp->fdict = funtree;
6498462SApril.Chin@Sun.COM 		}
6508462SApril.Chin@Sun.COM 		while((rp=dtnext(shp->fpathdict,rp)) && strcmp(pname,rp->fname)==0);
6518462SApril.Chin@Sun.COM 		return;
6528462SApril.Chin@Sun.COM 	}
6534887Schin 	sh_onstate(SH_NOLOG);
6544887Schin 	sh_onstate(SH_NOALIAS);
6554887Schin 	shp->readscript = (char*)name;
6568462SApril.Chin@Sun.COM 	shp->st.filename = pname;
6578462SApril.Chin@Sun.COM 	shp->funload = 1;
6584887Schin 	error_info.line = 0;
65910898Sroland.mainz@nrubsig.org 	sh_eval(sfnew(NIL(Sfio_t*),buff,IOBSIZE,fno,SF_READ),SH_FUNEVAL);
6604887Schin 	shp->readscript = 0;
6614887Schin 	free((void*)shp->st.filename);
6628462SApril.Chin@Sun.COM 	shp->funload = oldload;
6634887Schin 	shp->st.filename = oldname;
6644887Schin 	sh_setstate(savestates);
6654887Schin }
6664887Schin 
6674887Schin /*
6684887Schin  * do a path search and track alias if requested
6694887Schin  * if flag is 0, or if name not found, then try autoloading function
6708462SApril.Chin@Sun.COM  * if flag==2 or 3, returns 1 if name found on FPATH
6718462SApril.Chin@Sun.COM  * if flag==3 no tracked alias will be set
6724887Schin  * returns 1, if function was autoloaded.
6738462SApril.Chin@Sun.COM  * If oldpp is not NULL, it will contain a pointer to the path component
6748462SApril.Chin@Sun.COM  *    where it was found.
6754887Schin  */
6764887Schin 
path_search(register const char * name,Pathcomp_t ** oldpp,int flag)6778462SApril.Chin@Sun.COM int	path_search(register const char *name,Pathcomp_t **oldpp, int flag)
6784887Schin {
6794887Schin 	register Namval_t *np;
6804887Schin 	register int fno;
6814887Schin 	Pathcomp_t *pp=0;
6824887Schin 	Shell_t *shp = &sh;
6834887Schin 	if(name && strchr(name,'/'))
6844887Schin 	{
6854887Schin 		stakseek(PATH_OFFSET);
6864887Schin 		stakputs(name);
6874887Schin 		if(canexecute(stakptr(PATH_OFFSET),0)<0)
6884887Schin 		{
6894887Schin 			*stakptr(PATH_OFFSET) = 0;
6904887Schin 			return(0);
6914887Schin 		}
6924887Schin 		if(*name=='/')
6934887Schin 			return(1);
6944887Schin 		stakseek(PATH_OFFSET);
6954887Schin 		stakputs(path_pwd(1));
6964887Schin 		stakputc('/');
6974887Schin 		stakputs(name);
6984887Schin 		stakputc(0);
6994887Schin 		return(0);
7004887Schin 	}
7014887Schin 	if(sh_isstate(SH_DEFPATH))
7024887Schin 	{
7034887Schin 		if(!shp->defpathlist)
7044887Schin 			defpath_init(shp);
7054887Schin 	}
7064887Schin 	else if(!shp->pathlist)
7074887Schin 		path_init(shp);
7084887Schin 	if(flag)
7094887Schin 	{
71010898Sroland.mainz@nrubsig.org 		if((np=nv_search(name,shp->track_tree,0)) && !nv_isattr(np,NV_NOALIAS) && (pp=(Pathcomp_t*)np->nvalue.cp))
71110898Sroland.mainz@nrubsig.org 		{
71210898Sroland.mainz@nrubsig.org 			stakseek(PATH_OFFSET);
71310898Sroland.mainz@nrubsig.org 			path_nextcomp(pp,name,pp);
71410898Sroland.mainz@nrubsig.org 			stakputc(0);
71510898Sroland.mainz@nrubsig.org 			return(0);
71610898Sroland.mainz@nrubsig.org 		}
7178462SApril.Chin@Sun.COM 		pp = path_absolute(name,oldpp?*oldpp:NIL(Pathcomp_t*));
7188462SApril.Chin@Sun.COM 		if(oldpp)
7198462SApril.Chin@Sun.COM 			*oldpp = pp;
72010898Sroland.mainz@nrubsig.org 		if(!pp && (np=nv_search(name,shp->fun_tree,HASH_NOSCOPE))&&np->nvalue.ip)
7214887Schin 			return(1);
7224887Schin 		if(!pp)
7234887Schin 			*stakptr(PATH_OFFSET) = 0;
7244887Schin 	}
7254887Schin 	if(flag==0 || !pp || (pp->flags&PATH_FPATH))
7264887Schin 	{
7274887Schin 		if(!pp)
7284887Schin 			pp=sh_isstate(SH_DEFPATH)?shp->defpathlist:shp->pathlist;
7294887Schin 		if(pp && strmatch(name,e_alphanum)  && (fno=path_opentype(name,pp,1))>=0)
7304887Schin 		{
7314887Schin 			if(flag==2)
7324887Schin 			{
7334887Schin 				sh_close(fno);
7344887Schin 				return(1);
7354887Schin 			}
7364887Schin 			funload(shp,fno,name);
7374887Schin 			return(1);
7384887Schin 		}
7394887Schin 		*stakptr(PATH_OFFSET) = 0;
7404887Schin 		return(0);
7414887Schin 	}
7428462SApril.Chin@Sun.COM 	else if(pp && !sh_isstate(SH_DEFPATH) && *name!='/' && flag<3)
7434887Schin 	{
7444887Schin 		if(np=nv_search(name,shp->track_tree,NV_ADD))
7454887Schin 			path_alias(np,pp);
7464887Schin 	}
7474887Schin 	return(0);
7484887Schin }
7494887Schin 
7504887Schin /*
7514887Schin  * do a path search and find the full pathname of file name
7524887Schin  */
path_absolute(register const char * name,Pathcomp_t * pp)7538462SApril.Chin@Sun.COM Pathcomp_t *path_absolute(register const char *name, Pathcomp_t *pp)
7544887Schin {
7554887Schin 	register int	f,isfun;
7564887Schin 	int		noexec=0;
7578462SApril.Chin@Sun.COM 	Pathcomp_t	*oldpp;
7584887Schin 	Shell_t		*shp = &sh;
7594887Schin 	Namval_t	*np;
7604887Schin 	shp->path_err = ENOENT;
7618462SApril.Chin@Sun.COM 	if(!pp && !(pp=path_get("")))
7624887Schin 		return(0);
7634887Schin 	shp->path_err = 0;
7644887Schin 	while(1)
7654887Schin 	{
7664887Schin 		sh_sigcheck();
7674887Schin 		isfun = (pp->flags&PATH_FPATH);
7684887Schin 		if(oldpp=pp)
76910898Sroland.mainz@nrubsig.org 		{
7704887Schin 			pp = path_nextcomp(pp,name,0);
77110898Sroland.mainz@nrubsig.org 			while(oldpp->flags&PATH_SKIP)
77210898Sroland.mainz@nrubsig.org 			{
77310898Sroland.mainz@nrubsig.org 				if(!(oldpp=oldpp->next))
77410898Sroland.mainz@nrubsig.org 				{
77510898Sroland.mainz@nrubsig.org 					shp->path_err = ENOENT;
77610898Sroland.mainz@nrubsig.org 					return(0);
77710898Sroland.mainz@nrubsig.org 				}
77810898Sroland.mainz@nrubsig.org 			}
77910898Sroland.mainz@nrubsig.org 		}
78010898Sroland.mainz@nrubsig.org 
7814887Schin 		if(!isfun && !sh_isoption(SH_RESTRICTED))
7824887Schin 		{
7838462SApril.Chin@Sun.COM 			if(*stakptr(PATH_OFFSET)=='/' && nv_search(stakptr(PATH_OFFSET),sh.bltin_tree,0))
7844887Schin 				return(oldpp);
7858462SApril.Chin@Sun.COM #if SHOPT_DYNAMIC
7864887Schin 			if(oldpp->blib)
7874887Schin 			{
7884887Schin 				typedef int (*Fptr_t)(int, char*[], void*);
7894887Schin 				Fptr_t addr;
7904887Schin 				int n = staktell();
79110898Sroland.mainz@nrubsig.org 				int libcmd;
7924887Schin 				char *cp;
7934887Schin 				stakputs("b_");
7944887Schin 				stakputs(name);
7954887Schin 				stakputc(0);
7964887Schin 				if(!oldpp->bltin_lib)
7974887Schin 				{
7984887Schin 					if(cp = strrchr(oldpp->blib,'/'))
7994887Schin 						cp++;
8004887Schin 					else
8014887Schin 						cp = oldpp->blib;
80210898Sroland.mainz@nrubsig.org 					if((libcmd = !strcmp(cp,LIBCMD)) && (addr=(Fptr_t)dlllook((void*)0,stakptr(n))))
8034887Schin 					{
8048462SApril.Chin@Sun.COM 						if((np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL)) && nv_isattr(np,NV_BLTINOPT))
8058462SApril.Chin@Sun.COM 							return(oldpp);
8064887Schin 					}
8074887Schin #if (_AST_VERSION>=20040404)
8084887Schin 					if (oldpp->bltin_lib = dllplug(SH_ID, oldpp->blib, NiL, RTLD_LAZY, NiL, 0))
8094887Schin #else
8104887Schin 					if (oldpp->bltin_lib = dllfind(oldpp->blib, NiL, RTLD_LAZY, NiL, 0))
8114887Schin #endif
81210898Sroland.mainz@nrubsig.org 					{
81310898Sroland.mainz@nrubsig.org 						/*
81410898Sroland.mainz@nrubsig.org 						 * this detects the 2007-05-11 builtin context change and also
81510898Sroland.mainz@nrubsig.org 						 * the 2008-03-30 opt_info.num change that hit libcmd::b_head
81610898Sroland.mainz@nrubsig.org 						 */
81710898Sroland.mainz@nrubsig.org 
81810898Sroland.mainz@nrubsig.org 						if (libcmd && !dlllook(oldpp->bltin_lib, "b_pids"))
81910898Sroland.mainz@nrubsig.org 						{
82010898Sroland.mainz@nrubsig.org 							dlclose(oldpp->bltin_lib);
82110898Sroland.mainz@nrubsig.org 							oldpp->bltin_lib = 0;
82210898Sroland.mainz@nrubsig.org 							oldpp->blib = 0;
82310898Sroland.mainz@nrubsig.org 						}
82410898Sroland.mainz@nrubsig.org 						else
82510898Sroland.mainz@nrubsig.org 							sh_addlib(oldpp->bltin_lib);
82610898Sroland.mainz@nrubsig.org 					}
8274887Schin 				}
8284887Schin 				if((addr=(Fptr_t)dlllook(oldpp->bltin_lib,stakptr(n))) &&
8294887Schin 				   (!(np = sh_addbuiltin(stakptr(PATH_OFFSET),NiL,NiL)) || np->nvalue.bfp!=addr) &&
8304887Schin 				   (np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL)))
8314887Schin 				{
8324887Schin 					np->nvenv = oldpp->bltin_lib;
8334887Schin 					return(oldpp);
8344887Schin 				}
8354887Schin 			}
8368462SApril.Chin@Sun.COM #endif /* SHOPT_DYNAMIC */
8374887Schin 		}
8388462SApril.Chin@Sun.COM 		sh_stats(STAT_PATHS);
8394887Schin 		f = canexecute(stakptr(PATH_OFFSET),isfun);
8404887Schin 		if(isfun && f>=0)
8414887Schin 		{
84210898Sroland.mainz@nrubsig.org 			nv_onattr(nv_open(name,sh_subfuntree(1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE),NV_LTOU|NV_FUNCTION);
84310898Sroland.mainz@nrubsig.org 			funload(shp,f,name);
8444887Schin 			close(f);
8454887Schin 			f = -1;
8464887Schin 			return(0);
8474887Schin 		}
8484887Schin 		else if(f>=0 && (oldpp->flags & PATH_STD_DIR))
8494887Schin 		{
8508462SApril.Chin@Sun.COM 			int n = staktell();
8514887Schin 			stakputs("/bin/");
8524887Schin 			stakputs(name);
8534887Schin 			stakputc(0);
8548462SApril.Chin@Sun.COM 			np = nv_search(stakptr(n),sh.bltin_tree,0);
8558462SApril.Chin@Sun.COM 			stakseek(n);
8564887Schin 			if(np)
8574887Schin 			{
8588462SApril.Chin@Sun.COM 				n = np->nvflag;
8598462SApril.Chin@Sun.COM 				np = sh_addbuiltin(stakptr(PATH_OFFSET),np->nvalue.bfp,nv_context(np));
8608462SApril.Chin@Sun.COM 				np->nvflag = n;
8614887Schin 			}
8624887Schin 		}
8634887Schin 		if(!pp || f>=0)
8644887Schin 			break;
8654887Schin 		if(errno!=ENOENT)
8664887Schin 			noexec = errno;
8674887Schin 	}
8684887Schin 	if(f<0)
8694887Schin 	{
8708462SApril.Chin@Sun.COM 		shp->path_err = (noexec?noexec:ENOENT);
8714887Schin 		return(0);
8724887Schin 	}
8734887Schin 	stakputc(0);
8744887Schin 	return(oldpp);
8754887Schin }
8764887Schin 
8774887Schin /*
8784887Schin  * returns 0 if path can execute
8794887Schin  * sets exec_err if file is found but can't be executable
8804887Schin  */
8814887Schin #undef S_IXALL
8824887Schin #ifdef S_IXUSR
8834887Schin #   define S_IXALL	(S_IXUSR|S_IXGRP|S_IXOTH)
8844887Schin #else
8854887Schin #   ifdef S_IEXEC
8864887Schin #	define S_IXALL	(S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6))
8874887Schin #   else
8884887Schin #	define S_IXALL	0111
8894887Schin #   endif /*S_EXEC */
8904887Schin #endif /* S_IXUSR */
8914887Schin 
canexecute(register char * path,int isfun)8924887Schin static int canexecute(register char *path, int isfun)
8934887Schin {
8944887Schin 	struct stat statb;
8954887Schin 	register int fd=0;
8964887Schin 	path = path_relative(path);
8974887Schin 	if(isfun)
8984887Schin 	{
8994887Schin 		if((fd=open(path,O_RDONLY,0))<0 || fstat(fd,&statb)<0)
9004887Schin 			goto err;
9014887Schin 	}
9024887Schin 	else if(stat(path,&statb) < 0)
9034887Schin 	{
9044887Schin #if _WINIX
9054887Schin 		/* check for .exe or .bat suffix */
9064887Schin 		char *cp;
9074887Schin 		if(errno==ENOENT && (!(cp=strrchr(path,'.')) || strlen(cp)>4 || strchr(cp,'/')))
9084887Schin 		{
9094887Schin 			int offset = staktell()-1;
9104887Schin 			stakseek(offset);
9114887Schin 			stakputs(".bat");
9124887Schin 			path = stakptr(PATH_OFFSET);
9134887Schin 			if(stat(path,&statb) < 0)
9144887Schin 			{
9154887Schin 				if(errno!=ENOENT)
9164887Schin 					goto err;
9174887Schin 				memcpy(stakptr(offset),".sh",4);
9184887Schin 				if(stat(path,&statb) < 0)
9194887Schin 					goto err;
9204887Schin 			}
9214887Schin 		}
9224887Schin 		else
9234887Schin #endif /* _WINIX */
9244887Schin 		goto err;
9254887Schin 	}
9264887Schin 	errno = EPERM;
9274887Schin 	if(S_ISDIR(statb.st_mode))
9284887Schin 		errno = EISDIR;
9294887Schin 	else if((statb.st_mode&S_IXALL)==S_IXALL || sh_access(path,X_OK)>=0)
9304887Schin 		return(fd);
9314887Schin 	if(isfun && fd>=0)
9324887Schin 		sh_close(fd);
9334887Schin err:
9344887Schin 	return(-1);
9354887Schin }
9364887Schin 
9374887Schin /*
9384887Schin  * Return path relative to present working directory
9394887Schin  */
9404887Schin 
path_relative(register const char * file)9414887Schin char *path_relative(register const char* file)
9424887Schin {
9434887Schin 	register const char *pwd;
9444887Schin 	register const char *fp = file;
9454887Schin 	/* can't relpath when sh.pwd not set */
9464887Schin 	if(!(pwd=sh.pwd))
9474887Schin 		return((char*)fp);
9484887Schin 	while(*pwd==*fp)
9494887Schin 	{
9504887Schin 		if(*pwd++==0)
9514887Schin 			return((char*)e_dot);
9524887Schin 		fp++;
9534887Schin 	}
9544887Schin 	if(*pwd==0 && *fp == '/')
9554887Schin 	{
9564887Schin 		while(*++fp=='/');
9574887Schin 		if(*fp)
9584887Schin 			return((char*)fp);
9594887Schin 		return((char*)e_dot);
9604887Schin 	}
9614887Schin 	return((char*)file);
9624887Schin }
9634887Schin 
path_exec(register const char * arg0,register char * argv[],struct argnod * local)9644887Schin void	path_exec(register const char *arg0,register char *argv[],struct argnod *local)
9654887Schin {
9664887Schin 	char **envp;
9674887Schin 	const char *opath;
9684887Schin 	Pathcomp_t *libpath, *pp=0;
9694887Schin 	Shell_t *shp = &sh;
9704887Schin 	int slash=0;
97110898Sroland.mainz@nrubsig.org 	nv_setlist(local,NV_EXPORT|NV_IDENT|NV_ASSIGN,0);
9724887Schin 	envp = sh_envgen();
9734887Schin 	if(strchr(arg0,'/'))
9744887Schin 	{
9754887Schin 		slash=1;
9764887Schin 		/* name containing / not allowed for restricted shell */
9774887Schin 		if(sh_isoption(SH_RESTRICTED))
9784887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_restricted,arg0);
9794887Schin 	}
9804887Schin 	else
9814887Schin 		pp=path_get(arg0);
9824887Schin 	shp->path_err= ENOENT;
9834887Schin 	sfsync(NIL(Sfio_t*));
9844887Schin 	timerdel(NIL(void*));
9854887Schin 	/* find first path that has a library component */
98610898Sroland.mainz@nrubsig.org 	while(pp && (pp->flags&PATH_SKIP))
98710898Sroland.mainz@nrubsig.org 		pp = pp->next;
9884887Schin 	if(pp || slash) do
9894887Schin 	{
9904887Schin 		sh_sigcheck();
9914887Schin 		if(libpath=pp)
9924887Schin 		{
9934887Schin 			pp = path_nextcomp(pp,arg0,0);
9944887Schin 			opath = stakfreeze(1)+PATH_OFFSET;
9954887Schin 		}
9964887Schin 		else
9974887Schin 			opath = arg0;
9984887Schin 		path_spawn(opath,argv,envp,libpath,0);
9994887Schin 		while(pp && (pp->flags&PATH_FPATH))
10004887Schin 			pp = path_nextcomp(pp,arg0,0);
10014887Schin 	}
10024887Schin 	while(pp);
10034887Schin 	/* force an exit */
10044887Schin 	((struct checkpt*)shp->jmplist)->mode = SH_JMPEXIT;
10054887Schin 	if((errno=shp->path_err)==ENOENT)
10064887Schin 		errormsg(SH_DICT,ERROR_exit(ERROR_NOENT),e_found,arg0);
10074887Schin 	else
10084887Schin 		errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,arg0);
10094887Schin }
10104887Schin 
path_spawn(const char * opath,register char ** argv,char ** envp,Pathcomp_t * libpath,int spawn)10114887Schin pid_t path_spawn(const char *opath,register char **argv, char **envp, Pathcomp_t *libpath, int spawn)
10124887Schin {
10134887Schin 	Shell_t *shp = sh_getinterp();
10144887Schin 	register char *path;
10154887Schin 	char **xp=0, *xval, *libenv = (libpath?libpath->lib:0);
10164887Schin 	Namval_t*	np;
10174887Schin 	char		*s, *v;
101810898Sroland.mainz@nrubsig.org 	int		r, n, pidsize;
10194887Schin 	pid_t		pid= -1;
10204887Schin 	/* leave room for inserting _= pathname in environment */
10214887Schin 	envp--;
10224887Schin #if _lib_readlink
10234887Schin 	/* save original pathname */
10244887Schin 	stakseek(PATH_OFFSET);
102510898Sroland.mainz@nrubsig.org 	pidsize = sfprintf(stkstd,"*%d*",spawn?getpid():getppid());
10264887Schin 	stakputs(opath);
102710898Sroland.mainz@nrubsig.org 	opath = stakfreeze(1)+PATH_OFFSET+pidsize;
10284887Schin 	np=nv_search(argv[0],shp->track_tree,0);
10294887Schin 	while(libpath && !libpath->lib)
10304887Schin 		libpath=libpath->next;
10314887Schin 	if(libpath && (!np || nv_size(np)>0))
10324887Schin 	{
10334887Schin 		/* check for symlink and use symlink name */
10344887Schin 		char buff[PATH_MAX+1];
10354887Schin 		char save[PATH_MAX+1];
10364887Schin 		stakseek(PATH_OFFSET);
10374887Schin 		stakputs(opath);
10384887Schin 		path = stakptr(PATH_OFFSET);
10394887Schin 		while((n=readlink(path,buff,PATH_MAX))>0)
10404887Schin 		{
10414887Schin 			buff[n] = 0;
10424887Schin 			n = PATH_OFFSET;
10434887Schin 			r = 0;
10444887Schin 			if((v=strrchr(path,'/')) && *buff!='/')
10454887Schin 			{
10464887Schin 				if(buff[0]=='.' && buff[1]=='.' && (r = strlen(path) + 1) <= PATH_MAX)
10474887Schin 					memcpy(save, path, r);
10484887Schin 				else
10494887Schin 					r = 0;
10504887Schin 				n += (v+1-path);
10514887Schin 			}
10524887Schin 			stakseek(n);
10534887Schin 			stakputs(buff);
10544887Schin 			stakputc(0);
10554887Schin 			path = stakptr(PATH_OFFSET);
10564887Schin 			if(v && buff[0]=='.' && buff[1]=='.')
10574887Schin 			{
10584887Schin 				pathcanon(path, 0);
10594887Schin 				if(r && access(path,X_OK))
10604887Schin 				{
10614887Schin 					memcpy(path, save, r);
10624887Schin 					break;
10634887Schin 				}
10644887Schin 			}
10654887Schin 			if(libenv = path_lib(libpath,path))
10664887Schin 				break;
10674887Schin 		}
10684887Schin 		stakseek(0);
10694887Schin 	}
10704887Schin #endif
10714887Schin 	if(libenv && (v = strchr(libenv,'=')))
10724887Schin 	{
10734887Schin 		n = v - libenv;
10744887Schin 		*v = 0;
10754887Schin 		np = nv_open(libenv,shp->var_tree,0);
10764887Schin 		*v = '=';
10774887Schin 		s = nv_getval(np);
10784887Schin 		stakputs(libenv);
10794887Schin 		if(s)
10804887Schin 		{
10814887Schin 			stakputc(':');
10824887Schin 			stakputs(s);
10834887Schin 		}
10844887Schin 		v = stakfreeze(1);
10854887Schin 		r = 1;
10868462SApril.Chin@Sun.COM 		xp = envp + 1;
10874887Schin 		while (s = *xp++)
10884887Schin 		{
10894887Schin 			if (strneq(s, v, n) && s[n] == '=')
10904887Schin 			{
10914887Schin 				xval = *--xp;
10924887Schin 				*xp = v;
10934887Schin 				r = 0;
10944887Schin 				break;
10954887Schin 			}
10964887Schin 		}
10974887Schin 		if (r)
10984887Schin 		{
10994887Schin 			*envp-- = v;
11004887Schin 			xp = 0;
11014887Schin 		}
11024887Schin 	}
11034887Schin 	if(!opath)
11044887Schin 		opath = stakptr(PATH_OFFSET);
110510898Sroland.mainz@nrubsig.org 	envp[0] =  (char*)opath-(PATH_OFFSET+pidsize);
11064887Schin 	envp[0][0] =  '_';
11074887Schin 	envp[0][1] =  '=';
11084887Schin 	sfsync(sfstderr);
11094887Schin 	sh_sigcheck();
11104887Schin 	path = path_relative(opath);
11114887Schin #ifdef SHELLMAGIC
11124887Schin 	if(*path!='/' && path!=opath)
11134887Schin 	{
11144887Schin 		/*
11154887Schin 		 * The following code because execv(foo,) and execv(./foo,)
11164887Schin 		 * may not yield the same results
11174887Schin 		 */
11184887Schin 		char *sp = (char*)malloc(strlen(path)+3);
11194887Schin 		sp[0] = '.';
11204887Schin 		sp[1] = '/';
11214887Schin 		strcpy(sp+2,path);
11224887Schin 		path = sp;
11234887Schin 	}
11244887Schin #endif /* SHELLMAGIC */
11254887Schin 	if(spawn && !sh_isoption(SH_PFSH))
11264887Schin 		pid = _spawnveg(opath, &argv[0],envp, spawn>>1);
11274887Schin 	else
11288462SApril.Chin@Sun.COM 		pid = path_pfexecve(opath, &argv[0] ,envp,spawn);
11294887Schin 	if(xp)
11304887Schin 		*xp = xval;
11314887Schin #ifdef SHELLMAGIC
11324887Schin 	if(*path=='.' && path!=opath)
11334887Schin 	{
11344887Schin 		free(path);
11354887Schin 		path = path_relative(opath);
11364887Schin 	}
11374887Schin #endif /* SHELLMAGIC */
11384887Schin 	if(pid>0)
11394887Schin 		return(pid);
11404887Schin retry:
11414887Schin 	switch(sh.path_err = errno)
11424887Schin 	{
11434887Schin #ifdef apollo
11444887Schin 	    /*
11454887Schin   	     * On apollo's execve will fail with eacces when
11464887Schin 	     * file has execute but not read permissions. So,
11474887Schin 	     * for now we will pretend that EACCES and ENOEXEC
11484887Schin  	     * mean the same thing.
11494887Schin  	     */
11504887Schin 	    case EACCES:
11514887Schin #endif /* apollo */
11524887Schin 	    case ENOEXEC:
11534887Schin #if SHOPT_SUID_EXEC
11544887Schin 	    case EPERM:
11554887Schin 		/* some systems return EPERM if setuid bit is on */
11564887Schin #endif
11574887Schin 		errno = ENOEXEC;
11584887Schin 		if(spawn)
11594887Schin 		{
11604887Schin #ifdef _lib_fork
11614887Schin 			if(sh.subshell)
11624887Schin 				return(-1);
11634887Schin 			do
11644887Schin 			{
11654887Schin 				if((pid=fork())>0)
11664887Schin 					return(pid);
11674887Schin 			}
11684887Schin 			while(_sh_fork(pid,0,(int*)0) < 0);
11698462SApril.Chin@Sun.COM 			((struct checkpt*)shp->jmplist)->mode = SH_JMPEXIT;
11704887Schin #else
11714887Schin 			return(-1);
11724887Schin #endif
11734887Schin 		}
11744887Schin 		exscript(shp,path,argv,envp);
11754887Schin #ifndef apollo
11764887Schin 	    case EACCES:
11774887Schin 	    {
11784887Schin 		struct stat statb;
11794887Schin 		if(stat(path,&statb)>=0)
11804887Schin 		{
11814887Schin 			if(S_ISDIR(statb.st_mode))
11824887Schin 				errno = EISDIR;
11834887Schin #ifdef S_ISSOCK
11844887Schin 			if(S_ISSOCK(statb.st_mode))
11854887Schin 				exscript(shp,path,argv,envp);
11864887Schin #endif
11874887Schin 		}
11884887Schin 	    }
11894887Schin 		/* FALL THROUGH */
11904887Schin #endif /* !apollo */
11914887Schin #ifdef ENAMETOOLONG
11924887Schin 	    case ENAMETOOLONG:
11934887Schin #endif /* ENAMETOOLONG */
11944887Schin #if !SHOPT_SUID_EXEC
11954887Schin 	    case EPERM:
11964887Schin #endif
11974887Schin 		shp->path_err = errno;
11984887Schin 		return(-1);
11994887Schin 	    case ENOTDIR:
12004887Schin 	    case ENOENT:
12014887Schin 	    case EINTR:
12024887Schin #ifdef EMLINK
12034887Schin 	    case EMLINK:
12044887Schin #endif /* EMLINK */
12054887Schin 		return(-1);
12064887Schin 	    case E2BIG:
12074887Schin 		if(sh.xargmin)
12084887Schin 		{
12094887Schin 			pid = path_xargs(opath, &argv[0] ,envp,spawn);
12104887Schin 			if(pid<0)
12114887Schin 				goto retry;
12124887Schin 			return(pid);
12134887Schin 		}
12144887Schin 	    default:
12154887Schin 		errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path);
12164887Schin 	}
12174887Schin 	return 0;
12184887Schin }
12194887Schin 
12204887Schin /*
12214887Schin  * File is executable but not machine code.
12224887Schin  * Assume file is a Shell script and execute it.
12234887Schin  */
12244887Schin 
exscript(Shell_t * shp,register char * path,register char * argv[],char ** envp)12254887Schin static void exscript(Shell_t *shp,register char *path,register char *argv[],char **envp)
12264887Schin {
12274887Schin 	register Sfio_t *sp;
12284887Schin 	path = path_relative(path);
12294887Schin 	shp->comdiv=0;
12304887Schin 	shp->bckpid = 0;
12314887Schin 	shp->st.ioset=0;
12324887Schin 	/* clean up any cooperating processes */
12334887Schin 	if(shp->cpipe[0]>0)
12344887Schin 		sh_pclose(shp->cpipe);
12354887Schin 	if(shp->cpid && shp->outpipe)
12364887Schin 		sh_close(*shp->outpipe);
12374887Schin 	shp->cpid = 0;
12384887Schin 	if(sp=fcfile())
12394887Schin 		while(sfstack(sp,SF_POPSTACK));
12404887Schin 	job_clear();
12414887Schin 	if(shp->infd>0 && (shp->fdstatus[shp->infd]&IOCLEX))
12424887Schin 		sh_close(shp->infd);
12434887Schin 	sh_setstate(sh_state(SH_FORKED));
12444887Schin 	sfsync(sfstderr);
12454887Schin #if SHOPT_SUID_EXEC && !SHOPT_PFSH
12464887Schin 	/* check if file cannot open for read or script is setuid/setgid  */
12474887Schin 	{
12484887Schin 		static char name[] = "/tmp/euidXXXXXXXXXX";
12494887Schin 		register int n;
12504887Schin 		register uid_t euserid;
12514887Schin 		char *savet=0;
12524887Schin 		struct stat statb;
12534887Schin 		if((n=sh_open(path,O_RDONLY,0)) >= 0)
12544887Schin 		{
12554887Schin 			/* move <n> if n=0,1,2 */
12564887Schin 			n = sh_iomovefd(n);
12574887Schin 			if(fstat(n,&statb)>=0 && !(statb.st_mode&(S_ISUID|S_ISGID)))
12584887Schin 				goto openok;
12594887Schin 			sh_close(n);
12604887Schin 		}
12614887Schin 		if((euserid=geteuid()) != shp->userid)
12624887Schin 		{
12634887Schin 			strncpy(name+9,fmtbase((long)getpid(),10,0),sizeof(name)-10);
12644887Schin 			/* create a suid open file with owner equal effective uid */
12654887Schin 			if((n=open(name,O_CREAT|O_TRUNC|O_WRONLY,S_ISUID|S_IXUSR)) < 0)
12664887Schin 				goto fail;
12674887Schin 			unlink(name);
12684887Schin 			/* make sure that file has right owner */
12694887Schin 			if(fstat(n,&statb)<0 || statb.st_uid != euserid)
12704887Schin 				goto fail;
12714887Schin 			if(n!=10)
12724887Schin 			{
12734887Schin 				sh_close(10);
12744887Schin 				fcntl(n, F_DUPFD, 10);
12754887Schin 				sh_close(n);
12764887Schin 				n=10;
12774887Schin 			}
12784887Schin 		}
12794887Schin 		savet = *--argv;
12804887Schin 		*argv = path;
12818462SApril.Chin@Sun.COM 		path_pfexecve(e_suidexec,argv,envp,0);
12824887Schin 	fail:
12834887Schin 		/*
12844887Schin 		 *  The following code is just for compatibility
12854887Schin 		 */
12864887Schin 		if((n=open(path,O_RDONLY,0)) < 0)
12878462SApril.Chin@Sun.COM 			errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path);
12884887Schin 		if(savet)
12894887Schin 			*argv++ = savet;
12904887Schin 	openok:
12914887Schin 		shp->infd = n;
12924887Schin 	}
12934887Schin #else
12948462SApril.Chin@Sun.COM 	if((shp->infd = sh_open(path,O_RDONLY,0)) < 0)
12958462SApril.Chin@Sun.COM 		errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path);
12964887Schin #endif
12974887Schin 	shp->infd = sh_iomovefd(shp->infd);
12984887Schin #if SHOPT_ACCT
12994887Schin 	sh_accbegin(path) ;  /* reset accounting */
13004887Schin #endif	/* SHOPT_ACCT */
13014887Schin 	shp->arglist = sh_argcreate(argv);
13024887Schin 	shp->lastarg = strdup(path);
13034887Schin 	/* save name of calling command */
13044887Schin 	shp->readscript = error_info.id;
13054887Schin 	/* close history file if name has changed */
13064887Schin 	if(shp->hist_ptr && (path=nv_getval(HISTFILE)) && strcmp(path,shp->hist_ptr->histname))
13074887Schin 	{
13084887Schin 		hist_close(shp->hist_ptr);
13094887Schin 		(HISTCUR)->nvalue.lp = 0;
13104887Schin 	}
13114887Schin 	sh_offstate(SH_FORKED);
131210898Sroland.mainz@nrubsig.org 	if(shp->sigflag[SIGCHLD]==SH_SIGOFF)
131310898Sroland.mainz@nrubsig.org 		shp->sigflag[SIGCHLD] = SH_SIGFAULT;
13144887Schin 	siglongjmp(*shp->jmplist,SH_JMPSCRIPT);
13154887Schin }
13164887Schin 
13174887Schin #if SHOPT_ACCT
13184887Schin #   include <sys/acct.h>
13194887Schin #   include "FEATURE/time"
13204887Schin 
13214887Schin     static struct acct sabuf;
13224887Schin     static struct tms buffer;
13234887Schin     static clock_t	before;
13244887Schin     static char *SHACCT; /* set to value of SHACCT environment variable */
13254887Schin     static shaccton;	/* non-zero causes accounting record to be written */
13264887Schin     static int compress(time_t);
13274887Schin     /*
13284887Schin      *	initialize accounting, i.e., see if SHACCT variable set
13294887Schin      */
sh_accinit(void)13304887Schin     void sh_accinit(void)
13314887Schin     {
13324887Schin 	SHACCT = getenv("SHACCT");
13334887Schin     }
13344887Schin     /*
13358462SApril.Chin@Sun.COM     * suspend accounting until turned on by sh_accbegin()
13364887Schin     */
sh_accsusp(void)13374887Schin     void sh_accsusp(void)
13384887Schin     {
13394887Schin 	shaccton=0;
13404887Schin #ifdef AEXPAND
13414887Schin 	sabuf.ac_flag |= AEXPND;
13424887Schin #endif /* AEXPAND */
13434887Schin     }
13444887Schin 
13454887Schin     /*
13464887Schin      * begin an accounting record by recording start time
13474887Schin      */
sh_accbegin(const char * cmdname)13484887Schin     void sh_accbegin(const char *cmdname)
13494887Schin     {
13504887Schin 	if(SHACCT)
13514887Schin 	{
13524887Schin 		sabuf.ac_btime = time(NIL(time_t *));
13534887Schin 		before = times(&buffer);
13544887Schin 		sabuf.ac_uid = getuid();
13554887Schin 		sabuf.ac_gid = getgid();
13564887Schin 		strncpy(sabuf.ac_comm, (char*)path_basename(cmdname),
13574887Schin 			sizeof(sabuf.ac_comm));
13584887Schin 		shaccton = 1;
13594887Schin 	}
13604887Schin     }
13614887Schin     /*
13624887Schin      * terminate an accounting record and append to accounting file
13634887Schin      */
sh_accend(void)13644887Schin     void	sh_accend(void)
13654887Schin     {
13664887Schin 	int	fd;
13674887Schin 	clock_t	after;
13684887Schin 
13694887Schin 	if(shaccton)
13704887Schin 	{
13714887Schin 		after = times(&buffer);
13724887Schin 		sabuf.ac_utime = compress(buffer.tms_utime + buffer.tms_cutime);
13734887Schin 		sabuf.ac_stime = compress(buffer.tms_stime + buffer.tms_cstime);
13744887Schin 		sabuf.ac_etime = compress( (time_t)(after-before));
13754887Schin 		fd = open( SHACCT , O_WRONLY | O_APPEND | O_CREAT,RW_ALL);
13764887Schin 		write(fd, (const char*)&sabuf, sizeof( sabuf ));
13774887Schin 		close( fd);
13784887Schin 	}
13794887Schin     }
13804887Schin 
13814887Schin     /*
13824887Schin      * Produce a pseudo-floating point representation
13834887Schin      * with 3 bits base-8 exponent, 13 bits fraction.
13844887Schin      */
compress(register time_t t)13854887Schin     static int compress(register time_t t)
13864887Schin     {
13874887Schin 	register int exp = 0, rund = 0;
13884887Schin 
13894887Schin 	while (t >= 8192)
13904887Schin 	{
13914887Schin 		exp++;
13924887Schin 		rund = t&04;
13934887Schin 		t >>= 3;
13944887Schin 	}
13954887Schin 	if (rund)
13964887Schin 	{
13974887Schin 		t++;
13984887Schin 		if (t >= 8192)
13994887Schin 		{
14004887Schin 			t >>= 3;
14014887Schin 			exp++;
14024887Schin 		}
14034887Schin 	}
14044887Schin 	return((exp<<13) + t);
14054887Schin     }
14064887Schin #endif	/* SHOPT_ACCT */
14074887Schin 
14084887Schin 
14094887Schin 
14104887Schin /*
14114887Schin  * add a pathcomponent to the path search list and eliminate duplicates
14124887Schin  * and non-existing absolute paths.
14134887Schin  */
path_addcomp(Pathcomp_t * first,Pathcomp_t * old,const char * name,int flag)14144887Schin static Pathcomp_t *path_addcomp(Pathcomp_t *first, Pathcomp_t *old,const char *name, int flag)
14154887Schin {
14164887Schin 	register Pathcomp_t *pp, *oldpp;
14174887Schin 	int len, offset=staktell();
14184887Schin 	if(!(flag&PATH_BFPATH))
14194887Schin 	{
14204887Schin 		register const char *cp = name;
14214887Schin 		while(*cp && *cp!=':')
14224887Schin 			stakputc(*cp++);
14234887Schin 		len = staktell()-offset;
14244887Schin 		stakputc(0);
14254887Schin 		stakseek(offset);
14264887Schin 		name = (const char*)stakptr(offset);
14274887Schin 	}
14284887Schin 	else
14294887Schin 		len = strlen(name);
14304887Schin 	for(pp=first; pp; pp=pp->next)
14314887Schin 	{
14324887Schin 		if(memcmp(name,pp->name,len)==0 && (pp->name[len]==':' || pp->name[len]==0))
14334887Schin 		{
14344887Schin 			pp->flags |= flag;
14354887Schin 			return(first);
14364887Schin 		}
14374887Schin 	}
143810898Sroland.mainz@nrubsig.org 	for(pp=first, oldpp=0; pp; oldpp=pp, pp=pp->next);
14394887Schin 	pp = newof((Pathcomp_t*)0,Pathcomp_t,1,len+1);
14404887Schin 	pp->refcount = 1;
14414887Schin 	memcpy((char*)(pp+1),name,len+1);
14424887Schin 	pp->name = (char*)(pp+1);
14434887Schin 	pp->len = len;
14444887Schin 	if(oldpp)
14454887Schin 		oldpp->next = pp;
14464887Schin 	else
14474887Schin 		first = pp;
14484887Schin 	pp->flags = flag;
144910898Sroland.mainz@nrubsig.org 	if(strcmp(name,SH_CMDLIB_DIR)==0)
14504887Schin 	{
145110898Sroland.mainz@nrubsig.org 		pp->dev = 1;
14524887Schin 		pp->flags |= PATH_BUILTIN_LIB;
14534887Schin 		pp->blib = malloc(4);
14544887Schin 		strcpy(pp->blib,LIBCMD);
14554887Schin 		return(first);
14564887Schin 	}
145710898Sroland.mainz@nrubsig.org 	if(old && ((flag&(PATH_PATH|PATH_SKIP))==PATH_PATH))
14584887Schin 		path_chkpaths(first,old,pp,offset);
14594887Schin 	return(first);
14604887Schin }
14614887Schin 
14624887Schin /*
14634887Schin  * This function checks for the .paths file in directory in <pp>
14644887Schin  * it assumes that the directory is on the stack at <offset>
14654887Schin  */
path_chkpaths(Pathcomp_t * first,Pathcomp_t * old,Pathcomp_t * pp,int offset)14664887Schin static int path_chkpaths(Pathcomp_t *first, Pathcomp_t* old,Pathcomp_t *pp, int offset)
14674887Schin {
14684887Schin 	struct stat statb;
14694887Schin 	int k,m,n,fd;
14704887Schin 	char *sp,*cp,*ep;
14714887Schin 	stakseek(offset+pp->len);
14724887Schin 	if(pp->len==1 && *stakptr(offset)=='/')
14734887Schin 		stakseek(offset);
14744887Schin 	stakputs("/.paths");
14754887Schin 	if((fd=open(stakptr(offset),O_RDONLY))>=0)
14764887Schin 	{
14774887Schin 		fstat(fd,&statb);
14784887Schin 		n = statb.st_size;
14794887Schin 		stakseek(offset+pp->len+n+2);
14804887Schin 		sp = stakptr(offset+pp->len);
14814887Schin 		*sp++ = '/';
14824887Schin 		n=read(fd,cp=sp,n);
14834887Schin 		sp[n] = 0;
14844887Schin 		close(fd);
14854887Schin 		for(ep=0; n--; cp++)
14864887Schin 		{
14874887Schin 			if(*cp=='=')
14884887Schin 			{
14894887Schin 				ep = cp+1;
14904887Schin 				continue;
14914887Schin 			}
14924887Schin 			else if(*cp!='\r' &&  *cp!='\n')
14934887Schin 				continue;
14944887Schin 			if(*sp=='#' || sp==cp)
14954887Schin 			{
14964887Schin 				sp = cp+1;
14974887Schin 				continue;
14984887Schin 			}
14994887Schin 			*cp = 0;
15004887Schin 			m = ep ? (ep-sp) : 0;
1501*12068SRoger.Faulkner@Oracle.COM 			if(m==0 || m==6 && memcmp((void*)sp,(void*)"FPATH=",6)==0)
15024887Schin 			{
15034887Schin 				if(first)
15044887Schin 				{
15054887Schin 					char *ptr = stakptr(offset+pp->len+1);
15064887Schin 					if(ep)
15074887Schin 						strcpy(ptr,ep);
15084887Schin 					path_addcomp(first,old,stakptr(offset),PATH_FPATH|PATH_BFPATH);
15094887Schin 				}
15104887Schin 			}
15114887Schin 			else if(m==12 && memcmp((void*)sp,(void*)"BUILTIN_LIB=",12)==0)
15124887Schin 			{
1513*12068SRoger.Faulkner@Oracle.COM 				if(!(pp->flags & PATH_BUILTIN_LIB) || strchr(ep,'-'))
15144887Schin 				{
1515*12068SRoger.Faulkner@Oracle.COM 					if ((pp->flags & (PATH_BUILTIN_LIB|PATH_STD_DIR)) == PATH_BUILTIN_LIB)
1516*12068SRoger.Faulkner@Oracle.COM 					{
1517*12068SRoger.Faulkner@Oracle.COM 						free(pp->blib);
1518*12068SRoger.Faulkner@Oracle.COM 						pp->blib = 0;
1519*12068SRoger.Faulkner@Oracle.COM 					}
15204887Schin 					pp->flags |= PATH_BUILTIN_LIB;
15214887Schin 					if (*ep == '.' && !*(ep + 1))
15224887Schin 						pp->flags |= PATH_STD_DIR;
15234887Schin 					else
15244887Schin 					{
15254887Schin 						k = strlen(ep)+1;
15264887Schin 						if (*ep != '/')
15274887Schin 							k +=  pp->len+1;
15284887Schin 						pp->blib = sp = malloc(k);
15294887Schin 						if (*ep != '/')
15304887Schin 						{
15314887Schin 							strcpy(pp->blib,pp->name);
15324887Schin 							sp += pp->len;
15334887Schin 							*sp++ = '/';
15344887Schin 						}
15354887Schin 						strcpy(sp,ep);
15364887Schin 					}
15374887Schin 				}
15384887Schin 			}
15394887Schin 			else if(m)
15404887Schin 			{
15414887Schin 				pp->lib = (char*)malloc(cp-sp+pp->len+2);
15424887Schin 				memcpy((void*)pp->lib,(void*)sp,m);
15434887Schin 				memcpy((void*)&pp->lib[m],stakptr(offset),pp->len);
15444887Schin 				pp->lib[k=m+pp->len] = '/';
15454887Schin 				strcpy((void*)&pp->lib[k+1],ep);
15464887Schin 				pathcanon(&pp->lib[m],0);
15474887Schin 				if(!first)
15484887Schin 				{
15494887Schin 					stakseek(0);
15504887Schin 					stakputs(pp->lib);
15514887Schin 					free((void*)pp->lib);
15524887Schin 					return(1);
15534887Schin 				}
15544887Schin 			}
15554887Schin 			sp = cp+1;
15564887Schin 			ep = 0;
15574887Schin 		}
15584887Schin 	}
15594887Schin 	return(0);
15604887Schin }
15614887Schin 
15624887Schin 
path_addpath(Pathcomp_t * first,register const char * path,int type)15634887Schin Pathcomp_t *path_addpath(Pathcomp_t *first, register const char *path,int type)
15644887Schin {
15654887Schin 	register const char *cp;
15664887Schin 	Pathcomp_t *old=0;
15674887Schin 	int offset = staktell();
15684887Schin 	char *savptr;
15694887Schin 
15704887Schin 	if(!path && type!=PATH_PATH)
15714887Schin 		return(first);
15724887Schin 	if(type!=PATH_FPATH)
15734887Schin 	{
15744887Schin 		old = first;
15754887Schin 		first = 0;
15764887Schin 	}
15774887Schin 	if(offset)
15784887Schin 		savptr = stakfreeze(0);
15794887Schin 	if(path) while(*(cp=path))
15804887Schin 	{
15814887Schin 		if(*cp==':')
15824887Schin 		{
15834887Schin 			if(type!=PATH_FPATH)
15844887Schin 				first = path_addcomp(first,old,".",type);
15854887Schin 			while(*++path == ':');
15864887Schin 		}
15874887Schin 		else
15884887Schin 		{
15894887Schin 			int c;
15904887Schin 			while(*path && *path!=':')
15914887Schin 				path++;
15924887Schin 			c = *path++;
15934887Schin 			first = path_addcomp(first,old,cp,type);
15944887Schin 			if(c==0)
15954887Schin 				break;
15964887Schin 			if(*path==0)
15974887Schin 				path--;
15984887Schin 		}
15994887Schin 	}
16004887Schin 	if(old)
16014887Schin 	{
16024887Schin 		if(!first && !path)
16034887Schin 		{
16044887Schin 			Pathcomp_t *pp = (Pathcomp_t*)old->shp->defpathlist;
16054887Schin 			if(!pp)
16064887Schin 				pp = defpath_init(old->shp);
16074887Schin 			first = path_dup(pp);
16084887Schin 		}
16094887Schin 		if(cp=(FPATHNOD)->nvalue.cp)
16104887Schin 			first = (void*)path_addpath((Pathcomp_t*)first,cp,PATH_FPATH);
16114887Schin 		path_delete(old);
16124887Schin 	}
16134887Schin 	if(offset)
16144887Schin 		stakset(savptr,offset);
16154887Schin 	else
16164887Schin 		stakseek(0);
16174887Schin 	return(first);
16184887Schin }
16194887Schin 
16204887Schin /*
16214887Schin  * duplicate the path give by <first> by incremented reference counts
16224887Schin  */
path_dup(Pathcomp_t * first)16234887Schin Pathcomp_t *path_dup(Pathcomp_t *first)
16244887Schin {
16254887Schin 	register Pathcomp_t *pp=first;
16264887Schin 	while(pp)
16274887Schin 	{
16284887Schin 		pp->refcount++;
16294887Schin 		pp = pp->next;
16304887Schin 	}
16314887Schin 	return(first);
16324887Schin }
16334887Schin 
16344887Schin /*
16354887Schin  * called whenever the directory is changed
16364887Schin  */
path_newdir(Pathcomp_t * first)16374887Schin void path_newdir(Pathcomp_t *first)
16384887Schin {
16394887Schin 	register Pathcomp_t *pp=first, *next, *pq;
16404887Schin 	struct stat statb;
16414887Schin 	for(pp=first; pp; pp=pp->next)
16424887Schin 	{
16434887Schin 		pp->flags &= ~PATH_SKIP;
16444887Schin 		if(*pp->name=='/')
16454887Schin 			continue;
16464887Schin 		/* delete .paths component */
16474887Schin 		if((next=pp->next) && (next->flags&PATH_BFPATH))
16484887Schin 		{
16494887Schin 			pp->next = next->next;
16504887Schin 			if(--next->refcount<=0)
16514887Schin 				free((void*)next);
16524887Schin 		}
16534887Schin 		if(stat(pp->name,&statb)<0 || !S_ISDIR(statb.st_mode))
16544887Schin 		{
16554887Schin 			pp->dev = 0;
16564887Schin 			pp->ino = 0;
16574887Schin 			continue;
16584887Schin 		}
16594887Schin 		pp->dev = statb.st_dev;
16604887Schin 		pp->ino = statb.st_ino;
16618462SApril.Chin@Sun.COM 		pp->mtime = statb.st_mtime;
16624887Schin 		for(pq=first;pq!=pp;pq=pq->next)
16634887Schin 		{
16644887Schin 			if(pp->ino==pq->ino && pp->dev==pq->dev)
16654887Schin 				pp->flags |= PATH_SKIP;
16664887Schin 		}
16674887Schin 		for(pq=pp;pq=pq->next;)
16684887Schin 		{
16694887Schin 			if(pp->ino==pq->ino && pp->dev==pq->dev)
16704887Schin 				pq->flags |= PATH_SKIP;
16714887Schin 		}
16724887Schin 		if((pp->flags&(PATH_PATH|PATH_SKIP))==PATH_PATH)
16734887Schin 		{
16744887Schin 			/* try to insert .paths component */
16754887Schin 			int offset = staktell();
16764887Schin 			stakputs(pp->name);
16774887Schin 			stakseek(offset);
16784887Schin 			next = pp->next;
16794887Schin 			pp->next = 0;
16804887Schin 			path_chkpaths(first,(Pathcomp_t*)0,pp,offset);
16814887Schin 			if(pp->next)
16824887Schin 				pp = pp->next;
16834887Schin 			pp->next = next;
16844887Schin 		}
16854887Schin 	}
16864887Schin #if 0
16874887Schin 	path_dump(first);
16884887Schin #endif
16894887Schin }
16904887Schin 
path_unsetfpath(Pathcomp_t * first)16914887Schin Pathcomp_t *path_unsetfpath(Pathcomp_t *first)
16924887Schin {
16934887Schin 	register Pathcomp_t *pp=first, *old=0;
16948462SApril.Chin@Sun.COM 	Shell_t	*shp = &sh;
16958462SApril.Chin@Sun.COM 	if(shp->fpathdict)
16968462SApril.Chin@Sun.COM 	{
16978462SApril.Chin@Sun.COM 		struct Ufunction  *rp, *rpnext;
16988462SApril.Chin@Sun.COM 		for(rp=(struct Ufunction*)dtfirst(shp->fpathdict);rp;rp=rpnext)
16998462SApril.Chin@Sun.COM 		{
17008462SApril.Chin@Sun.COM 			rpnext = (struct Ufunction*)dtnext(shp->fpathdict,rp);
17018462SApril.Chin@Sun.COM 			if(rp->fdict)
17028462SApril.Chin@Sun.COM 				nv_delete(rp->np,rp->fdict,NV_NOFREE);
17038462SApril.Chin@Sun.COM 			rp->fdict = 0;
17048462SApril.Chin@Sun.COM 		}
17058462SApril.Chin@Sun.COM 	}
17064887Schin 	while(pp)
17074887Schin 	{
17084887Schin 		if((pp->flags&PATH_FPATH) && !(pp->flags&PATH_BFPATH))
17094887Schin 		{
17104887Schin 			if(pp->flags&PATH_PATH)
17114887Schin 				pp->flags &= ~PATH_FPATH;
17124887Schin 			else
17134887Schin 			{
17144887Schin 				Pathcomp_t *ppsave=pp;
17154887Schin 				if(old)
17164887Schin 					old->next = pp->next;
17174887Schin 				else
17184887Schin 					first = pp->next;
17194887Schin 				pp = pp->next;
17204887Schin 				if(--ppsave->refcount<=0)
17214887Schin 				{
17224887Schin 					if(ppsave->lib)
17234887Schin 						free((void*)ppsave->lib);
17244887Schin 					free((void*)ppsave);
17254887Schin 				}
17264887Schin 				continue;
17274887Schin 			}
17284887Schin 
17294887Schin 		}
17304887Schin 		old = pp;
17314887Schin 		pp = pp->next;
17324887Schin 	}
17334887Schin 	return(first);
17344887Schin }
17354887Schin 
path_dirfind(Pathcomp_t * first,const char * name,int c)17364887Schin Pathcomp_t *path_dirfind(Pathcomp_t *first,const char *name,int c)
17374887Schin {
17384887Schin 	register Pathcomp_t *pp=first;
17394887Schin 	while(pp)
17404887Schin 	{
17414887Schin 		if(memcmp(name,pp->name,pp->len)==0 && name[pp->len]==c)
17424887Schin 			return(pp);
17434887Schin 		pp = pp->next;
17444887Schin 	}
17454887Schin 	return(0);
17464887Schin }
17474887Schin 
17484887Schin /*
17494887Schin  * get discipline for tracked alias
17504887Schin  */
talias_get(Namval_t * np,Namfun_t * nvp)17514887Schin static char *talias_get(Namval_t *np, Namfun_t *nvp)
17524887Schin {
17534887Schin 	Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp;
17544887Schin 	char *ptr;
17554887Schin 	if(!pp)
17564887Schin 		return(NULL);
17574887Schin 	path_nextcomp(pp,nv_name(np),pp);
17584887Schin 	ptr = stakfreeze(0);
17594887Schin 	return(ptr+PATH_OFFSET);
17604887Schin }
17614887Schin 
talias_put(register Namval_t * np,const char * val,int flags,Namfun_t * fp)17624887Schin static void talias_put(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
17634887Schin {
17644887Schin 	if(!val && np->nvalue.cp)
17654887Schin 	{
17664887Schin 		Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp;
17674887Schin 		if(--pp->refcount<=0)
17684887Schin 			free((void*)pp);
17694887Schin 	}
17704887Schin 	nv_putv(np,val,flags,fp);
17714887Schin }
17724887Schin 
17734887Schin static const Namdisc_t talias_disc   = { 0, talias_put, talias_get   };
17744887Schin static Namfun_t  talias_init = { &talias_disc, 1 };
17754887Schin 
17764887Schin /*
17774887Schin  *  set tracked alias node <np> to value <pp>
17784887Schin  */
path_alias(register Namval_t * np,register Pathcomp_t * pp)17794887Schin void path_alias(register Namval_t *np,register Pathcomp_t *pp)
17804887Schin {
17814887Schin 	if(pp)
17824887Schin 	{
17834887Schin 		struct stat statb;
17844887Schin 		char *sp;
17854887Schin 		nv_offattr(np,NV_NOPRINT);
17864887Schin 		nv_stack(np,&talias_init);
17874887Schin 		np->nvalue.cp = (char*)pp;
17884887Schin 		pp->refcount++;
17894887Schin 		nv_setattr(np,NV_TAGGED|NV_NOFREE);
17904887Schin 		path_nextcomp(pp,nv_name(np),pp);
17914887Schin 		sp = stakptr(PATH_OFFSET);
17924887Schin 		if(sp && lstat(sp,&statb)>=0 && S_ISLNK(statb.st_mode))
17934887Schin 			nv_setsize(np,statb.st_size+1);
17944887Schin 		else
17954887Schin 			nv_setsize(np,0);
17964887Schin 	}
17974887Schin 	else
17984887Schin 		nv_unset(np);
17994887Schin }
18004887Schin 
1801