14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*8462SApril.Chin@Sun.COM *          Copyright (c) 1982-2008 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
7*8462SApril.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"
37*8462SApril.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 #   else
434887Schin #	undef SHOPT_PFSH
444887Schin #   endif
45*8462SApril.Chin@Sun.COM #   if     _lib_vfork
46*8462SApril.Chin@Sun.COM #	include     <ast_vfork.h>
47*8462SApril.Chin@Sun.COM #   else
48*8462SApril.Chin@Sun.COM #	define vfork()      fork()
49*8462SApril.Chin@Sun.COM #   endif
504887Schin #endif
514887Schin 
524887Schin #define RW_ALL	(S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH)
534887Schin #define LIBCMD	"cmd"
544887Schin 
554887Schin 
564887Schin static int		canexecute(char*,int);
574887Schin static void		funload(Shell_t*,int,const char*);
584887Schin static void		exscript(Shell_t*,char*, char*[], char**);
594887Schin static int		path_chkpaths(Pathcomp_t*,Pathcomp_t*,Pathcomp_t*,int);
604887Schin 
614887Schin static const char	*std_path;
624887Schin 
634887Schin static int onstdpath(const char *name)
644887Schin {
654887Schin 	register const char *cp = std_path, *sp;
664887Schin 	if(cp)
674887Schin 		while(*cp)
684887Schin 		{
694887Schin 			for(sp=name; *sp && (*cp == *sp); sp++,cp++);
704887Schin 			if(*sp==0 && (*cp==0 || *cp==':'))
714887Schin 				return(1);
724887Schin 			while(*cp && *cp++!=':');
734887Schin 		}
744887Schin 	return(0);
754887Schin }
764887Schin 
77*8462SApril.Chin@Sun.COM static pid_t path_pfexecve(const char *path, char *argv[],char *const envp[],int spawn)
784887Schin {
794887Schin #if SHOPT_PFSH
80*8462SApril.Chin@Sun.COM 	pid_t	pid;
814887Schin 	char  resolvedpath[PATH_MAX + 1];
82*8462SApril.Chin@Sun.COM 	if(spawn)
83*8462SApril.Chin@Sun.COM 	{
84*8462SApril.Chin@Sun.COM 		while((pid = vfork()) < 0)
85*8462SApril.Chin@Sun.COM 			_sh_fork(pid, 0, (int*)0);
86*8462SApril.Chin@Sun.COM 		if(pid)
87*8462SApril.Chin@Sun.COM 			return(pid);
88*8462SApril.Chin@Sun.COM 	}
894887Schin 	if(!sh_isoption(SH_PFSH))
904887Schin 		return(execve(path, argv, envp));
914887Schin 	/* Solaris implements realpath(3C) using the resolvepath(2) */
924887Schin 	/* system call so we can save us to call access(2) first */
934887Schin 	if (!realpath(path, resolvedpath))
944887Schin 		return -1;
954887Schin 
964887Schin 	/* we can exec the command directly instead of via pfexec(1) if */
974887Schin 	/* there is a matching entry without attributes in exec_attr(4) */
984887Schin 	if (sh.user && *sh.user)
994887Schin 	{
1004887Schin 		execattr_t *pf;
1014887Schin 		if(pf=getexecuser(sh.user, KV_COMMAND, resolvedpath, GET_ONE))
1024887Schin 		{
1034887Schin 			if (!pf->attr || pf->attr->length == 0)
1044887Schin 			{
1054887Schin 				int r = execve(path, argv, envp);
1064887Schin 				free_execattr(pf);
1074887Schin 				return r;
1084887Schin 			}
1094887Schin 			free_execattr(pf);
1104887Schin 		}
1114887Schin 		else
1124887Schin 		{
1134887Schin 			errno = ENOENT;
1144887Schin 			return -1;
1154887Schin 		}
1164887Schin 	}
1174887Schin 	--argv;
1184887Schin 	argv[0] = argv[1];
1194887Schin 	argv[1] = resolvedpath;
1204887Schin 	return(execve("/usr/bin/pfexec", argv, envp));
1214887Schin #else
1224887Schin 	return(execve(path, argv, envp));
1234887Schin #endif
1244887Schin }
1254887Schin 
1264887Schin 
127*8462SApril.Chin@Sun.COM static pid_t _spawnveg(const char *path, char* const argv[], char* const envp[], pid_t pgid)
1284887Schin {
1294887Schin 	int waitsafe = job.waitsafe;
130*8462SApril.Chin@Sun.COM 	pid_t pid;
1314887Schin 	job_lock();
132*8462SApril.Chin@Sun.COM 	while(1)
133*8462SApril.Chin@Sun.COM 	{
134*8462SApril.Chin@Sun.COM 		sh_stats(STAT_SPAWN);
135*8462SApril.Chin@Sun.COM 		pid = spawnveg(path,argv,envp,pgid);
136*8462SApril.Chin@Sun.COM 		if(pid>=0 || errno!=EAGAIN)
137*8462SApril.Chin@Sun.COM 			break;
138*8462SApril.Chin@Sun.COM 		_sh_fork(pid, 0, (int*)0);
139*8462SApril.Chin@Sun.COM 	}
1404887Schin 	job.waitsafe = waitsafe;
1414887Schin 	job_unlock();
1424887Schin 	return(pid);
1434887Schin }
1444887Schin /*
1454887Schin  * used with command -x to run the command in multiple passes
1464887Schin  * spawn is non-zero when invoked via spawn
1474887Schin  * the exitval is set to the maximum for each execution
1484887Schin  */
1494887Schin static pid_t path_xargs(const char *path, char *argv[],char *const envp[], int spawn)
1504887Schin {
1514887Schin 	register char *cp, **av, **xv;
1524887Schin 	char **avlast= &argv[sh.xargmax], **saveargs=0;
1534887Schin 	char *const *ev;
1544887Schin 	long size, left;
1554887Schin 	int nlast=1,n,exitval=0;
1564887Schin 	pid_t pid;
1574887Schin 	if(sh.xargmin < 0)
1584887Schin 		return((pid_t)-1);
1594887Schin 	size = sh.lim.arg_max-1024;
1604887Schin 	for(ev=envp; cp= *ev; ev++)
1614887Schin 		size -= strlen(cp)-1;
1624887Schin 	for(av=argv; (cp= *av) && av< &argv[sh.xargmin]; av++)
1634887Schin 		size -= strlen(cp)-1;
1644887Schin 	for(av=avlast; cp= *av; av++,nlast++)
1654887Schin 		size -= strlen(cp)-1;
1664887Schin 	av =  &argv[sh.xargmin];
1674887Schin 	if(!spawn)
1684887Schin 		job_clear();
1694887Schin 	sh.exitval = 0;
1704887Schin 	while(av<avlast)
1714887Schin 	{
1724887Schin 		for(xv=av,left=size; left>0 && av<avlast;)
1734887Schin 			left -= strlen(*av++)+1;
1744887Schin 		/* leave at least two for last */
1754887Schin 		if(left<0 && (avlast-av)<2)
1764887Schin 			av--;
1774887Schin 		if(xv==&argv[sh.xargmin])
1784887Schin 		{
1794887Schin 			n = nlast*sizeof(char*);
1804887Schin 			saveargs = (char**)malloc(n);
1814887Schin 			memcpy((void*)saveargs, (void*)av, n);
1824887Schin 			memcpy((void*)av,(void*)avlast,n);
1834887Schin 		}
1844887Schin 		else
1854887Schin 		{
1864887Schin 			for(n=sh.xargmin; xv < av; xv++)
1874887Schin 				argv[n++] = *xv;
1884887Schin 			for(xv=avlast; cp=  *xv; xv++)
1894887Schin 				argv[n++] = cp;
1904887Schin 			argv[n] = 0;
1914887Schin 		}
1924887Schin 		if(saveargs || av<avlast || (exitval && !spawn))
1934887Schin 		{
1944887Schin 			if((pid=_spawnveg(path,argv,envp,0)) < 0)
1954887Schin 				return(-1);
1964887Schin 			job_post(pid,0);
1974887Schin 			job_wait(pid);
1984887Schin 			if(sh.exitval>exitval)
1994887Schin 				exitval = sh.exitval;
2004887Schin 			if(saveargs)
2014887Schin 			{
2024887Schin 				memcpy((void*)av,saveargs,n);
2034887Schin 				free((void*)saveargs);
2044887Schin 				saveargs = 0;
2054887Schin 			}
2064887Schin 		}
2074887Schin 		else if(spawn && !sh_isoption(SH_PFSH))
2084887Schin 		{
2094887Schin 			sh.xargexit = exitval;
2104887Schin 			return(_spawnveg(path,argv,envp,spawn>>1));
2114887Schin 		}
2124887Schin 		else
213*8462SApril.Chin@Sun.COM 			return(path_pfexecve(path,argv,envp,spawn));
2144887Schin 	}
2154887Schin 	if(!spawn)
2164887Schin 		exit(exitval);
2174887Schin 	return((pid_t)-1);
2184887Schin }
2194887Schin 
2204887Schin /*
2214887Schin  * make sure PWD is set up correctly
2224887Schin  * Return the present working directory
2234887Schin  * Invokes getcwd() if flag==0 and if necessary
2244887Schin  * Sets the PWD variable to this value
2254887Schin  */
2264887Schin char *path_pwd(int flag)
2274887Schin {
2284887Schin 	register char *cp;
2294887Schin 	register char *dfault = (char*)e_dot;
2304887Schin 	register int count = 0;
2314887Schin 	Shell_t *shp = &sh;
2324887Schin 	if(shp->pwd)
2334887Schin 		return((char*)shp->pwd);
2344887Schin 	while(1)
2354887Schin 	{
2364887Schin 		/* try from lowest to highest */
2374887Schin 		switch(count++)
2384887Schin 		{
2394887Schin 			case 0:
2404887Schin 				cp = nv_getval(PWDNOD);
2414887Schin 				break;
2424887Schin 			case 1:
2434887Schin 				cp = nv_getval(HOME);
2444887Schin 				break;
2454887Schin 			case 2:
2464887Schin 				cp = "/";
2474887Schin 				break;
2484887Schin 			case 3:
2494887Schin 				cp = (char*)e_crondir;
2504887Schin 				if(flag) /* skip next case when non-zero flag */
2514887Schin 					++count;
2524887Schin 				break;
2534887Schin 			case 4:
2544887Schin 			{
2554887Schin 				if(cp=getcwd(NIL(char*),0))
2564887Schin 				{
2574887Schin 					nv_offattr(PWDNOD,NV_NOFREE);
2584887Schin 					nv_unset(PWDNOD);
2594887Schin 					PWDNOD->nvalue.cp = cp;
2604887Schin 					goto skip;
2614887Schin 				}
2624887Schin 				break;
2634887Schin 			}
2644887Schin 			case 5:
2654887Schin 				return(dfault);
2664887Schin 		}
2674887Schin 		if(cp && *cp=='/' && test_inode(cp,e_dot))
2684887Schin 			break;
2694887Schin 	}
2704887Schin 	if(count>1)
2714887Schin 	{
2724887Schin 		nv_offattr(PWDNOD,NV_NOFREE);
2734887Schin 		nv_putval(PWDNOD,cp,NV_RDONLY);
2744887Schin 	}
2754887Schin skip:
2764887Schin 	nv_onattr(PWDNOD,NV_NOFREE|NV_EXPORT);
2774887Schin 	shp->pwd = (char*)(PWDNOD->nvalue.cp);
2784887Schin 	return(cp);
2794887Schin }
2804887Schin 
2814887Schin static void free_bltin(Namval_t *np,void *data)
2824887Schin {
2834887Schin 	register Pathcomp_t *pp= (Pathcomp_t*)data;
2844887Schin 	if(pp->flags&PATH_STD_DIR)
2854887Schin 	{
2864887Schin 		int offset=staktell();;
2874887Schin 		if(strcmp(pp->name,"/bin")==0 || memcmp(pp->name,np->nvname,pp->len) || np->nvname[pp->len]!='/')
2884887Schin 			return;
2894887Schin 		stakputs("/bin");
2904887Schin 		stakputs(np->nvname+pp->len+1);
2914887Schin 		stakputc(0);
2924887Schin 		sh_addbuiltin(stakptr(offset),np->nvalue.bfp,NiL);
2934887Schin 		stakseek(offset);
2944887Schin 		return;
2954887Schin 	}
2964887Schin 	if((void*)np->nvenv==pp->bltin_lib)
297*8462SApril.Chin@Sun.COM 		nv_delete(np,sh_bltin_tree(),NV_NOFREE);
2984887Schin }
2994887Schin 
3004887Schin /*
3014887Schin  * delete current Pathcomp_t structure
3024887Schin  */
3034887Schin void  path_delete(Pathcomp_t *first)
3044887Schin {
3054887Schin 	register Pathcomp_t *pp=first, *old=0, *ppnext;
3064887Schin 	while(pp)
3074887Schin 	{
3084887Schin 		ppnext = pp->next;
3094887Schin 		if(--pp->refcount<=0)
3104887Schin 		{
3114887Schin 			if(pp->lib)
3124887Schin 				free((void*)pp->lib);
3134887Schin 			if(pp->blib)
3144887Schin 				free((void*)pp->blib);
3154887Schin 			if(pp->bltin_lib || (pp->flags&PATH_STD_DIR))
3164887Schin 			{
3174887Schin 				nv_scan(sh_bltin_tree(),free_bltin,pp,0,0);
318*8462SApril.Chin@Sun.COM #if SHOPT_DYNAMIC
3194887Schin 				if(pp->bltin_lib)
3204887Schin 					dlclose(pp->bltin_lib);
321*8462SApril.Chin@Sun.COM #endif /* SHOPT_DYNAMIC */
3224887Schin 			}
3234887Schin 			free((void*)pp);
3244887Schin 			if(old)
3254887Schin 				old->next = ppnext;
3264887Schin 		}
3274887Schin 		else
3284887Schin 			old = pp;
3294887Schin 		pp = ppnext;
3304887Schin 	}
3314887Schin }
3324887Schin 
3334887Schin /*
3344887Schin  * returns library variable from .paths
3354887Schin  * The value might be returned on the stack overwriting path
3364887Schin  */
3374887Schin static char *path_lib(Pathcomp_t *pp, char *path)
3384887Schin {
3394887Schin 	register char *last = strrchr(path,'/');
3404887Schin 	register int r;
3414887Schin 	struct stat statb;
3424887Schin 	if(last)
3434887Schin 		*last = 0;
3444887Schin 	else
3454887Schin 		path = ".";
3464887Schin 	r = stat(path,&statb);
3474887Schin 	if(last)
3484887Schin 		*last = '/';
3494887Schin 	if(r>=0)
3504887Schin 	{
3514887Schin 		Pathcomp_t pcomp;
3524887Schin 		char save[8];
3534887Schin 		for( ;pp; pp=pp->next)
3544887Schin 		{
355*8462SApril.Chin@Sun.COM 			if(pp->ino==statb.st_ino && pp->dev==statb.st_dev && pp->mtime==statb.st_mtime)
3564887Schin 				return(pp->lib);
3574887Schin 		}
3584887Schin 		pcomp.len = 0;
3594887Schin 		if(last)
3604887Schin 			pcomp.len = last-path;
3614887Schin 		memcpy((void*)save, (void*)stakptr(PATH_OFFSET+pcomp.len),sizeof(save));
3624887Schin 		if(path_chkpaths((Pathcomp_t*)0,(Pathcomp_t*)0,&pcomp,PATH_OFFSET))
3634887Schin 			return(stakfreeze(1));
3644887Schin 		memcpy((void*)stakptr(PATH_OFFSET+pcomp.len),(void*)save,sizeof(save));
3654887Schin 	}
3664887Schin 	return(0);
3674887Schin }
3684887Schin 
3694887Schin #if 0
3704887Schin void path_dump(register Pathcomp_t *pp)
3714887Schin {
3724887Schin 	sfprintf(sfstderr,"dump\n");
3734887Schin 	while(pp)
3744887Schin 	{
3754887Schin 		sfprintf(sfstderr,"pp=%x dev=%d ino=%d len=%d flags=%o name=%.*s\n",
3764887Schin 			pp,pp->dev,pp->ino,pp->len,pp->flags,pp->len,pp->name);
3774887Schin 		pp = pp->next;
3784887Schin 	}
3794887Schin }
3804887Schin #endif
3814887Schin 
3824887Schin /*
3834887Schin  * write the next path to search on the current stack
3844887Schin  * if last is given, all paths that come before <last> are skipped
3854887Schin  * the next pathcomp is returned.
3864887Schin  */
3874887Schin Pathcomp_t *path_nextcomp(register Pathcomp_t *pp, const char *name, Pathcomp_t *last)
3884887Schin {
3894887Schin 	stakseek(PATH_OFFSET);
3904887Schin 	if(*name=='/')
3914887Schin 		pp = 0;
3924887Schin 	else
3934887Schin 	{
3944887Schin 		for(;pp && pp!=last;pp=pp->next)
3954887Schin 		{
3964887Schin 			if(pp->flags&PATH_SKIP)
3974887Schin 				continue;
3984887Schin 			if(!last || *pp->name!='/')
3994887Schin 				break;
4004887Schin 		}
4014887Schin 		if(!pp)		/* this should not happen */
4024887Schin 			pp = last;
4034887Schin 	}
4044887Schin 	if(pp && (pp->name[0]!='.' || pp->name[1]))
4054887Schin 	{
4064887Schin 		if(*pp->name!='/')
4074887Schin 		{
4084887Schin 			stakputs(path_pwd(1));
4094887Schin 			if(*stakptr(staktell()-1)!='/')
4104887Schin 				stakputc('/');
4114887Schin 		}
4124887Schin 		stakwrite(pp->name,pp->len);
4134887Schin 		if(pp->name[pp->len-1]!='/')
4144887Schin 			stakputc('/');
4154887Schin 	}
4164887Schin 	stakputs(name);
4174887Schin 	stakputc(0);
4184887Schin 	while(pp && pp!=last && (pp=pp->next))
4194887Schin 	{
4204887Schin 		if(!(pp->flags&PATH_SKIP))
4214887Schin 			return(pp);
4224887Schin 	}
4234887Schin 	return((Pathcomp_t*)0);
4244887Schin }
4254887Schin 
4264887Schin static Pathcomp_t* defpath_init(Shell_t *shp)
4274887Schin {
4284887Schin 	Pathcomp_t *pp = (void*)path_addpath((Pathcomp_t*)0,(std_path),PATH_PATH);
4294887Schin 	if(shp->defpathlist = (void*)pp)
4304887Schin 		pp->shp = shp;
4314887Schin 	return(pp);
4324887Schin }
4334887Schin 
4344887Schin static void path_init(Shell_t *shp)
4354887Schin {
4364887Schin 	const char *val;
4374887Schin 	Pathcomp_t *pp;
4384887Schin 	if(!std_path && !(std_path=astconf("PATH",NIL(char*),NIL(char*))))
4394887Schin 		std_path = e_defpath;
440*8462SApril.Chin@Sun.COM 	if(val=sh_scoped(shp,(PATHNOD))->nvalue.cp)
4414887Schin 	{
4424887Schin 		pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_PATH);
4434887Schin 		if(shp->pathlist = (void*)pp)
4444887Schin 			pp->shp = shp;
4454887Schin 	}
4464887Schin 	else
4474887Schin 	{
4484887Schin 		if(!(pp=(Pathcomp_t*)shp->defpathlist))
4494887Schin 			pp = defpath_init(shp);
4504887Schin 		shp->pathlist = (void*)path_dup(pp);
4514887Schin 	}
452*8462SApril.Chin@Sun.COM 	if(val=sh_scoped(shp,(FPATHNOD))->nvalue.cp)
4534887Schin 	{
4544887Schin 		pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_FPATH);
4554887Schin 		if(shp->pathlist = (void*)pp)
4564887Schin 			pp->shp = shp;
4574887Schin 	}
4584887Schin }
4594887Schin 
4604887Schin /*
4614887Schin  * returns that pathlist to search
4624887Schin  */
4634887Schin Pathcomp_t *path_get(register const char *name)
4644887Schin {
4654887Schin 	register Shell_t *shp = &sh;
4664887Schin 	register Pathcomp_t *pp=0;
4674887Schin 	if(*name && strchr(name,'/'))
4684887Schin 		return(0);
4694887Schin 	if(!sh_isstate(SH_DEFPATH))
4704887Schin 	{
4714887Schin 		if(!shp->pathlist)
4724887Schin 			path_init(shp);
4734887Schin 		pp = (Pathcomp_t*)shp->pathlist;
4744887Schin 	}
4754887Schin 	if(!pp && (!(PATHNOD)->nvalue.cp) || sh_isstate(SH_DEFPATH))
4764887Schin 	{
4774887Schin 		if(!(pp=(Pathcomp_t*)shp->defpathlist))
4784887Schin 			pp = defpath_init(shp);
4794887Schin 	}
4804887Schin 	return(pp);
4814887Schin }
4824887Schin 
4834887Schin /*
4844887Schin  * open file corresponding to name using path give by <pp>
4854887Schin  */
4864887Schin static int	path_opentype(const char *name, register Pathcomp_t *pp, int fun)
4874887Schin {
4884887Schin 	register int fd= -1;
4894887Schin 	struct stat statb;
4904887Schin 	Pathcomp_t *oldpp;
4914887Schin 	Shell_t *shp;
4924887Schin 	if(pp)
4934887Schin 		shp = pp->shp;
4944887Schin 	else
4954887Schin 	{
4964887Schin 		shp = sh_getinterp();
4974887Schin 		if(!shp->pathlist)
4984887Schin 			path_init(shp);
4994887Schin 	}
5004887Schin 	if(!fun && strchr(name,'/'))
5014887Schin 	{
5024887Schin 		if(sh_isoption(SH_RESTRICTED))
5034887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_restricted,name);
5044887Schin 	}
5054887Schin 	do
5064887Schin 	{
5074887Schin 		pp = path_nextcomp(oldpp=pp,name,0);
5084887Schin 		while(oldpp && (oldpp->flags&PATH_SKIP))
5094887Schin 			oldpp = oldpp->next;
5104887Schin 		if(fun && (!oldpp || !(oldpp->flags&PATH_FPATH)))
5114887Schin 			continue;
5124887Schin 		if((fd = sh_open(path_relative(stakptr(PATH_OFFSET)),O_RDONLY,0)) >= 0)
5134887Schin 		{
5144887Schin 			if(fstat(fd,&statb)<0 || S_ISDIR(statb.st_mode))
5154887Schin 			{
5164887Schin 				errno = EISDIR;
5174887Schin 				sh_close(fd);
5184887Schin 				fd = -1;
5194887Schin 			}
5204887Schin 		}
5214887Schin 	}
5224887Schin 	while( fd<0 && pp);
5234887Schin 	if(fd>=0 && (fd = sh_iomovefd(fd)) > 0)
5244887Schin 	{
5254887Schin 		fcntl(fd,F_SETFD,FD_CLOEXEC);
5264887Schin 		shp->fdstatus[fd] |= IOCLEX;
5274887Schin 	}
5284887Schin 	return(fd);
5294887Schin }
5304887Schin 
5314887Schin /*
5324887Schin  * open file corresponding to name using path give by <pp>
5334887Schin  */
5344887Schin int	path_open(const char *name, register Pathcomp_t *pp)
5354887Schin {
5364887Schin 	return(path_opentype(name,pp,0));
5374887Schin }
5384887Schin 
5394887Schin /*
5404887Schin  * given a pathname return the base name
5414887Schin  */
5424887Schin 
5434887Schin char	*path_basename(register const char *name)
5444887Schin {
5454887Schin 	register const char *start = name;
5464887Schin 	while (*name)
5474887Schin 		if ((*name++ == '/') && *name)	/* don't trim trailing / */
5484887Schin 			start = name;
5494887Schin 	return ((char*)start);
5504887Schin }
5514887Schin 
5524887Schin char *path_fullname(const char *name)
5534887Schin {
5544887Schin 	int len=strlen(name)+1,dirlen=0;
5554887Schin 	char *path,*pwd;
5564887Schin 	if(*name!='/')
5574887Schin 	{
5584887Schin 		pwd = path_pwd(1);
5594887Schin 		dirlen = strlen(pwd)+1;
5604887Schin 	}
5614887Schin 	path = (char*)malloc(len+dirlen);
5624887Schin 	if(dirlen)
5634887Schin 	{
5644887Schin 		memcpy((void*)path,(void*)pwd,dirlen);
5654887Schin 		path[dirlen-1] = '/';
5664887Schin 	}
5674887Schin 	memcpy((void*)&path[dirlen],(void*)name,len);
5684887Schin 	pathcanon(path,0);
5694887Schin 	return(path);
5704887Schin }
5714887Schin 
5724887Schin /*
5734887Schin  * load functions from file <fno>
5744887Schin  */
5754887Schin static void funload(Shell_t *shp,int fno, const char *name)
5764887Schin {
577*8462SApril.Chin@Sun.COM 	char		*pname,*oldname=shp->st.filename, buff[IOBSIZE+1];
578*8462SApril.Chin@Sun.COM 	Namval_t	*np;
579*8462SApril.Chin@Sun.COM 	struct Ufunction *rp;
580*8462SApril.Chin@Sun.COM 	int		 savestates = sh_getstate(), oldload=shp->funload;
581*8462SApril.Chin@Sun.COM 	pname = path_fullname(stakptr(PATH_OFFSET));
582*8462SApril.Chin@Sun.COM 	if(shp->fpathdict && (rp = dtmatch(shp->fpathdict,(void*)pname)))
583*8462SApril.Chin@Sun.COM 	{
584*8462SApril.Chin@Sun.COM 		do
585*8462SApril.Chin@Sun.COM 		{
586*8462SApril.Chin@Sun.COM 			if((np = dtsearch(shp->fun_tree,rp->np)) && is_afunction(np))
587*8462SApril.Chin@Sun.COM 			{
588*8462SApril.Chin@Sun.COM 				if(np->nvalue.rp)
589*8462SApril.Chin@Sun.COM 					np->nvalue.rp->fdict = 0;
590*8462SApril.Chin@Sun.COM 				nv_delete(np,shp->fun_tree,NV_NOFREE);
591*8462SApril.Chin@Sun.COM 			}
592*8462SApril.Chin@Sun.COM 			dtinsert(shp->fun_tree,rp->np);
593*8462SApril.Chin@Sun.COM 			rp->fdict = shp->fun_tree;
594*8462SApril.Chin@Sun.COM 		}
595*8462SApril.Chin@Sun.COM 		while((rp=dtnext(shp->fpathdict,rp)) && strcmp(pname,rp->fname)==0);
596*8462SApril.Chin@Sun.COM 		return;
597*8462SApril.Chin@Sun.COM 	}
5984887Schin 	sh_onstate(SH_NOLOG);
5994887Schin 	sh_onstate(SH_NOALIAS);
6004887Schin 	shp->readscript = (char*)name;
601*8462SApril.Chin@Sun.COM 	shp->st.filename = pname;
602*8462SApril.Chin@Sun.COM 	shp->funload = 1;
6034887Schin 	error_info.line = 0;
6044887Schin 	sh_eval(sfnew(NIL(Sfio_t*),buff,IOBSIZE,fno,SF_READ),0);
6054887Schin 	shp->readscript = 0;
6064887Schin 	free((void*)shp->st.filename);
607*8462SApril.Chin@Sun.COM 	shp->funload = oldload;
6084887Schin 	shp->st.filename = oldname;
6094887Schin 	sh_setstate(savestates);
6104887Schin }
6114887Schin 
6124887Schin /*
6134887Schin  * do a path search and track alias if requested
6144887Schin  * if flag is 0, or if name not found, then try autoloading function
615*8462SApril.Chin@Sun.COM  * if flag==2 or 3, returns 1 if name found on FPATH
616*8462SApril.Chin@Sun.COM  * if flag==3 no tracked alias will be set
6174887Schin  * returns 1, if function was autoloaded.
618*8462SApril.Chin@Sun.COM  * If oldpp is not NULL, it will contain a pointer to the path component
619*8462SApril.Chin@Sun.COM  *    where it was found.
6204887Schin  */
6214887Schin 
622*8462SApril.Chin@Sun.COM int	path_search(register const char *name,Pathcomp_t **oldpp, int flag)
6234887Schin {
6244887Schin 	register Namval_t *np;
6254887Schin 	register int fno;
6264887Schin 	Pathcomp_t *pp=0;
6274887Schin 	Shell_t *shp = &sh;
6284887Schin 	if(name && strchr(name,'/'))
6294887Schin 	{
6304887Schin 		stakseek(PATH_OFFSET);
6314887Schin 		stakputs(name);
6324887Schin 		if(canexecute(stakptr(PATH_OFFSET),0)<0)
6334887Schin 		{
6344887Schin 			*stakptr(PATH_OFFSET) = 0;
6354887Schin 			return(0);
6364887Schin 		}
6374887Schin 		if(*name=='/')
6384887Schin 			return(1);
6394887Schin 		stakseek(PATH_OFFSET);
6404887Schin 		stakputs(path_pwd(1));
6414887Schin 		stakputc('/');
6424887Schin 		stakputs(name);
6434887Schin 		stakputc(0);
6444887Schin 		return(0);
6454887Schin 	}
6464887Schin 	if(sh_isstate(SH_DEFPATH))
6474887Schin 	{
6484887Schin 		if(!shp->defpathlist)
6494887Schin 			defpath_init(shp);
6504887Schin 	}
6514887Schin 	else if(!shp->pathlist)
6524887Schin 		path_init(shp);
6534887Schin 	if(flag)
6544887Schin 	{
655*8462SApril.Chin@Sun.COM 		pp = path_absolute(name,oldpp?*oldpp:NIL(Pathcomp_t*));
656*8462SApril.Chin@Sun.COM 		if(oldpp)
657*8462SApril.Chin@Sun.COM 			*oldpp = pp;
6584887Schin 		if(!pp && (np=nv_search(name,sh.fun_tree,HASH_NOSCOPE))&&np->nvalue.ip)
6594887Schin 			return(1);
6604887Schin 		if(!pp)
6614887Schin 			*stakptr(PATH_OFFSET) = 0;
6624887Schin 	}
6634887Schin 	if(flag==0 || !pp || (pp->flags&PATH_FPATH))
6644887Schin 	{
6654887Schin 		if(!pp)
6664887Schin 			pp=sh_isstate(SH_DEFPATH)?shp->defpathlist:shp->pathlist;
6674887Schin 		if(pp && strmatch(name,e_alphanum)  && (fno=path_opentype(name,pp,1))>=0)
6684887Schin 		{
6694887Schin 			if(flag==2)
6704887Schin 			{
6714887Schin 				sh_close(fno);
6724887Schin 				return(1);
6734887Schin 			}
6744887Schin 			funload(shp,fno,name);
6754887Schin 			return(1);
6764887Schin 		}
6774887Schin 		*stakptr(PATH_OFFSET) = 0;
6784887Schin 		return(0);
6794887Schin 	}
680*8462SApril.Chin@Sun.COM 	else if(pp && !sh_isstate(SH_DEFPATH) && *name!='/' && flag<3)
6814887Schin 	{
6824887Schin 		if(np=nv_search(name,shp->track_tree,NV_ADD))
6834887Schin 			path_alias(np,pp);
6844887Schin 	}
6854887Schin 	return(0);
6864887Schin }
6874887Schin 
6884887Schin 
6894887Schin /*
6904887Schin  * do a path search and find the full pathname of file name
6914887Schin  */
6924887Schin 
693*8462SApril.Chin@Sun.COM Pathcomp_t *path_absolute(register const char *name, Pathcomp_t *pp)
6944887Schin {
6954887Schin 	register int	f,isfun;
6964887Schin 	int		noexec=0;
697*8462SApril.Chin@Sun.COM 	Pathcomp_t	*oldpp;
6984887Schin 	Shell_t		*shp = &sh;
6994887Schin 	Namval_t	*np;
7004887Schin 	shp->path_err = ENOENT;
701*8462SApril.Chin@Sun.COM 	if(!pp && !(pp=path_get("")))
7024887Schin 		return(0);
7034887Schin 	shp->path_err = 0;
7044887Schin 	while(1)
7054887Schin 	{
7064887Schin 		sh_sigcheck();
7074887Schin 		isfun = (pp->flags&PATH_FPATH);
7084887Schin 		if(oldpp=pp)
7094887Schin 			pp = path_nextcomp(pp,name,0);
7104887Schin 		if(!isfun && !sh_isoption(SH_RESTRICTED))
7114887Schin 		{
712*8462SApril.Chin@Sun.COM 			if(*stakptr(PATH_OFFSET)=='/' && nv_search(stakptr(PATH_OFFSET),sh.bltin_tree,0))
7134887Schin 				return(oldpp);
714*8462SApril.Chin@Sun.COM #if SHOPT_DYNAMIC
7154887Schin 			if(oldpp->blib)
7164887Schin 			{
7174887Schin 				typedef int (*Fptr_t)(int, char*[], void*);
7184887Schin 				Fptr_t addr;
7194887Schin 				int n = staktell();
7204887Schin 				char *cp;
7214887Schin 				stakputs("b_");
7224887Schin 				stakputs(name);
7234887Schin 				stakputc(0);
7244887Schin 				if(!oldpp->bltin_lib)
7254887Schin 				{
7264887Schin 					if(cp = strrchr(oldpp->blib,'/'))
7274887Schin 						cp++;
7284887Schin 					else
7294887Schin 						cp = oldpp->blib;
7304887Schin 					if(strcmp(cp,LIBCMD)==0 && (addr=(Fptr_t)dlllook((void*)0,stakptr(n))))
7314887Schin 					{
732*8462SApril.Chin@Sun.COM 						if((np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL)) && nv_isattr(np,NV_BLTINOPT))
733*8462SApril.Chin@Sun.COM 							return(oldpp);
7344887Schin 					}
7354887Schin #if (_AST_VERSION>=20040404)
7364887Schin 					if (oldpp->bltin_lib = dllplug(SH_ID, oldpp->blib, NiL, RTLD_LAZY, NiL, 0))
7374887Schin #else
7384887Schin 					if (oldpp->bltin_lib = dllfind(oldpp->blib, NiL, RTLD_LAZY, NiL, 0))
7394887Schin #endif
7404887Schin 						sh_addlib(oldpp->bltin_lib);
7414887Schin 				}
7424887Schin 				if((addr=(Fptr_t)dlllook(oldpp->bltin_lib,stakptr(n))) &&
7434887Schin 				   (!(np = sh_addbuiltin(stakptr(PATH_OFFSET),NiL,NiL)) || np->nvalue.bfp!=addr) &&
7444887Schin 				   (np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL)))
7454887Schin 				{
7464887Schin 					np->nvenv = oldpp->bltin_lib;
7474887Schin 					return(oldpp);
7484887Schin 				}
7494887Schin 			}
750*8462SApril.Chin@Sun.COM #endif /* SHOPT_DYNAMIC */
7514887Schin 		}
752*8462SApril.Chin@Sun.COM 		sh_stats(STAT_PATHS);
7534887Schin 		f = canexecute(stakptr(PATH_OFFSET),isfun);
7544887Schin 		if(isfun && f>=0)
7554887Schin 		{
7564887Schin 			nv_onattr(nv_open(name,shp->fun_tree,NV_NOARRAY|NV_IDENT|NV_NOSCOPE),NV_LTOU|NV_FUNCTION);
7574887Schin 			close(f);
7584887Schin 			f = -1;
7594887Schin 			return(0);
7604887Schin 		}
7614887Schin 		else if(f>=0 && (oldpp->flags & PATH_STD_DIR))
7624887Schin 		{
763*8462SApril.Chin@Sun.COM 			int n = staktell();
7644887Schin 			stakputs("/bin/");
7654887Schin 			stakputs(name);
7664887Schin 			stakputc(0);
767*8462SApril.Chin@Sun.COM 			np = nv_search(stakptr(n),sh.bltin_tree,0);
768*8462SApril.Chin@Sun.COM 			stakseek(n);
7694887Schin 			if(np)
7704887Schin 			{
771*8462SApril.Chin@Sun.COM 				n = np->nvflag;
772*8462SApril.Chin@Sun.COM 				np = sh_addbuiltin(stakptr(PATH_OFFSET),np->nvalue.bfp,nv_context(np));
773*8462SApril.Chin@Sun.COM 				np->nvflag = n;
7744887Schin 			}
7754887Schin 		}
7764887Schin 		if(!pp || f>=0)
7774887Schin 			break;
7784887Schin 		if(errno!=ENOENT)
7794887Schin 			noexec = errno;
7804887Schin 	}
7814887Schin 	if(f<0)
7824887Schin 	{
783*8462SApril.Chin@Sun.COM 		shp->path_err = (noexec?noexec:ENOENT);
7844887Schin 		return(0);
7854887Schin 	}
7864887Schin 	stakputc(0);
7874887Schin 	return(oldpp);
7884887Schin }
7894887Schin 
7904887Schin /*
7914887Schin  * returns 0 if path can execute
7924887Schin  * sets exec_err if file is found but can't be executable
7934887Schin  */
7944887Schin #undef S_IXALL
7954887Schin #ifdef S_IXUSR
7964887Schin #   define S_IXALL	(S_IXUSR|S_IXGRP|S_IXOTH)
7974887Schin #else
7984887Schin #   ifdef S_IEXEC
7994887Schin #	define S_IXALL	(S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6))
8004887Schin #   else
8014887Schin #	define S_IXALL	0111
8024887Schin #   endif /*S_EXEC */
8034887Schin #endif /* S_IXUSR */
8044887Schin 
8054887Schin static int canexecute(register char *path, int isfun)
8064887Schin {
8074887Schin 	struct stat statb;
8084887Schin 	register int fd=0;
8094887Schin 	path = path_relative(path);
8104887Schin 	if(isfun)
8114887Schin 	{
8124887Schin 		if((fd=open(path,O_RDONLY,0))<0 || fstat(fd,&statb)<0)
8134887Schin 			goto err;
8144887Schin 	}
8154887Schin 	else if(stat(path,&statb) < 0)
8164887Schin 	{
8174887Schin #if _WINIX
8184887Schin 		/* check for .exe or .bat suffix */
8194887Schin 		char *cp;
8204887Schin 		if(errno==ENOENT && (!(cp=strrchr(path,'.')) || strlen(cp)>4 || strchr(cp,'/')))
8214887Schin 		{
8224887Schin 			int offset = staktell()-1;
8234887Schin 			stakseek(offset);
8244887Schin 			stakputs(".bat");
8254887Schin 			path = stakptr(PATH_OFFSET);
8264887Schin 			if(stat(path,&statb) < 0)
8274887Schin 			{
8284887Schin 				if(errno!=ENOENT)
8294887Schin 					goto err;
8304887Schin 				memcpy(stakptr(offset),".sh",4);
8314887Schin 				if(stat(path,&statb) < 0)
8324887Schin 					goto err;
8334887Schin 			}
8344887Schin 		}
8354887Schin 		else
8364887Schin #endif /* _WINIX */
8374887Schin 		goto err;
8384887Schin 	}
8394887Schin 	errno = EPERM;
8404887Schin 	if(S_ISDIR(statb.st_mode))
8414887Schin 		errno = EISDIR;
8424887Schin 	else if((statb.st_mode&S_IXALL)==S_IXALL || sh_access(path,X_OK)>=0)
8434887Schin 		return(fd);
8444887Schin 	if(isfun && fd>=0)
8454887Schin 		sh_close(fd);
8464887Schin err:
8474887Schin 	return(-1);
8484887Schin }
8494887Schin 
8504887Schin /*
8514887Schin  * Return path relative to present working directory
8524887Schin  */
8534887Schin 
8544887Schin char *path_relative(register const char* file)
8554887Schin {
8564887Schin 	register const char *pwd;
8574887Schin 	register const char *fp = file;
8584887Schin 	/* can't relpath when sh.pwd not set */
8594887Schin 	if(!(pwd=sh.pwd))
8604887Schin 		return((char*)fp);
8614887Schin 	while(*pwd==*fp)
8624887Schin 	{
8634887Schin 		if(*pwd++==0)
8644887Schin 			return((char*)e_dot);
8654887Schin 		fp++;
8664887Schin 	}
8674887Schin 	if(*pwd==0 && *fp == '/')
8684887Schin 	{
8694887Schin 		while(*++fp=='/');
8704887Schin 		if(*fp)
8714887Schin 			return((char*)fp);
8724887Schin 		return((char*)e_dot);
8734887Schin 	}
8744887Schin 	return((char*)file);
8754887Schin }
8764887Schin 
8774887Schin void	path_exec(register const char *arg0,register char *argv[],struct argnod *local)
8784887Schin {
8794887Schin 	char **envp;
8804887Schin 	const char *opath;
8814887Schin 	Pathcomp_t *libpath, *pp=0;
8824887Schin 	Shell_t *shp = &sh;
8834887Schin 	int slash=0;
8844887Schin 	nv_setlist(local,NV_EXPORT|NV_IDENT|NV_ASSIGN);
8854887Schin 	envp = sh_envgen();
8864887Schin 	if(strchr(arg0,'/'))
8874887Schin 	{
8884887Schin 		slash=1;
8894887Schin 		/* name containing / not allowed for restricted shell */
8904887Schin 		if(sh_isoption(SH_RESTRICTED))
8914887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_restricted,arg0);
8924887Schin 	}
8934887Schin 	else
8944887Schin 		pp=path_get(arg0);
8954887Schin 	shp->path_err= ENOENT;
8964887Schin 	sfsync(NIL(Sfio_t*));
8974887Schin 	timerdel(NIL(void*));
8984887Schin 	/* find first path that has a library component */
8994887Schin 	if(pp || slash) do
9004887Schin 	{
9014887Schin 		sh_sigcheck();
9024887Schin 		if(libpath=pp)
9034887Schin 		{
9044887Schin 			pp = path_nextcomp(pp,arg0,0);
9054887Schin 			opath = stakfreeze(1)+PATH_OFFSET;
9064887Schin 		}
9074887Schin 		else
9084887Schin 			opath = arg0;
9094887Schin 		path_spawn(opath,argv,envp,libpath,0);
9104887Schin 		while(pp && (pp->flags&PATH_FPATH))
9114887Schin 			pp = path_nextcomp(pp,arg0,0);
9124887Schin 	}
9134887Schin 	while(pp);
9144887Schin 	/* force an exit */
9154887Schin 	((struct checkpt*)shp->jmplist)->mode = SH_JMPEXIT;
9164887Schin 	if((errno=shp->path_err)==ENOENT)
9174887Schin 		errormsg(SH_DICT,ERROR_exit(ERROR_NOENT),e_found,arg0);
9184887Schin 	else
9194887Schin 		errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,arg0);
9204887Schin }
9214887Schin 
9224887Schin pid_t path_spawn(const char *opath,register char **argv, char **envp, Pathcomp_t *libpath, int spawn)
9234887Schin {
9244887Schin 	Shell_t *shp = sh_getinterp();
9254887Schin 	register char *path;
9264887Schin 	char **xp=0, *xval, *libenv = (libpath?libpath->lib:0);
9274887Schin 	Namval_t*	np;
9284887Schin 	char		*s, *v;
9294887Schin 	int		r, n;
9304887Schin 	pid_t		pid= -1;
9314887Schin 	/* leave room for inserting _= pathname in environment */
9324887Schin 	envp--;
9334887Schin #if _lib_readlink
9344887Schin 	/* save original pathname */
9354887Schin 	stakseek(PATH_OFFSET);
9364887Schin 	stakputs(opath);
9374887Schin 	opath = stakfreeze(1)+PATH_OFFSET;
9384887Schin 	np=nv_search(argv[0],shp->track_tree,0);
9394887Schin 	while(libpath && !libpath->lib)
9404887Schin 		libpath=libpath->next;
9414887Schin 	if(libpath && (!np || nv_size(np)>0))
9424887Schin 	{
9434887Schin 		/* check for symlink and use symlink name */
9444887Schin 		char buff[PATH_MAX+1];
9454887Schin 		char save[PATH_MAX+1];
9464887Schin 		stakseek(PATH_OFFSET);
9474887Schin 		stakputs(opath);
9484887Schin 		path = stakptr(PATH_OFFSET);
9494887Schin 		while((n=readlink(path,buff,PATH_MAX))>0)
9504887Schin 		{
9514887Schin 			buff[n] = 0;
9524887Schin 			n = PATH_OFFSET;
9534887Schin 			r = 0;
9544887Schin 			if((v=strrchr(path,'/')) && *buff!='/')
9554887Schin 			{
9564887Schin 				if(buff[0]=='.' && buff[1]=='.' && (r = strlen(path) + 1) <= PATH_MAX)
9574887Schin 					memcpy(save, path, r);
9584887Schin 				else
9594887Schin 					r = 0;
9604887Schin 				n += (v+1-path);
9614887Schin 			}
9624887Schin 			stakseek(n);
9634887Schin 			stakputs(buff);
9644887Schin 			stakputc(0);
9654887Schin 			path = stakptr(PATH_OFFSET);
9664887Schin 			if(v && buff[0]=='.' && buff[1]=='.')
9674887Schin 			{
9684887Schin 				pathcanon(path, 0);
9694887Schin 				if(r && access(path,X_OK))
9704887Schin 				{
9714887Schin 					memcpy(path, save, r);
9724887Schin 					break;
9734887Schin 				}
9744887Schin 			}
9754887Schin 			if(libenv = path_lib(libpath,path))
9764887Schin 				break;
9774887Schin 		}
9784887Schin 		stakseek(0);
9794887Schin 	}
9804887Schin #endif
9814887Schin 	if(libenv && (v = strchr(libenv,'=')))
9824887Schin 	{
9834887Schin 		n = v - libenv;
9844887Schin 		*v = 0;
9854887Schin 		np = nv_open(libenv,shp->var_tree,0);
9864887Schin 		*v = '=';
9874887Schin 		s = nv_getval(np);
9884887Schin 		stakputs(libenv);
9894887Schin 		if(s)
9904887Schin 		{
9914887Schin 			stakputc(':');
9924887Schin 			stakputs(s);
9934887Schin 		}
9944887Schin 		v = stakfreeze(1);
9954887Schin 		r = 1;
996*8462SApril.Chin@Sun.COM 		xp = envp + 1;
9974887Schin 		while (s = *xp++)
9984887Schin 		{
9994887Schin 			if (strneq(s, v, n) && s[n] == '=')
10004887Schin 			{
10014887Schin 				xval = *--xp;
10024887Schin 				*xp = v;
10034887Schin 				r = 0;
10044887Schin 				break;
10054887Schin 			}
10064887Schin 		}
10074887Schin 		if (r)
10084887Schin 		{
10094887Schin 			*envp-- = v;
10104887Schin 			xp = 0;
10114887Schin 		}
10124887Schin 	}
10134887Schin 	if(!opath)
10144887Schin 		opath = stakptr(PATH_OFFSET);
10154887Schin 	envp[0] =  (char*)opath-PATH_OFFSET;
10164887Schin 	envp[0][0] =  '_';
10174887Schin 	envp[0][1] =  '=';
10184887Schin 	sfsync(sfstderr);
10194887Schin 	sh_sigcheck();
10204887Schin 	path = path_relative(opath);
10214887Schin #ifdef SHELLMAGIC
10224887Schin 	if(*path!='/' && path!=opath)
10234887Schin 	{
10244887Schin 		/*
10254887Schin 		 * The following code because execv(foo,) and execv(./foo,)
10264887Schin 		 * may not yield the same results
10274887Schin 		 */
10284887Schin 		char *sp = (char*)malloc(strlen(path)+3);
10294887Schin 		sp[0] = '.';
10304887Schin 		sp[1] = '/';
10314887Schin 		strcpy(sp+2,path);
10324887Schin 		path = sp;
10334887Schin 	}
10344887Schin #endif /* SHELLMAGIC */
10354887Schin 	if(spawn && !sh_isoption(SH_PFSH))
10364887Schin 		pid = _spawnveg(opath, &argv[0],envp, spawn>>1);
10374887Schin 	else
1038*8462SApril.Chin@Sun.COM 		pid = path_pfexecve(opath, &argv[0] ,envp,spawn);
10394887Schin 	if(xp)
10404887Schin 		*xp = xval;
10414887Schin #ifdef SHELLMAGIC
10424887Schin 	if(*path=='.' && path!=opath)
10434887Schin 	{
10444887Schin 		free(path);
10454887Schin 		path = path_relative(opath);
10464887Schin 	}
10474887Schin #endif /* SHELLMAGIC */
10484887Schin 	if(pid>0)
10494887Schin 		return(pid);
10504887Schin retry:
10514887Schin 	switch(sh.path_err = errno)
10524887Schin 	{
10534887Schin #ifdef apollo
10544887Schin 	    /*
10554887Schin   	     * On apollo's execve will fail with eacces when
10564887Schin 	     * file has execute but not read permissions. So,
10574887Schin 	     * for now we will pretend that EACCES and ENOEXEC
10584887Schin  	     * mean the same thing.
10594887Schin  	     */
10604887Schin 	    case EACCES:
10614887Schin #endif /* apollo */
10624887Schin 	    case ENOEXEC:
10634887Schin #if SHOPT_SUID_EXEC
10644887Schin 	    case EPERM:
10654887Schin 		/* some systems return EPERM if setuid bit is on */
10664887Schin #endif
10674887Schin 		errno = ENOEXEC;
10684887Schin 		if(spawn)
10694887Schin 		{
10704887Schin #ifdef _lib_fork
10714887Schin 			if(sh.subshell)
10724887Schin 				return(-1);
10734887Schin 			do
10744887Schin 			{
10754887Schin 				if((pid=fork())>0)
10764887Schin 					return(pid);
10774887Schin 			}
10784887Schin 			while(_sh_fork(pid,0,(int*)0) < 0);
1079*8462SApril.Chin@Sun.COM 			((struct checkpt*)shp->jmplist)->mode = SH_JMPEXIT;
10804887Schin #else
10814887Schin 			return(-1);
10824887Schin #endif
10834887Schin 		}
10844887Schin 		exscript(shp,path,argv,envp);
10854887Schin #ifndef apollo
10864887Schin 	    case EACCES:
10874887Schin 	    {
10884887Schin 		struct stat statb;
10894887Schin 		if(stat(path,&statb)>=0)
10904887Schin 		{
10914887Schin 			if(S_ISDIR(statb.st_mode))
10924887Schin 				errno = EISDIR;
10934887Schin #ifdef S_ISSOCK
10944887Schin 			if(S_ISSOCK(statb.st_mode))
10954887Schin 				exscript(shp,path,argv,envp);
10964887Schin #endif
10974887Schin 		}
10984887Schin 	    }
10994887Schin 		/* FALL THROUGH */
11004887Schin #endif /* !apollo */
11014887Schin #ifdef ENAMETOOLONG
11024887Schin 	    case ENAMETOOLONG:
11034887Schin #endif /* ENAMETOOLONG */
11044887Schin #if !SHOPT_SUID_EXEC
11054887Schin 	    case EPERM:
11064887Schin #endif
11074887Schin 		shp->path_err = errno;
11084887Schin 		return(-1);
11094887Schin 	    case ENOTDIR:
11104887Schin 	    case ENOENT:
11114887Schin 	    case EINTR:
11124887Schin #ifdef EMLINK
11134887Schin 	    case EMLINK:
11144887Schin #endif /* EMLINK */
11154887Schin 		return(-1);
11164887Schin 	    case E2BIG:
11174887Schin 		if(sh.xargmin)
11184887Schin 		{
11194887Schin 			pid = path_xargs(opath, &argv[0] ,envp,spawn);
11204887Schin 			if(pid<0)
11214887Schin 				goto retry;
11224887Schin 			return(pid);
11234887Schin 		}
11244887Schin 	    default:
11254887Schin 		errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path);
11264887Schin 	}
11274887Schin 	return 0;
11284887Schin }
11294887Schin 
11304887Schin /*
11314887Schin  * File is executable but not machine code.
11324887Schin  * Assume file is a Shell script and execute it.
11334887Schin  */
11344887Schin 
11354887Schin static void exscript(Shell_t *shp,register char *path,register char *argv[],char **envp)
11364887Schin {
11374887Schin 	register Sfio_t *sp;
11384887Schin 	path = path_relative(path);
11394887Schin 	shp->comdiv=0;
11404887Schin 	shp->bckpid = 0;
11414887Schin 	shp->st.ioset=0;
11424887Schin 	/* clean up any cooperating processes */
11434887Schin 	if(shp->cpipe[0]>0)
11444887Schin 		sh_pclose(shp->cpipe);
11454887Schin 	if(shp->cpid && shp->outpipe)
11464887Schin 		sh_close(*shp->outpipe);
11474887Schin 	shp->cpid = 0;
11484887Schin 	if(sp=fcfile())
11494887Schin 		while(sfstack(sp,SF_POPSTACK));
11504887Schin 	job_clear();
11514887Schin 	if(shp->infd>0 && (shp->fdstatus[shp->infd]&IOCLEX))
11524887Schin 		sh_close(shp->infd);
11534887Schin 	sh_setstate(sh_state(SH_FORKED));
11544887Schin 	sfsync(sfstderr);
11554887Schin #if SHOPT_SUID_EXEC && !SHOPT_PFSH
11564887Schin 	/* check if file cannot open for read or script is setuid/setgid  */
11574887Schin 	{
11584887Schin 		static char name[] = "/tmp/euidXXXXXXXXXX";
11594887Schin 		register int n;
11604887Schin 		register uid_t euserid;
11614887Schin 		char *savet=0;
11624887Schin 		struct stat statb;
11634887Schin 		if((n=sh_open(path,O_RDONLY,0)) >= 0)
11644887Schin 		{
11654887Schin 			/* move <n> if n=0,1,2 */
11664887Schin 			n = sh_iomovefd(n);
11674887Schin 			if(fstat(n,&statb)>=0 && !(statb.st_mode&(S_ISUID|S_ISGID)))
11684887Schin 				goto openok;
11694887Schin 			sh_close(n);
11704887Schin 		}
11714887Schin 		if((euserid=geteuid()) != shp->userid)
11724887Schin 		{
11734887Schin 			strncpy(name+9,fmtbase((long)getpid(),10,0),sizeof(name)-10);
11744887Schin 			/* create a suid open file with owner equal effective uid */
11754887Schin 			if((n=open(name,O_CREAT|O_TRUNC|O_WRONLY,S_ISUID|S_IXUSR)) < 0)
11764887Schin 				goto fail;
11774887Schin 			unlink(name);
11784887Schin 			/* make sure that file has right owner */
11794887Schin 			if(fstat(n,&statb)<0 || statb.st_uid != euserid)
11804887Schin 				goto fail;
11814887Schin 			if(n!=10)
11824887Schin 			{
11834887Schin 				sh_close(10);
11844887Schin 				fcntl(n, F_DUPFD, 10);
11854887Schin 				sh_close(n);
11864887Schin 				n=10;
11874887Schin 			}
11884887Schin 		}
11894887Schin 		savet = *--argv;
11904887Schin 		*argv = path;
1191*8462SApril.Chin@Sun.COM 		path_pfexecve(e_suidexec,argv,envp,0);
11924887Schin 	fail:
11934887Schin 		/*
11944887Schin 		 *  The following code is just for compatibility
11954887Schin 		 */
11964887Schin 		if((n=open(path,O_RDONLY,0)) < 0)
1197*8462SApril.Chin@Sun.COM 			errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path);
11984887Schin 		if(savet)
11994887Schin 			*argv++ = savet;
12004887Schin 	openok:
12014887Schin 		shp->infd = n;
12024887Schin 	}
12034887Schin #else
1204*8462SApril.Chin@Sun.COM 	if((shp->infd = sh_open(path,O_RDONLY,0)) < 0)
1205*8462SApril.Chin@Sun.COM 		errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path);
12064887Schin #endif
12074887Schin 	shp->infd = sh_iomovefd(shp->infd);
12084887Schin #if SHOPT_ACCT
12094887Schin 	sh_accbegin(path) ;  /* reset accounting */
12104887Schin #endif	/* SHOPT_ACCT */
12114887Schin 	shp->arglist = sh_argcreate(argv);
12124887Schin 	shp->lastarg = strdup(path);
12134887Schin 	/* save name of calling command */
12144887Schin 	shp->readscript = error_info.id;
12154887Schin 	/* close history file if name has changed */
12164887Schin 	if(shp->hist_ptr && (path=nv_getval(HISTFILE)) && strcmp(path,shp->hist_ptr->histname))
12174887Schin 	{
12184887Schin 		hist_close(shp->hist_ptr);
12194887Schin 		(HISTCUR)->nvalue.lp = 0;
12204887Schin 	}
12214887Schin 	sh_offstate(SH_FORKED);
12224887Schin 	siglongjmp(*shp->jmplist,SH_JMPSCRIPT);
12234887Schin }
12244887Schin 
12254887Schin #if SHOPT_ACCT
12264887Schin #   include <sys/acct.h>
12274887Schin #   include "FEATURE/time"
12284887Schin 
12294887Schin     static struct acct sabuf;
12304887Schin     static struct tms buffer;
12314887Schin     static clock_t	before;
12324887Schin     static char *SHACCT; /* set to value of SHACCT environment variable */
12334887Schin     static shaccton;	/* non-zero causes accounting record to be written */
12344887Schin     static int compress(time_t);
12354887Schin     /*
12364887Schin      *	initialize accounting, i.e., see if SHACCT variable set
12374887Schin      */
12384887Schin     void sh_accinit(void)
12394887Schin     {
12404887Schin 	SHACCT = getenv("SHACCT");
12414887Schin     }
12424887Schin     /*
1243*8462SApril.Chin@Sun.COM     * suspend accounting until turned on by sh_accbegin()
12444887Schin     */
12454887Schin     void sh_accsusp(void)
12464887Schin     {
12474887Schin 	shaccton=0;
12484887Schin #ifdef AEXPAND
12494887Schin 	sabuf.ac_flag |= AEXPND;
12504887Schin #endif /* AEXPAND */
12514887Schin     }
12524887Schin 
12534887Schin     /*
12544887Schin      * begin an accounting record by recording start time
12554887Schin      */
12564887Schin     void sh_accbegin(const char *cmdname)
12574887Schin     {
12584887Schin 	if(SHACCT)
12594887Schin 	{
12604887Schin 		sabuf.ac_btime = time(NIL(time_t *));
12614887Schin 		before = times(&buffer);
12624887Schin 		sabuf.ac_uid = getuid();
12634887Schin 		sabuf.ac_gid = getgid();
12644887Schin 		strncpy(sabuf.ac_comm, (char*)path_basename(cmdname),
12654887Schin 			sizeof(sabuf.ac_comm));
12664887Schin 		shaccton = 1;
12674887Schin 	}
12684887Schin     }
12694887Schin     /*
12704887Schin      * terminate an accounting record and append to accounting file
12714887Schin      */
12724887Schin     void	sh_accend(void)
12734887Schin     {
12744887Schin 	int	fd;
12754887Schin 	clock_t	after;
12764887Schin 
12774887Schin 	if(shaccton)
12784887Schin 	{
12794887Schin 		after = times(&buffer);
12804887Schin 		sabuf.ac_utime = compress(buffer.tms_utime + buffer.tms_cutime);
12814887Schin 		sabuf.ac_stime = compress(buffer.tms_stime + buffer.tms_cstime);
12824887Schin 		sabuf.ac_etime = compress( (time_t)(after-before));
12834887Schin 		fd = open( SHACCT , O_WRONLY | O_APPEND | O_CREAT,RW_ALL);
12844887Schin 		write(fd, (const char*)&sabuf, sizeof( sabuf ));
12854887Schin 		close( fd);
12864887Schin 	}
12874887Schin     }
12884887Schin 
12894887Schin     /*
12904887Schin      * Produce a pseudo-floating point representation
12914887Schin      * with 3 bits base-8 exponent, 13 bits fraction.
12924887Schin      */
12934887Schin     static int compress(register time_t t)
12944887Schin     {
12954887Schin 	register int exp = 0, rund = 0;
12964887Schin 
12974887Schin 	while (t >= 8192)
12984887Schin 	{
12994887Schin 		exp++;
13004887Schin 		rund = t&04;
13014887Schin 		t >>= 3;
13024887Schin 	}
13034887Schin 	if (rund)
13044887Schin 	{
13054887Schin 		t++;
13064887Schin 		if (t >= 8192)
13074887Schin 		{
13084887Schin 			t >>= 3;
13094887Schin 			exp++;
13104887Schin 		}
13114887Schin 	}
13124887Schin 	return((exp<<13) + t);
13134887Schin     }
13144887Schin #endif	/* SHOPT_ACCT */
13154887Schin 
13164887Schin 
13174887Schin 
13184887Schin /*
13194887Schin  * add a pathcomponent to the path search list and eliminate duplicates
13204887Schin  * and non-existing absolute paths.
13214887Schin  */
13224887Schin static Pathcomp_t *path_addcomp(Pathcomp_t *first, Pathcomp_t *old,const char *name, int flag)
13234887Schin {
13244887Schin 	register Pathcomp_t *pp, *oldpp;
13254887Schin 	struct stat statb;
13264887Schin 	int len, offset=staktell();
13274887Schin 	if(!(flag&PATH_BFPATH))
13284887Schin 	{
13294887Schin 		register const char *cp = name;
13304887Schin 		while(*cp && *cp!=':')
13314887Schin 			stakputc(*cp++);
13324887Schin 		len = staktell()-offset;
13334887Schin 		stakputc(0);
13344887Schin 		stakseek(offset);
13354887Schin 		name = (const char*)stakptr(offset);
13364887Schin 	}
13374887Schin 	else
13384887Schin 		len = strlen(name);
13394887Schin 	for(pp=first; pp; pp=pp->next)
13404887Schin 	{
13414887Schin 		if(memcmp(name,pp->name,len)==0 && (pp->name[len]==':' || pp->name[len]==0))
13424887Schin 		{
13434887Schin 			pp->flags |= flag;
13444887Schin 			return(first);
13454887Schin 		}
13464887Schin 	}
13474887Schin 	if(old && (old=path_dirfind(old,name,0)))
13484887Schin 	{
13494887Schin 		statb.st_ino = old->ino;
13504887Schin 		statb.st_dev = old->dev;
1351*8462SApril.Chin@Sun.COM 		statb.st_mtime = old->mtime;
13524887Schin 		if(old->ino==0 && old->dev==0)
13534887Schin 			flag |= PATH_SKIP;
13544887Schin 	}
13554887Schin 	else if(stat(name,&statb)<0 || !S_ISDIR(statb.st_mode))
13564887Schin 	{
13574887Schin 		if(*name=='/')
13584887Schin 		{
13594887Schin 			if(strcmp(name,SH_CMDLIB_DIR))
13604887Schin 				return(first);
13614887Schin 			statb.st_dev = 1;
13624887Schin 		}
13634887Schin 		else
13644887Schin 		{
13654887Schin 			flag |= PATH_SKIP;
13664887Schin 			statb.st_dev = 0;
13674887Schin 		}
13684887Schin 		statb.st_ino = 0;
1369*8462SApril.Chin@Sun.COM 		statb.st_mtime = 0;
13704887Schin 	}
13714887Schin 	if(*name=='/' && onstdpath(name))
13724887Schin 		flag |= PATH_STD_DIR;
13734887Schin 	for(pp=first, oldpp=0; pp; oldpp=pp, pp=pp->next)
13744887Schin 	{
1375*8462SApril.Chin@Sun.COM 		if(pp->ino==statb.st_ino && pp->dev==statb.st_dev && pp->mtime==statb.st_mtime)
13764887Schin 		{
13774887Schin 			/* if both absolute paths, eliminate second */
13784887Schin 			pp->flags |= flag;
13794887Schin 			if(*name=='/' && *pp->name=='/')
13804887Schin 				return(first);
13814887Schin 			/* keep the path but mark it as skip */
13824887Schin 			flag |= PATH_SKIP;
13834887Schin 		}
13844887Schin 	}
13854887Schin 	pp = newof((Pathcomp_t*)0,Pathcomp_t,1,len+1);
13864887Schin 	pp->refcount = 1;
13874887Schin 	memcpy((char*)(pp+1),name,len+1);
13884887Schin 	pp->name = (char*)(pp+1);
13894887Schin 	pp->len = len;
13904887Schin 	pp->dev = statb.st_dev;
13914887Schin 	pp->ino = statb.st_ino;
1392*8462SApril.Chin@Sun.COM 	pp->mtime = statb.st_mtime;
13934887Schin 	if(oldpp)
13944887Schin 		oldpp->next = pp;
13954887Schin 	else
13964887Schin 		first = pp;
13974887Schin 	pp->flags = flag;
13984887Schin 	if(pp->ino==0 && pp->dev==1)
13994887Schin 	{
14004887Schin 		pp->flags |= PATH_BUILTIN_LIB;
14014887Schin 		pp->blib = malloc(4);
14024887Schin 		strcpy(pp->blib,LIBCMD);
14034887Schin 		return(first);
14044887Schin 	}
14054887Schin 	if((flag&(PATH_PATH|PATH_SKIP))==PATH_PATH)
14064887Schin 		path_chkpaths(first,old,pp,offset);
14074887Schin 	return(first);
14084887Schin }
14094887Schin 
14104887Schin /*
14114887Schin  * This function checks for the .paths file in directory in <pp>
14124887Schin  * it assumes that the directory is on the stack at <offset>
14134887Schin  */
14144887Schin static int path_chkpaths(Pathcomp_t *first, Pathcomp_t* old,Pathcomp_t *pp, int offset)
14154887Schin {
14164887Schin 	struct stat statb;
14174887Schin 	int k,m,n,fd;
14184887Schin 	char *sp,*cp,*ep;
14194887Schin 	stakseek(offset+pp->len);
14204887Schin 	if(pp->len==1 && *stakptr(offset)=='/')
14214887Schin 		stakseek(offset);
14224887Schin 	stakputs("/.paths");
14234887Schin 	if((fd=open(stakptr(offset),O_RDONLY))>=0)
14244887Schin 	{
14254887Schin 		fstat(fd,&statb);
14264887Schin 		n = statb.st_size;
14274887Schin 		stakseek(offset+pp->len+n+2);
14284887Schin 		sp = stakptr(offset+pp->len);
14294887Schin 		*sp++ = '/';
14304887Schin 		n=read(fd,cp=sp,n);
14314887Schin 		sp[n] = 0;
14324887Schin 		close(fd);
14334887Schin 		for(ep=0; n--; cp++)
14344887Schin 		{
14354887Schin 			if(*cp=='=')
14364887Schin 			{
14374887Schin 				ep = cp+1;
14384887Schin 				continue;
14394887Schin 			}
14404887Schin 			else if(*cp!='\r' &&  *cp!='\n')
14414887Schin 				continue;
14424887Schin 			if(*sp=='#' || sp==cp)
14434887Schin 			{
14444887Schin 				sp = cp+1;
14454887Schin 				continue;
14464887Schin 			}
14474887Schin 			*cp = 0;
14484887Schin 			m = ep ? (ep-sp) : 0;
14494887Schin 			if(!m || m==6 && memcmp((void*)sp,(void*)"FPATH=",6)==0)
14504887Schin 			{
14514887Schin 				if(first)
14524887Schin 				{
14534887Schin 					char *ptr = stakptr(offset+pp->len+1);
14544887Schin 					if(ep)
14554887Schin 						strcpy(ptr,ep);
14564887Schin 					path_addcomp(first,old,stakptr(offset),PATH_FPATH|PATH_BFPATH);
14574887Schin 				}
14584887Schin 			}
14594887Schin 			else if(m==12 && memcmp((void*)sp,(void*)"BUILTIN_LIB=",12)==0)
14604887Schin 			{
14614887Schin 				if(!(pp->flags & PATH_BUILTIN_LIB))
14624887Schin 				{
14634887Schin 					pp->flags |= PATH_BUILTIN_LIB;
14644887Schin 					if (*ep == '.' && !*(ep + 1))
14654887Schin 						pp->flags |= PATH_STD_DIR;
14664887Schin 					else
14674887Schin 					{
14684887Schin 						k = strlen(ep)+1;
14694887Schin 						if (*ep != '/')
14704887Schin 							k +=  pp->len+1;
14714887Schin 						pp->blib = sp = malloc(k);
14724887Schin 						if (*ep != '/')
14734887Schin 						{
14744887Schin 							strcpy(pp->blib,pp->name);
14754887Schin 							sp += pp->len;
14764887Schin 							*sp++ = '/';
14774887Schin 						}
14784887Schin 						strcpy(sp,ep);
14794887Schin 					}
14804887Schin 				}
14814887Schin 			}
14824887Schin 			else if(m)
14834887Schin 			{
14844887Schin 				pp->lib = (char*)malloc(cp-sp+pp->len+2);
14854887Schin 				memcpy((void*)pp->lib,(void*)sp,m);
14864887Schin 				memcpy((void*)&pp->lib[m],stakptr(offset),pp->len);
14874887Schin 				pp->lib[k=m+pp->len] = '/';
14884887Schin 				strcpy((void*)&pp->lib[k+1],ep);
14894887Schin 				pathcanon(&pp->lib[m],0);
14904887Schin 				if(!first)
14914887Schin 				{
14924887Schin 					stakseek(0);
14934887Schin 					stakputs(pp->lib);
14944887Schin 					free((void*)pp->lib);
14954887Schin 					return(1);
14964887Schin 				}
14974887Schin 			}
14984887Schin 			sp = cp+1;
14994887Schin 			ep = 0;
15004887Schin 		}
15014887Schin 	}
15024887Schin 	return(0);
15034887Schin }
15044887Schin 
15054887Schin 
15064887Schin Pathcomp_t *path_addpath(Pathcomp_t *first, register const char *path,int type)
15074887Schin {
15084887Schin 	register const char *cp;
15094887Schin 	Pathcomp_t *old=0;
15104887Schin 	int offset = staktell();
15114887Schin 	char *savptr;
15124887Schin 
15134887Schin 	if(!path && type!=PATH_PATH)
15144887Schin 		return(first);
15154887Schin 	if(type!=PATH_FPATH)
15164887Schin 	{
15174887Schin 		old = first;
15184887Schin 		first = 0;
15194887Schin 	}
15204887Schin 	if(offset)
15214887Schin 		savptr = stakfreeze(0);
15224887Schin 	if(path) while(*(cp=path))
15234887Schin 	{
15244887Schin 		if(*cp==':')
15254887Schin 		{
15264887Schin 			if(type!=PATH_FPATH)
15274887Schin 				first = path_addcomp(first,old,".",type);
15284887Schin 			while(*++path == ':');
15294887Schin 		}
15304887Schin 		else
15314887Schin 		{
15324887Schin 			int c;
15334887Schin 			while(*path && *path!=':')
15344887Schin 				path++;
15354887Schin 			c = *path++;
15364887Schin 			first = path_addcomp(first,old,cp,type);
15374887Schin 			if(c==0)
15384887Schin 				break;
15394887Schin 			if(*path==0)
15404887Schin 				path--;
15414887Schin 		}
15424887Schin 	}
15434887Schin 	if(old)
15444887Schin 	{
15454887Schin 		if(!first && !path)
15464887Schin 		{
15474887Schin 			Pathcomp_t *pp = (Pathcomp_t*)old->shp->defpathlist;
15484887Schin 			if(!pp)
15494887Schin 				pp = defpath_init(old->shp);
15504887Schin 			first = path_dup(pp);
15514887Schin 		}
15524887Schin 		if(cp=(FPATHNOD)->nvalue.cp)
15534887Schin 			first = (void*)path_addpath((Pathcomp_t*)first,cp,PATH_FPATH);
15544887Schin 		path_delete(old);
15554887Schin 	}
15564887Schin 	if(offset)
15574887Schin 		stakset(savptr,offset);
15584887Schin 	else
15594887Schin 		stakseek(0);
15604887Schin 	return(first);
15614887Schin }
15624887Schin 
15634887Schin /*
15644887Schin  * duplicate the path give by <first> by incremented reference counts
15654887Schin  */
15664887Schin Pathcomp_t *path_dup(Pathcomp_t *first)
15674887Schin {
15684887Schin 	register Pathcomp_t *pp=first;
15694887Schin 	while(pp)
15704887Schin 	{
15714887Schin 		pp->refcount++;
15724887Schin 		pp = pp->next;
15734887Schin 	}
15744887Schin 	return(first);
15754887Schin }
15764887Schin 
15774887Schin /*
15784887Schin  * called whenever the directory is changed
15794887Schin  */
15804887Schin void path_newdir(Pathcomp_t *first)
15814887Schin {
15824887Schin 	register Pathcomp_t *pp=first, *next, *pq;
15834887Schin 	struct stat statb;
15844887Schin 	for(pp=first; pp; pp=pp->next)
15854887Schin 	{
15864887Schin 		pp->flags &= ~PATH_SKIP;
15874887Schin 		if(*pp->name=='/')
15884887Schin 			continue;
15894887Schin 		/* delete .paths component */
15904887Schin 		if((next=pp->next) && (next->flags&PATH_BFPATH))
15914887Schin 		{
15924887Schin 			pp->next = next->next;
15934887Schin 			if(--next->refcount<=0)
15944887Schin 				free((void*)next);
15954887Schin 		}
15964887Schin 		if(stat(pp->name,&statb)<0 || !S_ISDIR(statb.st_mode))
15974887Schin 		{
15984887Schin 			pp->dev = 0;
15994887Schin 			pp->ino = 0;
16004887Schin 			continue;
16014887Schin 		}
16024887Schin 		pp->dev = statb.st_dev;
16034887Schin 		pp->ino = statb.st_ino;
1604*8462SApril.Chin@Sun.COM 		pp->mtime = statb.st_mtime;
16054887Schin 		for(pq=first;pq!=pp;pq=pq->next)
16064887Schin 		{
16074887Schin 			if(pp->ino==pq->ino && pp->dev==pq->dev)
16084887Schin 				pp->flags |= PATH_SKIP;
16094887Schin 		}
16104887Schin 		for(pq=pp;pq=pq->next;)
16114887Schin 		{
16124887Schin 			if(pp->ino==pq->ino && pp->dev==pq->dev)
16134887Schin 				pq->flags |= PATH_SKIP;
16144887Schin 		}
16154887Schin 		if((pp->flags&(PATH_PATH|PATH_SKIP))==PATH_PATH)
16164887Schin 		{
16174887Schin 			/* try to insert .paths component */
16184887Schin 			int offset = staktell();
16194887Schin 			stakputs(pp->name);
16204887Schin 			stakseek(offset);
16214887Schin 			next = pp->next;
16224887Schin 			pp->next = 0;
16234887Schin 			path_chkpaths(first,(Pathcomp_t*)0,pp,offset);
16244887Schin 			if(pp->next)
16254887Schin 				pp = pp->next;
16264887Schin 			pp->next = next;
16274887Schin 		}
16284887Schin 	}
16294887Schin #if 0
16304887Schin 	path_dump(first);
16314887Schin #endif
16324887Schin }
16334887Schin 
16344887Schin Pathcomp_t *path_unsetfpath(Pathcomp_t *first)
16354887Schin {
16364887Schin 	register Pathcomp_t *pp=first, *old=0;
1637*8462SApril.Chin@Sun.COM 	Shell_t	*shp = &sh;
1638*8462SApril.Chin@Sun.COM 	if(shp->fpathdict)
1639*8462SApril.Chin@Sun.COM 	{
1640*8462SApril.Chin@Sun.COM 		struct Ufunction  *rp, *rpnext;
1641*8462SApril.Chin@Sun.COM 		for(rp=(struct Ufunction*)dtfirst(shp->fpathdict);rp;rp=rpnext)
1642*8462SApril.Chin@Sun.COM 		{
1643*8462SApril.Chin@Sun.COM 			rpnext = (struct Ufunction*)dtnext(shp->fpathdict,rp);
1644*8462SApril.Chin@Sun.COM 			if(rp->fdict)
1645*8462SApril.Chin@Sun.COM 				nv_delete(rp->np,rp->fdict,NV_NOFREE);
1646*8462SApril.Chin@Sun.COM 			rp->fdict = 0;
1647*8462SApril.Chin@Sun.COM 		}
1648*8462SApril.Chin@Sun.COM 	}
16494887Schin 	while(pp)
16504887Schin 	{
16514887Schin 		if((pp->flags&PATH_FPATH) && !(pp->flags&PATH_BFPATH))
16524887Schin 		{
16534887Schin 			if(pp->flags&PATH_PATH)
16544887Schin 				pp->flags &= ~PATH_FPATH;
16554887Schin 			else
16564887Schin 			{
16574887Schin 				Pathcomp_t *ppsave=pp;
16584887Schin 				if(old)
16594887Schin 					old->next = pp->next;
16604887Schin 				else
16614887Schin 					first = pp->next;
16624887Schin 				pp = pp->next;
16634887Schin 				if(--ppsave->refcount<=0)
16644887Schin 				{
16654887Schin 					if(ppsave->lib)
16664887Schin 						free((void*)ppsave->lib);
16674887Schin 					free((void*)ppsave);
16684887Schin 				}
16694887Schin 				continue;
16704887Schin 			}
16714887Schin 
16724887Schin 		}
16734887Schin 		old = pp;
16744887Schin 		pp = pp->next;
16754887Schin 	}
16764887Schin 	return(first);
16774887Schin }
16784887Schin 
16794887Schin Pathcomp_t *path_dirfind(Pathcomp_t *first,const char *name,int c)
16804887Schin {
16814887Schin 	register Pathcomp_t *pp=first;
16824887Schin 	while(pp)
16834887Schin 	{
16844887Schin 		if(memcmp(name,pp->name,pp->len)==0 && name[pp->len]==c)
16854887Schin 			return(pp);
16864887Schin 		pp = pp->next;
16874887Schin 	}
16884887Schin 	return(0);
16894887Schin }
16904887Schin 
16914887Schin /*
16924887Schin  * get discipline for tracked alias
16934887Schin  */
16944887Schin static char *talias_get(Namval_t *np, Namfun_t *nvp)
16954887Schin {
16964887Schin 	Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp;
16974887Schin 	char *ptr;
16984887Schin 	if(!pp)
16994887Schin 		return(NULL);
17004887Schin 	path_nextcomp(pp,nv_name(np),pp);
17014887Schin 	ptr = stakfreeze(0);
17024887Schin 	return(ptr+PATH_OFFSET);
17034887Schin }
17044887Schin 
17054887Schin static void talias_put(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
17064887Schin {
17074887Schin 	if(!val && np->nvalue.cp)
17084887Schin 	{
17094887Schin 		Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp;
17104887Schin 		if(--pp->refcount<=0)
17114887Schin 			free((void*)pp);
17124887Schin 	}
17134887Schin 	nv_putv(np,val,flags,fp);
17144887Schin }
17154887Schin 
17164887Schin static const Namdisc_t talias_disc   = { 0, talias_put, talias_get   };
17174887Schin static Namfun_t  talias_init = { &talias_disc, 1 };
17184887Schin 
17194887Schin /*
17204887Schin  *  set tracked alias node <np> to value <pp>
17214887Schin  */
17224887Schin void path_alias(register Namval_t *np,register Pathcomp_t *pp)
17234887Schin {
17244887Schin 	if(pp)
17254887Schin 	{
17264887Schin 		struct stat statb;
17274887Schin 		char *sp;
17284887Schin 		nv_offattr(np,NV_NOPRINT);
17294887Schin 		nv_stack(np,&talias_init);
17304887Schin 		np->nvalue.cp = (char*)pp;
17314887Schin 		pp->refcount++;
17324887Schin 		nv_setattr(np,NV_TAGGED|NV_NOFREE);
17334887Schin 		path_nextcomp(pp,nv_name(np),pp);
17344887Schin 		sp = stakptr(PATH_OFFSET);
17354887Schin 		if(sp && lstat(sp,&statb)>=0 && S_ISLNK(statb.st_mode))
17364887Schin 			nv_setsize(np,statb.st_size+1);
17374887Schin 		else
17384887Schin 			nv_setsize(np,0);
17394887Schin 	}
17404887Schin 	else
17414887Schin 		nv_unset(np);
17424887Schin }
17434887Schin 
1744