14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*10898Sroland.mainz@nrubsig.org *          Copyright (c) 1982-2009 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 #   else
434887Schin #	undef SHOPT_PFSH
444887Schin #   endif
458462SApril.Chin@Sun.COM #   if     _lib_vfork
468462SApril.Chin@Sun.COM #	include     <ast_vfork.h>
478462SApril.Chin@Sun.COM #   else
488462SApril.Chin@Sun.COM #	define vfork()      fork()
498462SApril.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);
60*10898Sroland.mainz@nrubsig.org static void		path_checkdup(register Pathcomp_t*);
614887Schin 
624887Schin static const char	*std_path;
634887Schin 
644887Schin static int onstdpath(const char *name)
654887Schin {
664887Schin 	register const char *cp = std_path, *sp;
674887Schin 	if(cp)
684887Schin 		while(*cp)
694887Schin 		{
704887Schin 			for(sp=name; *sp && (*cp == *sp); sp++,cp++);
714887Schin 			if(*sp==0 && (*cp==0 || *cp==':'))
724887Schin 				return(1);
734887Schin 			while(*cp && *cp++!=':');
744887Schin 		}
754887Schin 	return(0);
764887Schin }
774887Schin 
788462SApril.Chin@Sun.COM static pid_t path_pfexecve(const char *path, char *argv[],char *const envp[],int spawn)
794887Schin {
804887Schin #if SHOPT_PFSH
818462SApril.Chin@Sun.COM 	pid_t	pid;
824887Schin 	char  resolvedpath[PATH_MAX + 1];
838462SApril.Chin@Sun.COM 	if(spawn)
848462SApril.Chin@Sun.COM 	{
858462SApril.Chin@Sun.COM 		while((pid = vfork()) < 0)
868462SApril.Chin@Sun.COM 			_sh_fork(pid, 0, (int*)0);
878462SApril.Chin@Sun.COM 		if(pid)
888462SApril.Chin@Sun.COM 			return(pid);
898462SApril.Chin@Sun.COM 	}
904887Schin 	if(!sh_isoption(SH_PFSH))
914887Schin 		return(execve(path, argv, envp));
924887Schin 	/* Solaris implements realpath(3C) using the resolvepath(2) */
934887Schin 	/* system call so we can save us to call access(2) first */
944887Schin 	if (!realpath(path, resolvedpath))
954887Schin 		return -1;
964887Schin 
974887Schin 	/* we can exec the command directly instead of via pfexec(1) if */
984887Schin 	/* there is a matching entry without attributes in exec_attr(4) */
994887Schin 	if (sh.user && *sh.user)
1004887Schin 	{
1014887Schin 		execattr_t *pf;
1024887Schin 		if(pf=getexecuser(sh.user, KV_COMMAND, resolvedpath, GET_ONE))
1034887Schin 		{
1044887Schin 			if (!pf->attr || pf->attr->length == 0)
1054887Schin 			{
1064887Schin 				int r = execve(path, argv, envp);
1074887Schin 				free_execattr(pf);
1084887Schin 				return r;
1094887Schin 			}
1104887Schin 			free_execattr(pf);
1114887Schin 		}
1124887Schin 		else
1134887Schin 		{
1144887Schin 			errno = ENOENT;
1154887Schin 			return -1;
1164887Schin 		}
1174887Schin 	}
1184887Schin 	--argv;
1194887Schin 	argv[0] = argv[1];
1204887Schin 	argv[1] = resolvedpath;
1214887Schin 	return(execve("/usr/bin/pfexec", argv, envp));
1224887Schin #else
1234887Schin 	return(execve(path, argv, envp));
1244887Schin #endif
1254887Schin }
1264887Schin 
1274887Schin 
1288462SApril.Chin@Sun.COM static pid_t _spawnveg(const char *path, char* const argv[], char* const envp[], pid_t pgid)
1294887Schin {
1304887Schin 	int waitsafe = job.waitsafe;
1318462SApril.Chin@Sun.COM 	pid_t pid;
1324887Schin 	job_lock();
1338462SApril.Chin@Sun.COM 	while(1)
1348462SApril.Chin@Sun.COM 	{
1358462SApril.Chin@Sun.COM 		sh_stats(STAT_SPAWN);
1368462SApril.Chin@Sun.COM 		pid = spawnveg(path,argv,envp,pgid);
1378462SApril.Chin@Sun.COM 		if(pid>=0 || errno!=EAGAIN)
1388462SApril.Chin@Sun.COM 			break;
1398462SApril.Chin@Sun.COM 		_sh_fork(pid, 0, (int*)0);
1408462SApril.Chin@Sun.COM 	}
1414887Schin 	job.waitsafe = waitsafe;
1424887Schin 	job_unlock();
1434887Schin 	return(pid);
1444887Schin }
1454887Schin /*
1464887Schin  * used with command -x to run the command in multiple passes
1474887Schin  * spawn is non-zero when invoked via spawn
1484887Schin  * the exitval is set to the maximum for each execution
1494887Schin  */
1504887Schin static pid_t path_xargs(const char *path, char *argv[],char *const envp[], int spawn)
1514887Schin {
1524887Schin 	register char *cp, **av, **xv;
1534887Schin 	char **avlast= &argv[sh.xargmax], **saveargs=0;
1544887Schin 	char *const *ev;
1554887Schin 	long size, left;
1564887Schin 	int nlast=1,n,exitval=0;
1574887Schin 	pid_t pid;
1584887Schin 	if(sh.xargmin < 0)
1594887Schin 		return((pid_t)-1);
1604887Schin 	size = sh.lim.arg_max-1024;
1614887Schin 	for(ev=envp; cp= *ev; ev++)
1624887Schin 		size -= strlen(cp)-1;
1634887Schin 	for(av=argv; (cp= *av) && av< &argv[sh.xargmin]; av++)
1644887Schin 		size -= strlen(cp)-1;
1654887Schin 	for(av=avlast; cp= *av; av++,nlast++)
1664887Schin 		size -= strlen(cp)-1;
1674887Schin 	av =  &argv[sh.xargmin];
1684887Schin 	if(!spawn)
1694887Schin 		job_clear();
1704887Schin 	sh.exitval = 0;
1714887Schin 	while(av<avlast)
1724887Schin 	{
1734887Schin 		for(xv=av,left=size; left>0 && av<avlast;)
1744887Schin 			left -= strlen(*av++)+1;
1754887Schin 		/* leave at least two for last */
1764887Schin 		if(left<0 && (avlast-av)<2)
1774887Schin 			av--;
1784887Schin 		if(xv==&argv[sh.xargmin])
1794887Schin 		{
1804887Schin 			n = nlast*sizeof(char*);
1814887Schin 			saveargs = (char**)malloc(n);
1824887Schin 			memcpy((void*)saveargs, (void*)av, n);
1834887Schin 			memcpy((void*)av,(void*)avlast,n);
1844887Schin 		}
1854887Schin 		else
1864887Schin 		{
1874887Schin 			for(n=sh.xargmin; xv < av; xv++)
1884887Schin 				argv[n++] = *xv;
1894887Schin 			for(xv=avlast; cp=  *xv; xv++)
1904887Schin 				argv[n++] = cp;
1914887Schin 			argv[n] = 0;
1924887Schin 		}
1934887Schin 		if(saveargs || av<avlast || (exitval && !spawn))
1944887Schin 		{
1954887Schin 			if((pid=_spawnveg(path,argv,envp,0)) < 0)
1964887Schin 				return(-1);
1974887Schin 			job_post(pid,0);
1984887Schin 			job_wait(pid);
1994887Schin 			if(sh.exitval>exitval)
2004887Schin 				exitval = sh.exitval;
2014887Schin 			if(saveargs)
2024887Schin 			{
2034887Schin 				memcpy((void*)av,saveargs,n);
2044887Schin 				free((void*)saveargs);
2054887Schin 				saveargs = 0;
2064887Schin 			}
2074887Schin 		}
2084887Schin 		else if(spawn && !sh_isoption(SH_PFSH))
2094887Schin 		{
2104887Schin 			sh.xargexit = exitval;
2114887Schin 			return(_spawnveg(path,argv,envp,spawn>>1));
2124887Schin 		}
2134887Schin 		else
2148462SApril.Chin@Sun.COM 			return(path_pfexecve(path,argv,envp,spawn));
2154887Schin 	}
2164887Schin 	if(!spawn)
2174887Schin 		exit(exitval);
2184887Schin 	return((pid_t)-1);
2194887Schin }
2204887Schin 
2214887Schin /*
2224887Schin  * make sure PWD is set up correctly
2234887Schin  * Return the present working directory
2244887Schin  * Invokes getcwd() if flag==0 and if necessary
2254887Schin  * Sets the PWD variable to this value
2264887Schin  */
2274887Schin char *path_pwd(int flag)
2284887Schin {
2294887Schin 	register char *cp;
2304887Schin 	register char *dfault = (char*)e_dot;
2314887Schin 	register int count = 0;
2324887Schin 	Shell_t *shp = &sh;
2334887Schin 	if(shp->pwd)
2344887Schin 		return((char*)shp->pwd);
2354887Schin 	while(1)
2364887Schin 	{
2374887Schin 		/* try from lowest to highest */
2384887Schin 		switch(count++)
2394887Schin 		{
2404887Schin 			case 0:
2414887Schin 				cp = nv_getval(PWDNOD);
2424887Schin 				break;
2434887Schin 			case 1:
2444887Schin 				cp = nv_getval(HOME);
2454887Schin 				break;
2464887Schin 			case 2:
2474887Schin 				cp = "/";
2484887Schin 				break;
2494887Schin 			case 3:
2504887Schin 				cp = (char*)e_crondir;
2514887Schin 				if(flag) /* skip next case when non-zero flag */
2524887Schin 					++count;
2534887Schin 				break;
2544887Schin 			case 4:
2554887Schin 			{
2564887Schin 				if(cp=getcwd(NIL(char*),0))
2574887Schin 				{
2584887Schin 					nv_offattr(PWDNOD,NV_NOFREE);
2594887Schin 					nv_unset(PWDNOD);
2604887Schin 					PWDNOD->nvalue.cp = cp;
2614887Schin 					goto skip;
2624887Schin 				}
2634887Schin 				break;
2644887Schin 			}
2654887Schin 			case 5:
2664887Schin 				return(dfault);
2674887Schin 		}
2684887Schin 		if(cp && *cp=='/' && test_inode(cp,e_dot))
2694887Schin 			break;
2704887Schin 	}
2714887Schin 	if(count>1)
2724887Schin 	{
2734887Schin 		nv_offattr(PWDNOD,NV_NOFREE);
2744887Schin 		nv_putval(PWDNOD,cp,NV_RDONLY);
2754887Schin 	}
2764887Schin skip:
2774887Schin 	nv_onattr(PWDNOD,NV_NOFREE|NV_EXPORT);
2784887Schin 	shp->pwd = (char*)(PWDNOD->nvalue.cp);
2794887Schin 	return(cp);
2804887Schin }
2814887Schin 
2824887Schin static void free_bltin(Namval_t *np,void *data)
2834887Schin {
2844887Schin 	register Pathcomp_t *pp= (Pathcomp_t*)data;
2854887Schin 	if(pp->flags&PATH_STD_DIR)
2864887Schin 	{
2874887Schin 		int offset=staktell();;
2884887Schin 		if(strcmp(pp->name,"/bin")==0 || memcmp(pp->name,np->nvname,pp->len) || np->nvname[pp->len]!='/')
2894887Schin 			return;
2904887Schin 		stakputs("/bin");
2914887Schin 		stakputs(np->nvname+pp->len+1);
2924887Schin 		stakputc(0);
2934887Schin 		sh_addbuiltin(stakptr(offset),np->nvalue.bfp,NiL);
2944887Schin 		stakseek(offset);
2954887Schin 		return;
2964887Schin 	}
2974887Schin 	if((void*)np->nvenv==pp->bltin_lib)
2988462SApril.Chin@Sun.COM 		nv_delete(np,sh_bltin_tree(),NV_NOFREE);
2994887Schin }
3004887Schin 
3014887Schin /*
3024887Schin  * delete current Pathcomp_t structure
3034887Schin  */
3044887Schin void  path_delete(Pathcomp_t *first)
3054887Schin {
3064887Schin 	register Pathcomp_t *pp=first, *old=0, *ppnext;
3074887Schin 	while(pp)
3084887Schin 	{
3094887Schin 		ppnext = pp->next;
3104887Schin 		if(--pp->refcount<=0)
3114887Schin 		{
3124887Schin 			if(pp->lib)
3134887Schin 				free((void*)pp->lib);
3144887Schin 			if(pp->blib)
3154887Schin 				free((void*)pp->blib);
3164887Schin 			if(pp->bltin_lib || (pp->flags&PATH_STD_DIR))
3174887Schin 			{
3184887Schin 				nv_scan(sh_bltin_tree(),free_bltin,pp,0,0);
3198462SApril.Chin@Sun.COM #if SHOPT_DYNAMIC
3204887Schin 				if(pp->bltin_lib)
3214887Schin 					dlclose(pp->bltin_lib);
3228462SApril.Chin@Sun.COM #endif /* SHOPT_DYNAMIC */
3234887Schin 			}
3244887Schin 			free((void*)pp);
3254887Schin 			if(old)
3264887Schin 				old->next = ppnext;
3274887Schin 		}
3284887Schin 		else
3294887Schin 			old = pp;
3304887Schin 		pp = ppnext;
3314887Schin 	}
3324887Schin }
3334887Schin 
3344887Schin /*
3354887Schin  * returns library variable from .paths
3364887Schin  * The value might be returned on the stack overwriting path
3374887Schin  */
3384887Schin static char *path_lib(Pathcomp_t *pp, char *path)
3394887Schin {
3404887Schin 	register char *last = strrchr(path,'/');
3414887Schin 	register int r;
3424887Schin 	struct stat statb;
3434887Schin 	if(last)
3444887Schin 		*last = 0;
3454887Schin 	else
3464887Schin 		path = ".";
3474887Schin 	r = stat(path,&statb);
3484887Schin 	if(last)
3494887Schin 		*last = '/';
3504887Schin 	if(r>=0)
3514887Schin 	{
3524887Schin 		Pathcomp_t pcomp;
3534887Schin 		char save[8];
3544887Schin 		for( ;pp; pp=pp->next)
3554887Schin 		{
356*10898Sroland.mainz@nrubsig.org 			path_checkdup(pp);
3578462SApril.Chin@Sun.COM 			if(pp->ino==statb.st_ino && pp->dev==statb.st_dev && pp->mtime==statb.st_mtime)
3584887Schin 				return(pp->lib);
3594887Schin 		}
3604887Schin 		pcomp.len = 0;
3614887Schin 		if(last)
3624887Schin 			pcomp.len = last-path;
3634887Schin 		memcpy((void*)save, (void*)stakptr(PATH_OFFSET+pcomp.len),sizeof(save));
3644887Schin 		if(path_chkpaths((Pathcomp_t*)0,(Pathcomp_t*)0,&pcomp,PATH_OFFSET))
3654887Schin 			return(stakfreeze(1));
3664887Schin 		memcpy((void*)stakptr(PATH_OFFSET+pcomp.len),(void*)save,sizeof(save));
3674887Schin 	}
3684887Schin 	return(0);
3694887Schin }
3704887Schin 
3714887Schin #if 0
3724887Schin void path_dump(register Pathcomp_t *pp)
3734887Schin {
3744887Schin 	sfprintf(sfstderr,"dump\n");
3754887Schin 	while(pp)
3764887Schin 	{
3774887Schin 		sfprintf(sfstderr,"pp=%x dev=%d ino=%d len=%d flags=%o name=%.*s\n",
3784887Schin 			pp,pp->dev,pp->ino,pp->len,pp->flags,pp->len,pp->name);
3794887Schin 		pp = pp->next;
3804887Schin 	}
3814887Schin }
3824887Schin #endif
3834887Schin 
3844887Schin /*
385*10898Sroland.mainz@nrubsig.org  * check for duplicate directories on PATH
386*10898Sroland.mainz@nrubsig.org  */
387*10898Sroland.mainz@nrubsig.org static void path_checkdup(register Pathcomp_t *pp)
388*10898Sroland.mainz@nrubsig.org {
389*10898Sroland.mainz@nrubsig.org 	register char		*name = pp->name;
390*10898Sroland.mainz@nrubsig.org 	register Pathcomp_t	*oldpp,*first;
391*10898Sroland.mainz@nrubsig.org 	register int		flag=0;
392*10898Sroland.mainz@nrubsig.org 	struct stat 		statb;
393*10898Sroland.mainz@nrubsig.org 	if(stat(name,&statb)<0 || !S_ISDIR(statb.st_mode))
394*10898Sroland.mainz@nrubsig.org 	{
395*10898Sroland.mainz@nrubsig.org 		pp->flags |= PATH_SKIP;
396*10898Sroland.mainz@nrubsig.org 		pp->dev = *name=='/';
397*10898Sroland.mainz@nrubsig.org 		return;
398*10898Sroland.mainz@nrubsig.org 	}
399*10898Sroland.mainz@nrubsig.org 	pp->mtime = statb.st_mtime;
400*10898Sroland.mainz@nrubsig.org 	pp->ino = statb.st_ino;
401*10898Sroland.mainz@nrubsig.org 	pp->dev = statb.st_dev;
402*10898Sroland.mainz@nrubsig.org 	if(*name=='/' && onstdpath(name))
403*10898Sroland.mainz@nrubsig.org 		flag = PATH_STD_DIR;
404*10898Sroland.mainz@nrubsig.org 	first = (pp->flags&PATH_CDPATH)?pp->shp->cdpathlist:path_get("");
405*10898Sroland.mainz@nrubsig.org 	for(oldpp=first; oldpp && oldpp!=pp; oldpp=oldpp->next)
406*10898Sroland.mainz@nrubsig.org 	{
407*10898Sroland.mainz@nrubsig.org 		if(pp->ino==oldpp->ino && pp->dev==oldpp->dev && pp->mtime==oldpp->mtime)
408*10898Sroland.mainz@nrubsig.org 		{
409*10898Sroland.mainz@nrubsig.org 			flag |= PATH_SKIP;
410*10898Sroland.mainz@nrubsig.org 			break;
411*10898Sroland.mainz@nrubsig.org 		}
412*10898Sroland.mainz@nrubsig.org 	}
413*10898Sroland.mainz@nrubsig.org 	pp->flags |= flag;
414*10898Sroland.mainz@nrubsig.org 	if(((pp->flags&(PATH_PATH|PATH_SKIP))==PATH_PATH))
415*10898Sroland.mainz@nrubsig.org 	{
416*10898Sroland.mainz@nrubsig.org 		int offset = staktell();
417*10898Sroland.mainz@nrubsig.org 		stakputs(name);
418*10898Sroland.mainz@nrubsig.org 		path_chkpaths(first,0,pp,offset);
419*10898Sroland.mainz@nrubsig.org 		stakseek(offset);
420*10898Sroland.mainz@nrubsig.org 	}
421*10898Sroland.mainz@nrubsig.org }
422*10898Sroland.mainz@nrubsig.org 
423*10898Sroland.mainz@nrubsig.org /*
4244887Schin  * write the next path to search on the current stack
4254887Schin  * if last is given, all paths that come before <last> are skipped
4264887Schin  * the next pathcomp is returned.
4274887Schin  */
4284887Schin Pathcomp_t *path_nextcomp(register Pathcomp_t *pp, const char *name, Pathcomp_t *last)
4294887Schin {
430*10898Sroland.mainz@nrubsig.org 	Pathcomp_t	*ppnext;
4314887Schin 	stakseek(PATH_OFFSET);
4324887Schin 	if(*name=='/')
4334887Schin 		pp = 0;
4344887Schin 	else
4354887Schin 	{
436*10898Sroland.mainz@nrubsig.org 		for(;pp && pp!=last;pp=ppnext)
4374887Schin 		{
438*10898Sroland.mainz@nrubsig.org 			if(ppnext=pp->next)
439*10898Sroland.mainz@nrubsig.org 				ppnext->shp = pp->shp;
440*10898Sroland.mainz@nrubsig.org 			if(!pp->dev && !pp->ino)
441*10898Sroland.mainz@nrubsig.org 				path_checkdup(pp);
4424887Schin 			if(pp->flags&PATH_SKIP)
4434887Schin 				continue;
4444887Schin 			if(!last || *pp->name!='/')
4454887Schin 				break;
4464887Schin 		}
4474887Schin 		if(!pp)		/* this should not happen */
4484887Schin 			pp = last;
4494887Schin 	}
4504887Schin 	if(pp && (pp->name[0]!='.' || pp->name[1]))
4514887Schin 	{
4524887Schin 		if(*pp->name!='/')
4534887Schin 		{
4544887Schin 			stakputs(path_pwd(1));
4554887Schin 			if(*stakptr(staktell()-1)!='/')
4564887Schin 				stakputc('/');
4574887Schin 		}
4584887Schin 		stakwrite(pp->name,pp->len);
4594887Schin 		if(pp->name[pp->len-1]!='/')
4604887Schin 			stakputc('/');
4614887Schin 	}
4624887Schin 	stakputs(name);
4634887Schin 	stakputc(0);
4644887Schin 	while(pp && pp!=last && (pp=pp->next))
4654887Schin 	{
4664887Schin 		if(!(pp->flags&PATH_SKIP))
4674887Schin 			return(pp);
4684887Schin 	}
4694887Schin 	return((Pathcomp_t*)0);
4704887Schin }
4714887Schin 
4724887Schin static Pathcomp_t* defpath_init(Shell_t *shp)
4734887Schin {
4744887Schin 	Pathcomp_t *pp = (void*)path_addpath((Pathcomp_t*)0,(std_path),PATH_PATH);
4754887Schin 	if(shp->defpathlist = (void*)pp)
4764887Schin 		pp->shp = shp;
4774887Schin 	return(pp);
4784887Schin }
4794887Schin 
4804887Schin static void path_init(Shell_t *shp)
4814887Schin {
4824887Schin 	const char *val;
4834887Schin 	Pathcomp_t *pp;
4844887Schin 	if(!std_path && !(std_path=astconf("PATH",NIL(char*),NIL(char*))))
4854887Schin 		std_path = e_defpath;
4868462SApril.Chin@Sun.COM 	if(val=sh_scoped(shp,(PATHNOD))->nvalue.cp)
4874887Schin 	{
4884887Schin 		pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_PATH);
4894887Schin 		if(shp->pathlist = (void*)pp)
4904887Schin 			pp->shp = shp;
4914887Schin 	}
4924887Schin 	else
4934887Schin 	{
4944887Schin 		if(!(pp=(Pathcomp_t*)shp->defpathlist))
4954887Schin 			pp = defpath_init(shp);
4964887Schin 		shp->pathlist = (void*)path_dup(pp);
4974887Schin 	}
4988462SApril.Chin@Sun.COM 	if(val=sh_scoped(shp,(FPATHNOD))->nvalue.cp)
4994887Schin 	{
5004887Schin 		pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_FPATH);
5014887Schin 		if(shp->pathlist = (void*)pp)
5024887Schin 			pp->shp = shp;
5034887Schin 	}
5044887Schin }
5054887Schin 
5064887Schin /*
5074887Schin  * returns that pathlist to search
5084887Schin  */
5094887Schin Pathcomp_t *path_get(register const char *name)
5104887Schin {
5114887Schin 	register Shell_t *shp = &sh;
5124887Schin 	register Pathcomp_t *pp=0;
5134887Schin 	if(*name && strchr(name,'/'))
5144887Schin 		return(0);
5154887Schin 	if(!sh_isstate(SH_DEFPATH))
5164887Schin 	{
5174887Schin 		if(!shp->pathlist)
5184887Schin 			path_init(shp);
5194887Schin 		pp = (Pathcomp_t*)shp->pathlist;
5204887Schin 	}
5214887Schin 	if(!pp && (!(PATHNOD)->nvalue.cp) || sh_isstate(SH_DEFPATH))
5224887Schin 	{
5234887Schin 		if(!(pp=(Pathcomp_t*)shp->defpathlist))
5244887Schin 			pp = defpath_init(shp);
5254887Schin 	}
5264887Schin 	return(pp);
5274887Schin }
5284887Schin 
5294887Schin /*
5304887Schin  * open file corresponding to name using path give by <pp>
5314887Schin  */
5324887Schin static int	path_opentype(const char *name, register Pathcomp_t *pp, int fun)
5334887Schin {
5344887Schin 	register int fd= -1;
5354887Schin 	struct stat statb;
5364887Schin 	Pathcomp_t *oldpp;
5374887Schin 	Shell_t *shp;
5384887Schin 	if(pp)
5394887Schin 		shp = pp->shp;
5404887Schin 	else
5414887Schin 	{
5424887Schin 		shp = sh_getinterp();
5434887Schin 		if(!shp->pathlist)
5444887Schin 			path_init(shp);
5454887Schin 	}
5464887Schin 	if(!fun && strchr(name,'/'))
5474887Schin 	{
5484887Schin 		if(sh_isoption(SH_RESTRICTED))
5494887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_restricted,name);
5504887Schin 	}
5514887Schin 	do
5524887Schin 	{
5534887Schin 		pp = path_nextcomp(oldpp=pp,name,0);
5544887Schin 		while(oldpp && (oldpp->flags&PATH_SKIP))
5554887Schin 			oldpp = oldpp->next;
5564887Schin 		if(fun && (!oldpp || !(oldpp->flags&PATH_FPATH)))
5574887Schin 			continue;
5584887Schin 		if((fd = sh_open(path_relative(stakptr(PATH_OFFSET)),O_RDONLY,0)) >= 0)
5594887Schin 		{
5604887Schin 			if(fstat(fd,&statb)<0 || S_ISDIR(statb.st_mode))
5614887Schin 			{
5624887Schin 				errno = EISDIR;
5634887Schin 				sh_close(fd);
5644887Schin 				fd = -1;
5654887Schin 			}
5664887Schin 		}
5674887Schin 	}
5684887Schin 	while( fd<0 && pp);
5694887Schin 	if(fd>=0 && (fd = sh_iomovefd(fd)) > 0)
5704887Schin 	{
5714887Schin 		fcntl(fd,F_SETFD,FD_CLOEXEC);
572*10898Sroland.mainz@nrubsig.org 		if(!shp)
573*10898Sroland.mainz@nrubsig.org 		{
574*10898Sroland.mainz@nrubsig.org 			shp = sh_getinterp();
575*10898Sroland.mainz@nrubsig.org #if _UWIN
576*10898Sroland.mainz@nrubsig.org 			close(0x10001); /* this results in a /var/log/uwin message with "0x10001" for debugging */
577*10898Sroland.mainz@nrubsig.org #endif
578*10898Sroland.mainz@nrubsig.org 		}
5794887Schin 		shp->fdstatus[fd] |= IOCLEX;
5804887Schin 	}
5814887Schin 	return(fd);
5824887Schin }
5834887Schin 
5844887Schin /*
5854887Schin  * open file corresponding to name using path give by <pp>
5864887Schin  */
5874887Schin int	path_open(const char *name, register Pathcomp_t *pp)
5884887Schin {
5894887Schin 	return(path_opentype(name,pp,0));
5904887Schin }
5914887Schin 
5924887Schin /*
5934887Schin  * given a pathname return the base name
5944887Schin  */
5954887Schin 
5964887Schin char	*path_basename(register const char *name)
5974887Schin {
5984887Schin 	register const char *start = name;
5994887Schin 	while (*name)
6004887Schin 		if ((*name++ == '/') && *name)	/* don't trim trailing / */
6014887Schin 			start = name;
6024887Schin 	return ((char*)start);
6034887Schin }
6044887Schin 
6054887Schin char *path_fullname(const char *name)
6064887Schin {
6074887Schin 	int len=strlen(name)+1,dirlen=0;
6084887Schin 	char *path,*pwd;
6094887Schin 	if(*name!='/')
6104887Schin 	{
6114887Schin 		pwd = path_pwd(1);
6124887Schin 		dirlen = strlen(pwd)+1;
6134887Schin 	}
6144887Schin 	path = (char*)malloc(len+dirlen);
6154887Schin 	if(dirlen)
6164887Schin 	{
6174887Schin 		memcpy((void*)path,(void*)pwd,dirlen);
6184887Schin 		path[dirlen-1] = '/';
6194887Schin 	}
6204887Schin 	memcpy((void*)&path[dirlen],(void*)name,len);
6214887Schin 	pathcanon(path,0);
6224887Schin 	return(path);
6234887Schin }
6244887Schin 
6254887Schin /*
6264887Schin  * load functions from file <fno>
6274887Schin  */
6284887Schin static void funload(Shell_t *shp,int fno, const char *name)
6294887Schin {
6308462SApril.Chin@Sun.COM 	char		*pname,*oldname=shp->st.filename, buff[IOBSIZE+1];
6318462SApril.Chin@Sun.COM 	Namval_t	*np;
6328462SApril.Chin@Sun.COM 	struct Ufunction *rp;
6338462SApril.Chin@Sun.COM 	int		 savestates = sh_getstate(), oldload=shp->funload;
6348462SApril.Chin@Sun.COM 	pname = path_fullname(stakptr(PATH_OFFSET));
6358462SApril.Chin@Sun.COM 	if(shp->fpathdict && (rp = dtmatch(shp->fpathdict,(void*)pname)))
6368462SApril.Chin@Sun.COM 	{
637*10898Sroland.mainz@nrubsig.org 		Dt_t	*funtree = sh_subfuntree(1);
6388462SApril.Chin@Sun.COM 		do
6398462SApril.Chin@Sun.COM 		{
640*10898Sroland.mainz@nrubsig.org 			if((np = dtsearch(funtree,rp->np)) && is_afunction(np))
6418462SApril.Chin@Sun.COM 			{
6428462SApril.Chin@Sun.COM 				if(np->nvalue.rp)
6438462SApril.Chin@Sun.COM 					np->nvalue.rp->fdict = 0;
644*10898Sroland.mainz@nrubsig.org 				nv_delete(np,funtree,NV_NOFREE);
6458462SApril.Chin@Sun.COM 			}
646*10898Sroland.mainz@nrubsig.org 			dtinsert(funtree,rp->np);
647*10898Sroland.mainz@nrubsig.org 			rp->fdict = funtree;
6488462SApril.Chin@Sun.COM 		}
6498462SApril.Chin@Sun.COM 		while((rp=dtnext(shp->fpathdict,rp)) && strcmp(pname,rp->fname)==0);
6508462SApril.Chin@Sun.COM 		return;
6518462SApril.Chin@Sun.COM 	}
6524887Schin 	sh_onstate(SH_NOLOG);
6534887Schin 	sh_onstate(SH_NOALIAS);
6544887Schin 	shp->readscript = (char*)name;
6558462SApril.Chin@Sun.COM 	shp->st.filename = pname;
6568462SApril.Chin@Sun.COM 	shp->funload = 1;
6574887Schin 	error_info.line = 0;
658*10898Sroland.mainz@nrubsig.org 	sh_eval(sfnew(NIL(Sfio_t*),buff,IOBSIZE,fno,SF_READ),SH_FUNEVAL);
6594887Schin 	shp->readscript = 0;
6604887Schin 	free((void*)shp->st.filename);
6618462SApril.Chin@Sun.COM 	shp->funload = oldload;
6624887Schin 	shp->st.filename = oldname;
6634887Schin 	sh_setstate(savestates);
6644887Schin }
6654887Schin 
6664887Schin /*
6674887Schin  * do a path search and track alias if requested
6684887Schin  * if flag is 0, or if name not found, then try autoloading function
6698462SApril.Chin@Sun.COM  * if flag==2 or 3, returns 1 if name found on FPATH
6708462SApril.Chin@Sun.COM  * if flag==3 no tracked alias will be set
6714887Schin  * returns 1, if function was autoloaded.
6728462SApril.Chin@Sun.COM  * If oldpp is not NULL, it will contain a pointer to the path component
6738462SApril.Chin@Sun.COM  *    where it was found.
6744887Schin  */
6754887Schin 
6768462SApril.Chin@Sun.COM int	path_search(register const char *name,Pathcomp_t **oldpp, int flag)
6774887Schin {
6784887Schin 	register Namval_t *np;
6794887Schin 	register int fno;
6804887Schin 	Pathcomp_t *pp=0;
6814887Schin 	Shell_t *shp = &sh;
6824887Schin 	if(name && strchr(name,'/'))
6834887Schin 	{
6844887Schin 		stakseek(PATH_OFFSET);
6854887Schin 		stakputs(name);
6864887Schin 		if(canexecute(stakptr(PATH_OFFSET),0)<0)
6874887Schin 		{
6884887Schin 			*stakptr(PATH_OFFSET) = 0;
6894887Schin 			return(0);
6904887Schin 		}
6914887Schin 		if(*name=='/')
6924887Schin 			return(1);
6934887Schin 		stakseek(PATH_OFFSET);
6944887Schin 		stakputs(path_pwd(1));
6954887Schin 		stakputc('/');
6964887Schin 		stakputs(name);
6974887Schin 		stakputc(0);
6984887Schin 		return(0);
6994887Schin 	}
7004887Schin 	if(sh_isstate(SH_DEFPATH))
7014887Schin 	{
7024887Schin 		if(!shp->defpathlist)
7034887Schin 			defpath_init(shp);
7044887Schin 	}
7054887Schin 	else if(!shp->pathlist)
7064887Schin 		path_init(shp);
7074887Schin 	if(flag)
7084887Schin 	{
709*10898Sroland.mainz@nrubsig.org 		if((np=nv_search(name,shp->track_tree,0)) && !nv_isattr(np,NV_NOALIAS) && (pp=(Pathcomp_t*)np->nvalue.cp))
710*10898Sroland.mainz@nrubsig.org 		{
711*10898Sroland.mainz@nrubsig.org 			stakseek(PATH_OFFSET);
712*10898Sroland.mainz@nrubsig.org 			path_nextcomp(pp,name,pp);
713*10898Sroland.mainz@nrubsig.org 			stakputc(0);
714*10898Sroland.mainz@nrubsig.org 			return(0);
715*10898Sroland.mainz@nrubsig.org 		}
7168462SApril.Chin@Sun.COM 		pp = path_absolute(name,oldpp?*oldpp:NIL(Pathcomp_t*));
7178462SApril.Chin@Sun.COM 		if(oldpp)
7188462SApril.Chin@Sun.COM 			*oldpp = pp;
719*10898Sroland.mainz@nrubsig.org 		if(!pp && (np=nv_search(name,shp->fun_tree,HASH_NOSCOPE))&&np->nvalue.ip)
7204887Schin 			return(1);
7214887Schin 		if(!pp)
7224887Schin 			*stakptr(PATH_OFFSET) = 0;
7234887Schin 	}
7244887Schin 	if(flag==0 || !pp || (pp->flags&PATH_FPATH))
7254887Schin 	{
7264887Schin 		if(!pp)
7274887Schin 			pp=sh_isstate(SH_DEFPATH)?shp->defpathlist:shp->pathlist;
7284887Schin 		if(pp && strmatch(name,e_alphanum)  && (fno=path_opentype(name,pp,1))>=0)
7294887Schin 		{
7304887Schin 			if(flag==2)
7314887Schin 			{
7324887Schin 				sh_close(fno);
7334887Schin 				return(1);
7344887Schin 			}
7354887Schin 			funload(shp,fno,name);
7364887Schin 			return(1);
7374887Schin 		}
7384887Schin 		*stakptr(PATH_OFFSET) = 0;
7394887Schin 		return(0);
7404887Schin 	}
7418462SApril.Chin@Sun.COM 	else if(pp && !sh_isstate(SH_DEFPATH) && *name!='/' && flag<3)
7424887Schin 	{
7434887Schin 		if(np=nv_search(name,shp->track_tree,NV_ADD))
7444887Schin 			path_alias(np,pp);
7454887Schin 	}
7464887Schin 	return(0);
7474887Schin }
7484887Schin 
7494887Schin /*
7504887Schin  * do a path search and find the full pathname of file name
7514887Schin  */
7528462SApril.Chin@Sun.COM Pathcomp_t *path_absolute(register const char *name, Pathcomp_t *pp)
7534887Schin {
7544887Schin 	register int	f,isfun;
7554887Schin 	int		noexec=0;
7568462SApril.Chin@Sun.COM 	Pathcomp_t	*oldpp;
7574887Schin 	Shell_t		*shp = &sh;
7584887Schin 	Namval_t	*np;
7594887Schin 	shp->path_err = ENOENT;
7608462SApril.Chin@Sun.COM 	if(!pp && !(pp=path_get("")))
7614887Schin 		return(0);
7624887Schin 	shp->path_err = 0;
7634887Schin 	while(1)
7644887Schin 	{
7654887Schin 		sh_sigcheck();
7664887Schin 		isfun = (pp->flags&PATH_FPATH);
7674887Schin 		if(oldpp=pp)
768*10898Sroland.mainz@nrubsig.org 		{
7694887Schin 			pp = path_nextcomp(pp,name,0);
770*10898Sroland.mainz@nrubsig.org 			while(oldpp->flags&PATH_SKIP)
771*10898Sroland.mainz@nrubsig.org 			{
772*10898Sroland.mainz@nrubsig.org 				if(!(oldpp=oldpp->next))
773*10898Sroland.mainz@nrubsig.org 				{
774*10898Sroland.mainz@nrubsig.org 					shp->path_err = ENOENT;
775*10898Sroland.mainz@nrubsig.org 					return(0);
776*10898Sroland.mainz@nrubsig.org 				}
777*10898Sroland.mainz@nrubsig.org 			}
778*10898Sroland.mainz@nrubsig.org 		}
779*10898Sroland.mainz@nrubsig.org 
7804887Schin 		if(!isfun && !sh_isoption(SH_RESTRICTED))
7814887Schin 		{
7828462SApril.Chin@Sun.COM 			if(*stakptr(PATH_OFFSET)=='/' && nv_search(stakptr(PATH_OFFSET),sh.bltin_tree,0))
7834887Schin 				return(oldpp);
7848462SApril.Chin@Sun.COM #if SHOPT_DYNAMIC
7854887Schin 			if(oldpp->blib)
7864887Schin 			{
7874887Schin 				typedef int (*Fptr_t)(int, char*[], void*);
7884887Schin 				Fptr_t addr;
7894887Schin 				int n = staktell();
790*10898Sroland.mainz@nrubsig.org 				int libcmd;
7914887Schin 				char *cp;
7924887Schin 				stakputs("b_");
7934887Schin 				stakputs(name);
7944887Schin 				stakputc(0);
7954887Schin 				if(!oldpp->bltin_lib)
7964887Schin 				{
7974887Schin 					if(cp = strrchr(oldpp->blib,'/'))
7984887Schin 						cp++;
7994887Schin 					else
8004887Schin 						cp = oldpp->blib;
801*10898Sroland.mainz@nrubsig.org 					if((libcmd = !strcmp(cp,LIBCMD)) && (addr=(Fptr_t)dlllook((void*)0,stakptr(n))))
8024887Schin 					{
8038462SApril.Chin@Sun.COM 						if((np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL)) && nv_isattr(np,NV_BLTINOPT))
8048462SApril.Chin@Sun.COM 							return(oldpp);
8054887Schin 					}
8064887Schin #if (_AST_VERSION>=20040404)
8074887Schin 					if (oldpp->bltin_lib = dllplug(SH_ID, oldpp->blib, NiL, RTLD_LAZY, NiL, 0))
8084887Schin #else
8094887Schin 					if (oldpp->bltin_lib = dllfind(oldpp->blib, NiL, RTLD_LAZY, NiL, 0))
8104887Schin #endif
811*10898Sroland.mainz@nrubsig.org 					{
812*10898Sroland.mainz@nrubsig.org 						/*
813*10898Sroland.mainz@nrubsig.org 						 * this detects the 2007-05-11 builtin context change and also
814*10898Sroland.mainz@nrubsig.org 						 * the 2008-03-30 opt_info.num change that hit libcmd::b_head
815*10898Sroland.mainz@nrubsig.org 						 */
816*10898Sroland.mainz@nrubsig.org 
817*10898Sroland.mainz@nrubsig.org 						if (libcmd && !dlllook(oldpp->bltin_lib, "b_pids"))
818*10898Sroland.mainz@nrubsig.org 						{
819*10898Sroland.mainz@nrubsig.org 							dlclose(oldpp->bltin_lib);
820*10898Sroland.mainz@nrubsig.org 							oldpp->bltin_lib = 0;
821*10898Sroland.mainz@nrubsig.org 							oldpp->blib = 0;
822*10898Sroland.mainz@nrubsig.org 						}
823*10898Sroland.mainz@nrubsig.org 						else
824*10898Sroland.mainz@nrubsig.org 							sh_addlib(oldpp->bltin_lib);
825*10898Sroland.mainz@nrubsig.org 					}
8264887Schin 				}
8274887Schin 				if((addr=(Fptr_t)dlllook(oldpp->bltin_lib,stakptr(n))) &&
8284887Schin 				   (!(np = sh_addbuiltin(stakptr(PATH_OFFSET),NiL,NiL)) || np->nvalue.bfp!=addr) &&
8294887Schin 				   (np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL)))
8304887Schin 				{
8314887Schin 					np->nvenv = oldpp->bltin_lib;
8324887Schin 					return(oldpp);
8334887Schin 				}
8344887Schin 			}
8358462SApril.Chin@Sun.COM #endif /* SHOPT_DYNAMIC */
8364887Schin 		}
8378462SApril.Chin@Sun.COM 		sh_stats(STAT_PATHS);
8384887Schin 		f = canexecute(stakptr(PATH_OFFSET),isfun);
8394887Schin 		if(isfun && f>=0)
8404887Schin 		{
841*10898Sroland.mainz@nrubsig.org 			nv_onattr(nv_open(name,sh_subfuntree(1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE),NV_LTOU|NV_FUNCTION);
842*10898Sroland.mainz@nrubsig.org 			funload(shp,f,name);
8434887Schin 			close(f);
8444887Schin 			f = -1;
8454887Schin 			return(0);
8464887Schin 		}
8474887Schin 		else if(f>=0 && (oldpp->flags & PATH_STD_DIR))
8484887Schin 		{
8498462SApril.Chin@Sun.COM 			int n = staktell();
8504887Schin 			stakputs("/bin/");
8514887Schin 			stakputs(name);
8524887Schin 			stakputc(0);
8538462SApril.Chin@Sun.COM 			np = nv_search(stakptr(n),sh.bltin_tree,0);
8548462SApril.Chin@Sun.COM 			stakseek(n);
8554887Schin 			if(np)
8564887Schin 			{
8578462SApril.Chin@Sun.COM 				n = np->nvflag;
8588462SApril.Chin@Sun.COM 				np = sh_addbuiltin(stakptr(PATH_OFFSET),np->nvalue.bfp,nv_context(np));
8598462SApril.Chin@Sun.COM 				np->nvflag = n;
8604887Schin 			}
8614887Schin 		}
8624887Schin 		if(!pp || f>=0)
8634887Schin 			break;
8644887Schin 		if(errno!=ENOENT)
8654887Schin 			noexec = errno;
8664887Schin 	}
8674887Schin 	if(f<0)
8684887Schin 	{
8698462SApril.Chin@Sun.COM 		shp->path_err = (noexec?noexec:ENOENT);
8704887Schin 		return(0);
8714887Schin 	}
8724887Schin 	stakputc(0);
8734887Schin 	return(oldpp);
8744887Schin }
8754887Schin 
8764887Schin /*
8774887Schin  * returns 0 if path can execute
8784887Schin  * sets exec_err if file is found but can't be executable
8794887Schin  */
8804887Schin #undef S_IXALL
8814887Schin #ifdef S_IXUSR
8824887Schin #   define S_IXALL	(S_IXUSR|S_IXGRP|S_IXOTH)
8834887Schin #else
8844887Schin #   ifdef S_IEXEC
8854887Schin #	define S_IXALL	(S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6))
8864887Schin #   else
8874887Schin #	define S_IXALL	0111
8884887Schin #   endif /*S_EXEC */
8894887Schin #endif /* S_IXUSR */
8904887Schin 
8914887Schin static int canexecute(register char *path, int isfun)
8924887Schin {
8934887Schin 	struct stat statb;
8944887Schin 	register int fd=0;
8954887Schin 	path = path_relative(path);
8964887Schin 	if(isfun)
8974887Schin 	{
8984887Schin 		if((fd=open(path,O_RDONLY,0))<0 || fstat(fd,&statb)<0)
8994887Schin 			goto err;
9004887Schin 	}
9014887Schin 	else if(stat(path,&statb) < 0)
9024887Schin 	{
9034887Schin #if _WINIX
9044887Schin 		/* check for .exe or .bat suffix */
9054887Schin 		char *cp;
9064887Schin 		if(errno==ENOENT && (!(cp=strrchr(path,'.')) || strlen(cp)>4 || strchr(cp,'/')))
9074887Schin 		{
9084887Schin 			int offset = staktell()-1;
9094887Schin 			stakseek(offset);
9104887Schin 			stakputs(".bat");
9114887Schin 			path = stakptr(PATH_OFFSET);
9124887Schin 			if(stat(path,&statb) < 0)
9134887Schin 			{
9144887Schin 				if(errno!=ENOENT)
9154887Schin 					goto err;
9164887Schin 				memcpy(stakptr(offset),".sh",4);
9174887Schin 				if(stat(path,&statb) < 0)
9184887Schin 					goto err;
9194887Schin 			}
9204887Schin 		}
9214887Schin 		else
9224887Schin #endif /* _WINIX */
9234887Schin 		goto err;
9244887Schin 	}
9254887Schin 	errno = EPERM;
9264887Schin 	if(S_ISDIR(statb.st_mode))
9274887Schin 		errno = EISDIR;
9284887Schin 	else if((statb.st_mode&S_IXALL)==S_IXALL || sh_access(path,X_OK)>=0)
9294887Schin 		return(fd);
9304887Schin 	if(isfun && fd>=0)
9314887Schin 		sh_close(fd);
9324887Schin err:
9334887Schin 	return(-1);
9344887Schin }
9354887Schin 
9364887Schin /*
9374887Schin  * Return path relative to present working directory
9384887Schin  */
9394887Schin 
9404887Schin char *path_relative(register const char* file)
9414887Schin {
9424887Schin 	register const char *pwd;
9434887Schin 	register const char *fp = file;
9444887Schin 	/* can't relpath when sh.pwd not set */
9454887Schin 	if(!(pwd=sh.pwd))
9464887Schin 		return((char*)fp);
9474887Schin 	while(*pwd==*fp)
9484887Schin 	{
9494887Schin 		if(*pwd++==0)
9504887Schin 			return((char*)e_dot);
9514887Schin 		fp++;
9524887Schin 	}
9534887Schin 	if(*pwd==0 && *fp == '/')
9544887Schin 	{
9554887Schin 		while(*++fp=='/');
9564887Schin 		if(*fp)
9574887Schin 			return((char*)fp);
9584887Schin 		return((char*)e_dot);
9594887Schin 	}
9604887Schin 	return((char*)file);
9614887Schin }
9624887Schin 
9634887Schin void	path_exec(register const char *arg0,register char *argv[],struct argnod *local)
9644887Schin {
9654887Schin 	char **envp;
9664887Schin 	const char *opath;
9674887Schin 	Pathcomp_t *libpath, *pp=0;
9684887Schin 	Shell_t *shp = &sh;
9694887Schin 	int slash=0;
970*10898Sroland.mainz@nrubsig.org 	nv_setlist(local,NV_EXPORT|NV_IDENT|NV_ASSIGN,0);
9714887Schin 	envp = sh_envgen();
9724887Schin 	if(strchr(arg0,'/'))
9734887Schin 	{
9744887Schin 		slash=1;
9754887Schin 		/* name containing / not allowed for restricted shell */
9764887Schin 		if(sh_isoption(SH_RESTRICTED))
9774887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_restricted,arg0);
9784887Schin 	}
9794887Schin 	else
9804887Schin 		pp=path_get(arg0);
9814887Schin 	shp->path_err= ENOENT;
9824887Schin 	sfsync(NIL(Sfio_t*));
9834887Schin 	timerdel(NIL(void*));
9844887Schin 	/* find first path that has a library component */
985*10898Sroland.mainz@nrubsig.org 	while(pp && (pp->flags&PATH_SKIP))
986*10898Sroland.mainz@nrubsig.org 		pp = pp->next;
9874887Schin 	if(pp || slash) do
9884887Schin 	{
9894887Schin 		sh_sigcheck();
9904887Schin 		if(libpath=pp)
9914887Schin 		{
9924887Schin 			pp = path_nextcomp(pp,arg0,0);
9934887Schin 			opath = stakfreeze(1)+PATH_OFFSET;
9944887Schin 		}
9954887Schin 		else
9964887Schin 			opath = arg0;
9974887Schin 		path_spawn(opath,argv,envp,libpath,0);
9984887Schin 		while(pp && (pp->flags&PATH_FPATH))
9994887Schin 			pp = path_nextcomp(pp,arg0,0);
10004887Schin 	}
10014887Schin 	while(pp);
10024887Schin 	/* force an exit */
10034887Schin 	((struct checkpt*)shp->jmplist)->mode = SH_JMPEXIT;
10044887Schin 	if((errno=shp->path_err)==ENOENT)
10054887Schin 		errormsg(SH_DICT,ERROR_exit(ERROR_NOENT),e_found,arg0);
10064887Schin 	else
10074887Schin 		errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,arg0);
10084887Schin }
10094887Schin 
10104887Schin pid_t path_spawn(const char *opath,register char **argv, char **envp, Pathcomp_t *libpath, int spawn)
10114887Schin {
10124887Schin 	Shell_t *shp = sh_getinterp();
10134887Schin 	register char *path;
10144887Schin 	char **xp=0, *xval, *libenv = (libpath?libpath->lib:0);
10154887Schin 	Namval_t*	np;
10164887Schin 	char		*s, *v;
1017*10898Sroland.mainz@nrubsig.org 	int		r, n, pidsize;
10184887Schin 	pid_t		pid= -1;
10194887Schin 	/* leave room for inserting _= pathname in environment */
10204887Schin 	envp--;
10214887Schin #if _lib_readlink
10224887Schin 	/* save original pathname */
10234887Schin 	stakseek(PATH_OFFSET);
1024*10898Sroland.mainz@nrubsig.org 	pidsize = sfprintf(stkstd,"*%d*",spawn?getpid():getppid());
10254887Schin 	stakputs(opath);
1026*10898Sroland.mainz@nrubsig.org 	opath = stakfreeze(1)+PATH_OFFSET+pidsize;
10274887Schin 	np=nv_search(argv[0],shp->track_tree,0);
10284887Schin 	while(libpath && !libpath->lib)
10294887Schin 		libpath=libpath->next;
10304887Schin 	if(libpath && (!np || nv_size(np)>0))
10314887Schin 	{
10324887Schin 		/* check for symlink and use symlink name */
10334887Schin 		char buff[PATH_MAX+1];
10344887Schin 		char save[PATH_MAX+1];
10354887Schin 		stakseek(PATH_OFFSET);
10364887Schin 		stakputs(opath);
10374887Schin 		path = stakptr(PATH_OFFSET);
10384887Schin 		while((n=readlink(path,buff,PATH_MAX))>0)
10394887Schin 		{
10404887Schin 			buff[n] = 0;
10414887Schin 			n = PATH_OFFSET;
10424887Schin 			r = 0;
10434887Schin 			if((v=strrchr(path,'/')) && *buff!='/')
10444887Schin 			{
10454887Schin 				if(buff[0]=='.' && buff[1]=='.' && (r = strlen(path) + 1) <= PATH_MAX)
10464887Schin 					memcpy(save, path, r);
10474887Schin 				else
10484887Schin 					r = 0;
10494887Schin 				n += (v+1-path);
10504887Schin 			}
10514887Schin 			stakseek(n);
10524887Schin 			stakputs(buff);
10534887Schin 			stakputc(0);
10544887Schin 			path = stakptr(PATH_OFFSET);
10554887Schin 			if(v && buff[0]=='.' && buff[1]=='.')
10564887Schin 			{
10574887Schin 				pathcanon(path, 0);
10584887Schin 				if(r && access(path,X_OK))
10594887Schin 				{
10604887Schin 					memcpy(path, save, r);
10614887Schin 					break;
10624887Schin 				}
10634887Schin 			}
10644887Schin 			if(libenv = path_lib(libpath,path))
10654887Schin 				break;
10664887Schin 		}
10674887Schin 		stakseek(0);
10684887Schin 	}
10694887Schin #endif
10704887Schin 	if(libenv && (v = strchr(libenv,'=')))
10714887Schin 	{
10724887Schin 		n = v - libenv;
10734887Schin 		*v = 0;
10744887Schin 		np = nv_open(libenv,shp->var_tree,0);
10754887Schin 		*v = '=';
10764887Schin 		s = nv_getval(np);
10774887Schin 		stakputs(libenv);
10784887Schin 		if(s)
10794887Schin 		{
10804887Schin 			stakputc(':');
10814887Schin 			stakputs(s);
10824887Schin 		}
10834887Schin 		v = stakfreeze(1);
10844887Schin 		r = 1;
10858462SApril.Chin@Sun.COM 		xp = envp + 1;
10864887Schin 		while (s = *xp++)
10874887Schin 		{
10884887Schin 			if (strneq(s, v, n) && s[n] == '=')
10894887Schin 			{
10904887Schin 				xval = *--xp;
10914887Schin 				*xp = v;
10924887Schin 				r = 0;
10934887Schin 				break;
10944887Schin 			}
10954887Schin 		}
10964887Schin 		if (r)
10974887Schin 		{
10984887Schin 			*envp-- = v;
10994887Schin 			xp = 0;
11004887Schin 		}
11014887Schin 	}
11024887Schin 	if(!opath)
11034887Schin 		opath = stakptr(PATH_OFFSET);
1104*10898Sroland.mainz@nrubsig.org 	envp[0] =  (char*)opath-(PATH_OFFSET+pidsize);
11054887Schin 	envp[0][0] =  '_';
11064887Schin 	envp[0][1] =  '=';
11074887Schin 	sfsync(sfstderr);
11084887Schin 	sh_sigcheck();
11094887Schin 	path = path_relative(opath);
11104887Schin #ifdef SHELLMAGIC
11114887Schin 	if(*path!='/' && path!=opath)
11124887Schin 	{
11134887Schin 		/*
11144887Schin 		 * The following code because execv(foo,) and execv(./foo,)
11154887Schin 		 * may not yield the same results
11164887Schin 		 */
11174887Schin 		char *sp = (char*)malloc(strlen(path)+3);
11184887Schin 		sp[0] = '.';
11194887Schin 		sp[1] = '/';
11204887Schin 		strcpy(sp+2,path);
11214887Schin 		path = sp;
11224887Schin 	}
11234887Schin #endif /* SHELLMAGIC */
11244887Schin 	if(spawn && !sh_isoption(SH_PFSH))
11254887Schin 		pid = _spawnveg(opath, &argv[0],envp, spawn>>1);
11264887Schin 	else
11278462SApril.Chin@Sun.COM 		pid = path_pfexecve(opath, &argv[0] ,envp,spawn);
11284887Schin 	if(xp)
11294887Schin 		*xp = xval;
11304887Schin #ifdef SHELLMAGIC
11314887Schin 	if(*path=='.' && path!=opath)
11324887Schin 	{
11334887Schin 		free(path);
11344887Schin 		path = path_relative(opath);
11354887Schin 	}
11364887Schin #endif /* SHELLMAGIC */
11374887Schin 	if(pid>0)
11384887Schin 		return(pid);
11394887Schin retry:
11404887Schin 	switch(sh.path_err = errno)
11414887Schin 	{
11424887Schin #ifdef apollo
11434887Schin 	    /*
11444887Schin   	     * On apollo's execve will fail with eacces when
11454887Schin 	     * file has execute but not read permissions. So,
11464887Schin 	     * for now we will pretend that EACCES and ENOEXEC
11474887Schin  	     * mean the same thing.
11484887Schin  	     */
11494887Schin 	    case EACCES:
11504887Schin #endif /* apollo */
11514887Schin 	    case ENOEXEC:
11524887Schin #if SHOPT_SUID_EXEC
11534887Schin 	    case EPERM:
11544887Schin 		/* some systems return EPERM if setuid bit is on */
11554887Schin #endif
11564887Schin 		errno = ENOEXEC;
11574887Schin 		if(spawn)
11584887Schin 		{
11594887Schin #ifdef _lib_fork
11604887Schin 			if(sh.subshell)
11614887Schin 				return(-1);
11624887Schin 			do
11634887Schin 			{
11644887Schin 				if((pid=fork())>0)
11654887Schin 					return(pid);
11664887Schin 			}
11674887Schin 			while(_sh_fork(pid,0,(int*)0) < 0);
11688462SApril.Chin@Sun.COM 			((struct checkpt*)shp->jmplist)->mode = SH_JMPEXIT;
11694887Schin #else
11704887Schin 			return(-1);
11714887Schin #endif
11724887Schin 		}
11734887Schin 		exscript(shp,path,argv,envp);
11744887Schin #ifndef apollo
11754887Schin 	    case EACCES:
11764887Schin 	    {
11774887Schin 		struct stat statb;
11784887Schin 		if(stat(path,&statb)>=0)
11794887Schin 		{
11804887Schin 			if(S_ISDIR(statb.st_mode))
11814887Schin 				errno = EISDIR;
11824887Schin #ifdef S_ISSOCK
11834887Schin 			if(S_ISSOCK(statb.st_mode))
11844887Schin 				exscript(shp,path,argv,envp);
11854887Schin #endif
11864887Schin 		}
11874887Schin 	    }
11884887Schin 		/* FALL THROUGH */
11894887Schin #endif /* !apollo */
11904887Schin #ifdef ENAMETOOLONG
11914887Schin 	    case ENAMETOOLONG:
11924887Schin #endif /* ENAMETOOLONG */
11934887Schin #if !SHOPT_SUID_EXEC
11944887Schin 	    case EPERM:
11954887Schin #endif
11964887Schin 		shp->path_err = errno;
11974887Schin 		return(-1);
11984887Schin 	    case ENOTDIR:
11994887Schin 	    case ENOENT:
12004887Schin 	    case EINTR:
12014887Schin #ifdef EMLINK
12024887Schin 	    case EMLINK:
12034887Schin #endif /* EMLINK */
12044887Schin 		return(-1);
12054887Schin 	    case E2BIG:
12064887Schin 		if(sh.xargmin)
12074887Schin 		{
12084887Schin 			pid = path_xargs(opath, &argv[0] ,envp,spawn);
12094887Schin 			if(pid<0)
12104887Schin 				goto retry;
12114887Schin 			return(pid);
12124887Schin 		}
12134887Schin 	    default:
12144887Schin 		errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path);
12154887Schin 	}
12164887Schin 	return 0;
12174887Schin }
12184887Schin 
12194887Schin /*
12204887Schin  * File is executable but not machine code.
12214887Schin  * Assume file is a Shell script and execute it.
12224887Schin  */
12234887Schin 
12244887Schin static void exscript(Shell_t *shp,register char *path,register char *argv[],char **envp)
12254887Schin {
12264887Schin 	register Sfio_t *sp;
12274887Schin 	path = path_relative(path);
12284887Schin 	shp->comdiv=0;
12294887Schin 	shp->bckpid = 0;
12304887Schin 	shp->st.ioset=0;
12314887Schin 	/* clean up any cooperating processes */
12324887Schin 	if(shp->cpipe[0]>0)
12334887Schin 		sh_pclose(shp->cpipe);
12344887Schin 	if(shp->cpid && shp->outpipe)
12354887Schin 		sh_close(*shp->outpipe);
12364887Schin 	shp->cpid = 0;
12374887Schin 	if(sp=fcfile())
12384887Schin 		while(sfstack(sp,SF_POPSTACK));
12394887Schin 	job_clear();
12404887Schin 	if(shp->infd>0 && (shp->fdstatus[shp->infd]&IOCLEX))
12414887Schin 		sh_close(shp->infd);
12424887Schin 	sh_setstate(sh_state(SH_FORKED));
12434887Schin 	sfsync(sfstderr);
12444887Schin #if SHOPT_SUID_EXEC && !SHOPT_PFSH
12454887Schin 	/* check if file cannot open for read or script is setuid/setgid  */
12464887Schin 	{
12474887Schin 		static char name[] = "/tmp/euidXXXXXXXXXX";
12484887Schin 		register int n;
12494887Schin 		register uid_t euserid;
12504887Schin 		char *savet=0;
12514887Schin 		struct stat statb;
12524887Schin 		if((n=sh_open(path,O_RDONLY,0)) >= 0)
12534887Schin 		{
12544887Schin 			/* move <n> if n=0,1,2 */
12554887Schin 			n = sh_iomovefd(n);
12564887Schin 			if(fstat(n,&statb)>=0 && !(statb.st_mode&(S_ISUID|S_ISGID)))
12574887Schin 				goto openok;
12584887Schin 			sh_close(n);
12594887Schin 		}
12604887Schin 		if((euserid=geteuid()) != shp->userid)
12614887Schin 		{
12624887Schin 			strncpy(name+9,fmtbase((long)getpid(),10,0),sizeof(name)-10);
12634887Schin 			/* create a suid open file with owner equal effective uid */
12644887Schin 			if((n=open(name,O_CREAT|O_TRUNC|O_WRONLY,S_ISUID|S_IXUSR)) < 0)
12654887Schin 				goto fail;
12664887Schin 			unlink(name);
12674887Schin 			/* make sure that file has right owner */
12684887Schin 			if(fstat(n,&statb)<0 || statb.st_uid != euserid)
12694887Schin 				goto fail;
12704887Schin 			if(n!=10)
12714887Schin 			{
12724887Schin 				sh_close(10);
12734887Schin 				fcntl(n, F_DUPFD, 10);
12744887Schin 				sh_close(n);
12754887Schin 				n=10;
12764887Schin 			}
12774887Schin 		}
12784887Schin 		savet = *--argv;
12794887Schin 		*argv = path;
12808462SApril.Chin@Sun.COM 		path_pfexecve(e_suidexec,argv,envp,0);
12814887Schin 	fail:
12824887Schin 		/*
12834887Schin 		 *  The following code is just for compatibility
12844887Schin 		 */
12854887Schin 		if((n=open(path,O_RDONLY,0)) < 0)
12868462SApril.Chin@Sun.COM 			errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path);
12874887Schin 		if(savet)
12884887Schin 			*argv++ = savet;
12894887Schin 	openok:
12904887Schin 		shp->infd = n;
12914887Schin 	}
12924887Schin #else
12938462SApril.Chin@Sun.COM 	if((shp->infd = sh_open(path,O_RDONLY,0)) < 0)
12948462SApril.Chin@Sun.COM 		errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path);
12954887Schin #endif
12964887Schin 	shp->infd = sh_iomovefd(shp->infd);
12974887Schin #if SHOPT_ACCT
12984887Schin 	sh_accbegin(path) ;  /* reset accounting */
12994887Schin #endif	/* SHOPT_ACCT */
13004887Schin 	shp->arglist = sh_argcreate(argv);
13014887Schin 	shp->lastarg = strdup(path);
13024887Schin 	/* save name of calling command */
13034887Schin 	shp->readscript = error_info.id;
13044887Schin 	/* close history file if name has changed */
13054887Schin 	if(shp->hist_ptr && (path=nv_getval(HISTFILE)) && strcmp(path,shp->hist_ptr->histname))
13064887Schin 	{
13074887Schin 		hist_close(shp->hist_ptr);
13084887Schin 		(HISTCUR)->nvalue.lp = 0;
13094887Schin 	}
13104887Schin 	sh_offstate(SH_FORKED);
1311*10898Sroland.mainz@nrubsig.org 	if(shp->sigflag[SIGCHLD]==SH_SIGOFF)
1312*10898Sroland.mainz@nrubsig.org 		shp->sigflag[SIGCHLD] = SH_SIGFAULT;
13134887Schin 	siglongjmp(*shp->jmplist,SH_JMPSCRIPT);
13144887Schin }
13154887Schin 
13164887Schin #if SHOPT_ACCT
13174887Schin #   include <sys/acct.h>
13184887Schin #   include "FEATURE/time"
13194887Schin 
13204887Schin     static struct acct sabuf;
13214887Schin     static struct tms buffer;
13224887Schin     static clock_t	before;
13234887Schin     static char *SHACCT; /* set to value of SHACCT environment variable */
13244887Schin     static shaccton;	/* non-zero causes accounting record to be written */
13254887Schin     static int compress(time_t);
13264887Schin     /*
13274887Schin      *	initialize accounting, i.e., see if SHACCT variable set
13284887Schin      */
13294887Schin     void sh_accinit(void)
13304887Schin     {
13314887Schin 	SHACCT = getenv("SHACCT");
13324887Schin     }
13334887Schin     /*
13348462SApril.Chin@Sun.COM     * suspend accounting until turned on by sh_accbegin()
13354887Schin     */
13364887Schin     void sh_accsusp(void)
13374887Schin     {
13384887Schin 	shaccton=0;
13394887Schin #ifdef AEXPAND
13404887Schin 	sabuf.ac_flag |= AEXPND;
13414887Schin #endif /* AEXPAND */
13424887Schin     }
13434887Schin 
13444887Schin     /*
13454887Schin      * begin an accounting record by recording start time
13464887Schin      */
13474887Schin     void sh_accbegin(const char *cmdname)
13484887Schin     {
13494887Schin 	if(SHACCT)
13504887Schin 	{
13514887Schin 		sabuf.ac_btime = time(NIL(time_t *));
13524887Schin 		before = times(&buffer);
13534887Schin 		sabuf.ac_uid = getuid();
13544887Schin 		sabuf.ac_gid = getgid();
13554887Schin 		strncpy(sabuf.ac_comm, (char*)path_basename(cmdname),
13564887Schin 			sizeof(sabuf.ac_comm));
13574887Schin 		shaccton = 1;
13584887Schin 	}
13594887Schin     }
13604887Schin     /*
13614887Schin      * terminate an accounting record and append to accounting file
13624887Schin      */
13634887Schin     void	sh_accend(void)
13644887Schin     {
13654887Schin 	int	fd;
13664887Schin 	clock_t	after;
13674887Schin 
13684887Schin 	if(shaccton)
13694887Schin 	{
13704887Schin 		after = times(&buffer);
13714887Schin 		sabuf.ac_utime = compress(buffer.tms_utime + buffer.tms_cutime);
13724887Schin 		sabuf.ac_stime = compress(buffer.tms_stime + buffer.tms_cstime);
13734887Schin 		sabuf.ac_etime = compress( (time_t)(after-before));
13744887Schin 		fd = open( SHACCT , O_WRONLY | O_APPEND | O_CREAT,RW_ALL);
13754887Schin 		write(fd, (const char*)&sabuf, sizeof( sabuf ));
13764887Schin 		close( fd);
13774887Schin 	}
13784887Schin     }
13794887Schin 
13804887Schin     /*
13814887Schin      * Produce a pseudo-floating point representation
13824887Schin      * with 3 bits base-8 exponent, 13 bits fraction.
13834887Schin      */
13844887Schin     static int compress(register time_t t)
13854887Schin     {
13864887Schin 	register int exp = 0, rund = 0;
13874887Schin 
13884887Schin 	while (t >= 8192)
13894887Schin 	{
13904887Schin 		exp++;
13914887Schin 		rund = t&04;
13924887Schin 		t >>= 3;
13934887Schin 	}
13944887Schin 	if (rund)
13954887Schin 	{
13964887Schin 		t++;
13974887Schin 		if (t >= 8192)
13984887Schin 		{
13994887Schin 			t >>= 3;
14004887Schin 			exp++;
14014887Schin 		}
14024887Schin 	}
14034887Schin 	return((exp<<13) + t);
14044887Schin     }
14054887Schin #endif	/* SHOPT_ACCT */
14064887Schin 
14074887Schin 
14084887Schin 
14094887Schin /*
14104887Schin  * add a pathcomponent to the path search list and eliminate duplicates
14114887Schin  * and non-existing absolute paths.
14124887Schin  */
14134887Schin static Pathcomp_t *path_addcomp(Pathcomp_t *first, Pathcomp_t *old,const char *name, int flag)
14144887Schin {
14154887Schin 	register Pathcomp_t *pp, *oldpp;
14164887Schin 	int len, offset=staktell();
14174887Schin 	if(!(flag&PATH_BFPATH))
14184887Schin 	{
14194887Schin 		register const char *cp = name;
14204887Schin 		while(*cp && *cp!=':')
14214887Schin 			stakputc(*cp++);
14224887Schin 		len = staktell()-offset;
14234887Schin 		stakputc(0);
14244887Schin 		stakseek(offset);
14254887Schin 		name = (const char*)stakptr(offset);
14264887Schin 	}
14274887Schin 	else
14284887Schin 		len = strlen(name);
14294887Schin 	for(pp=first; pp; pp=pp->next)
14304887Schin 	{
14314887Schin 		if(memcmp(name,pp->name,len)==0 && (pp->name[len]==':' || pp->name[len]==0))
14324887Schin 		{
14334887Schin 			pp->flags |= flag;
14344887Schin 			return(first);
14354887Schin 		}
14364887Schin 	}
1437*10898Sroland.mainz@nrubsig.org 	for(pp=first, oldpp=0; pp; oldpp=pp, pp=pp->next);
14384887Schin 	pp = newof((Pathcomp_t*)0,Pathcomp_t,1,len+1);
14394887Schin 	pp->refcount = 1;
14404887Schin 	memcpy((char*)(pp+1),name,len+1);
14414887Schin 	pp->name = (char*)(pp+1);
14424887Schin 	pp->len = len;
14434887Schin 	if(oldpp)
14444887Schin 		oldpp->next = pp;
14454887Schin 	else
14464887Schin 		first = pp;
14474887Schin 	pp->flags = flag;
1448*10898Sroland.mainz@nrubsig.org 	if(strcmp(name,SH_CMDLIB_DIR)==0)
14494887Schin 	{
1450*10898Sroland.mainz@nrubsig.org 		pp->dev = 1;
14514887Schin 		pp->flags |= PATH_BUILTIN_LIB;
14524887Schin 		pp->blib = malloc(4);
14534887Schin 		strcpy(pp->blib,LIBCMD);
14544887Schin 		return(first);
14554887Schin 	}
1456*10898Sroland.mainz@nrubsig.org 	if(old && ((flag&(PATH_PATH|PATH_SKIP))==PATH_PATH))
14574887Schin 		path_chkpaths(first,old,pp,offset);
14584887Schin 	return(first);
14594887Schin }
14604887Schin 
14614887Schin /*
14624887Schin  * This function checks for the .paths file in directory in <pp>
14634887Schin  * it assumes that the directory is on the stack at <offset>
14644887Schin  */
14654887Schin static int path_chkpaths(Pathcomp_t *first, Pathcomp_t* old,Pathcomp_t *pp, int offset)
14664887Schin {
14674887Schin 	struct stat statb;
14684887Schin 	int k,m,n,fd;
14694887Schin 	char *sp,*cp,*ep;
14704887Schin 	stakseek(offset+pp->len);
14714887Schin 	if(pp->len==1 && *stakptr(offset)=='/')
14724887Schin 		stakseek(offset);
14734887Schin 	stakputs("/.paths");
14744887Schin 	if((fd=open(stakptr(offset),O_RDONLY))>=0)
14754887Schin 	{
14764887Schin 		fstat(fd,&statb);
14774887Schin 		n = statb.st_size;
14784887Schin 		stakseek(offset+pp->len+n+2);
14794887Schin 		sp = stakptr(offset+pp->len);
14804887Schin 		*sp++ = '/';
14814887Schin 		n=read(fd,cp=sp,n);
14824887Schin 		sp[n] = 0;
14834887Schin 		close(fd);
14844887Schin 		for(ep=0; n--; cp++)
14854887Schin 		{
14864887Schin 			if(*cp=='=')
14874887Schin 			{
14884887Schin 				ep = cp+1;
14894887Schin 				continue;
14904887Schin 			}
14914887Schin 			else if(*cp!='\r' &&  *cp!='\n')
14924887Schin 				continue;
14934887Schin 			if(*sp=='#' || sp==cp)
14944887Schin 			{
14954887Schin 				sp = cp+1;
14964887Schin 				continue;
14974887Schin 			}
14984887Schin 			*cp = 0;
14994887Schin 			m = ep ? (ep-sp) : 0;
15004887Schin 			if(!m || m==6 && memcmp((void*)sp,(void*)"FPATH=",6)==0)
15014887Schin 			{
15024887Schin 				if(first)
15034887Schin 				{
15044887Schin 					char *ptr = stakptr(offset+pp->len+1);
15054887Schin 					if(ep)
15064887Schin 						strcpy(ptr,ep);
15074887Schin 					path_addcomp(first,old,stakptr(offset),PATH_FPATH|PATH_BFPATH);
15084887Schin 				}
15094887Schin 			}
15104887Schin 			else if(m==12 && memcmp((void*)sp,(void*)"BUILTIN_LIB=",12)==0)
15114887Schin 			{
15124887Schin 				if(!(pp->flags & PATH_BUILTIN_LIB))
15134887Schin 				{
15144887Schin 					pp->flags |= PATH_BUILTIN_LIB;
15154887Schin 					if (*ep == '.' && !*(ep + 1))
15164887Schin 						pp->flags |= PATH_STD_DIR;
15174887Schin 					else
15184887Schin 					{
15194887Schin 						k = strlen(ep)+1;
15204887Schin 						if (*ep != '/')
15214887Schin 							k +=  pp->len+1;
15224887Schin 						pp->blib = sp = malloc(k);
15234887Schin 						if (*ep != '/')
15244887Schin 						{
15254887Schin 							strcpy(pp->blib,pp->name);
15264887Schin 							sp += pp->len;
15274887Schin 							*sp++ = '/';
15284887Schin 						}
15294887Schin 						strcpy(sp,ep);
15304887Schin 					}
15314887Schin 				}
15324887Schin 			}
15334887Schin 			else if(m)
15344887Schin 			{
15354887Schin 				pp->lib = (char*)malloc(cp-sp+pp->len+2);
15364887Schin 				memcpy((void*)pp->lib,(void*)sp,m);
15374887Schin 				memcpy((void*)&pp->lib[m],stakptr(offset),pp->len);
15384887Schin 				pp->lib[k=m+pp->len] = '/';
15394887Schin 				strcpy((void*)&pp->lib[k+1],ep);
15404887Schin 				pathcanon(&pp->lib[m],0);
15414887Schin 				if(!first)
15424887Schin 				{
15434887Schin 					stakseek(0);
15444887Schin 					stakputs(pp->lib);
15454887Schin 					free((void*)pp->lib);
15464887Schin 					return(1);
15474887Schin 				}
15484887Schin 			}
15494887Schin 			sp = cp+1;
15504887Schin 			ep = 0;
15514887Schin 		}
15524887Schin 	}
15534887Schin 	return(0);
15544887Schin }
15554887Schin 
15564887Schin 
15574887Schin Pathcomp_t *path_addpath(Pathcomp_t *first, register const char *path,int type)
15584887Schin {
15594887Schin 	register const char *cp;
15604887Schin 	Pathcomp_t *old=0;
15614887Schin 	int offset = staktell();
15624887Schin 	char *savptr;
15634887Schin 
15644887Schin 	if(!path && type!=PATH_PATH)
15654887Schin 		return(first);
15664887Schin 	if(type!=PATH_FPATH)
15674887Schin 	{
15684887Schin 		old = first;
15694887Schin 		first = 0;
15704887Schin 	}
15714887Schin 	if(offset)
15724887Schin 		savptr = stakfreeze(0);
15734887Schin 	if(path) while(*(cp=path))
15744887Schin 	{
15754887Schin 		if(*cp==':')
15764887Schin 		{
15774887Schin 			if(type!=PATH_FPATH)
15784887Schin 				first = path_addcomp(first,old,".",type);
15794887Schin 			while(*++path == ':');
15804887Schin 		}
15814887Schin 		else
15824887Schin 		{
15834887Schin 			int c;
15844887Schin 			while(*path && *path!=':')
15854887Schin 				path++;
15864887Schin 			c = *path++;
15874887Schin 			first = path_addcomp(first,old,cp,type);
15884887Schin 			if(c==0)
15894887Schin 				break;
15904887Schin 			if(*path==0)
15914887Schin 				path--;
15924887Schin 		}
15934887Schin 	}
15944887Schin 	if(old)
15954887Schin 	{
15964887Schin 		if(!first && !path)
15974887Schin 		{
15984887Schin 			Pathcomp_t *pp = (Pathcomp_t*)old->shp->defpathlist;
15994887Schin 			if(!pp)
16004887Schin 				pp = defpath_init(old->shp);
16014887Schin 			first = path_dup(pp);
16024887Schin 		}
16034887Schin 		if(cp=(FPATHNOD)->nvalue.cp)
16044887Schin 			first = (void*)path_addpath((Pathcomp_t*)first,cp,PATH_FPATH);
16054887Schin 		path_delete(old);
16064887Schin 	}
16074887Schin 	if(offset)
16084887Schin 		stakset(savptr,offset);
16094887Schin 	else
16104887Schin 		stakseek(0);
16114887Schin 	return(first);
16124887Schin }
16134887Schin 
16144887Schin /*
16154887Schin  * duplicate the path give by <first> by incremented reference counts
16164887Schin  */
16174887Schin Pathcomp_t *path_dup(Pathcomp_t *first)
16184887Schin {
16194887Schin 	register Pathcomp_t *pp=first;
16204887Schin 	while(pp)
16214887Schin 	{
16224887Schin 		pp->refcount++;
16234887Schin 		pp = pp->next;
16244887Schin 	}
16254887Schin 	return(first);
16264887Schin }
16274887Schin 
16284887Schin /*
16294887Schin  * called whenever the directory is changed
16304887Schin  */
16314887Schin void path_newdir(Pathcomp_t *first)
16324887Schin {
16334887Schin 	register Pathcomp_t *pp=first, *next, *pq;
16344887Schin 	struct stat statb;
16354887Schin 	for(pp=first; pp; pp=pp->next)
16364887Schin 	{
16374887Schin 		pp->flags &= ~PATH_SKIP;
16384887Schin 		if(*pp->name=='/')
16394887Schin 			continue;
16404887Schin 		/* delete .paths component */
16414887Schin 		if((next=pp->next) && (next->flags&PATH_BFPATH))
16424887Schin 		{
16434887Schin 			pp->next = next->next;
16444887Schin 			if(--next->refcount<=0)
16454887Schin 				free((void*)next);
16464887Schin 		}
16474887Schin 		if(stat(pp->name,&statb)<0 || !S_ISDIR(statb.st_mode))
16484887Schin 		{
16494887Schin 			pp->dev = 0;
16504887Schin 			pp->ino = 0;
16514887Schin 			continue;
16524887Schin 		}
16534887Schin 		pp->dev = statb.st_dev;
16544887Schin 		pp->ino = statb.st_ino;
16558462SApril.Chin@Sun.COM 		pp->mtime = statb.st_mtime;
16564887Schin 		for(pq=first;pq!=pp;pq=pq->next)
16574887Schin 		{
16584887Schin 			if(pp->ino==pq->ino && pp->dev==pq->dev)
16594887Schin 				pp->flags |= PATH_SKIP;
16604887Schin 		}
16614887Schin 		for(pq=pp;pq=pq->next;)
16624887Schin 		{
16634887Schin 			if(pp->ino==pq->ino && pp->dev==pq->dev)
16644887Schin 				pq->flags |= PATH_SKIP;
16654887Schin 		}
16664887Schin 		if((pp->flags&(PATH_PATH|PATH_SKIP))==PATH_PATH)
16674887Schin 		{
16684887Schin 			/* try to insert .paths component */
16694887Schin 			int offset = staktell();
16704887Schin 			stakputs(pp->name);
16714887Schin 			stakseek(offset);
16724887Schin 			next = pp->next;
16734887Schin 			pp->next = 0;
16744887Schin 			path_chkpaths(first,(Pathcomp_t*)0,pp,offset);
16754887Schin 			if(pp->next)
16764887Schin 				pp = pp->next;
16774887Schin 			pp->next = next;
16784887Schin 		}
16794887Schin 	}
16804887Schin #if 0
16814887Schin 	path_dump(first);
16824887Schin #endif
16834887Schin }
16844887Schin 
16854887Schin Pathcomp_t *path_unsetfpath(Pathcomp_t *first)
16864887Schin {
16874887Schin 	register Pathcomp_t *pp=first, *old=0;
16888462SApril.Chin@Sun.COM 	Shell_t	*shp = &sh;
16898462SApril.Chin@Sun.COM 	if(shp->fpathdict)
16908462SApril.Chin@Sun.COM 	{
16918462SApril.Chin@Sun.COM 		struct Ufunction  *rp, *rpnext;
16928462SApril.Chin@Sun.COM 		for(rp=(struct Ufunction*)dtfirst(shp->fpathdict);rp;rp=rpnext)
16938462SApril.Chin@Sun.COM 		{
16948462SApril.Chin@Sun.COM 			rpnext = (struct Ufunction*)dtnext(shp->fpathdict,rp);
16958462SApril.Chin@Sun.COM 			if(rp->fdict)
16968462SApril.Chin@Sun.COM 				nv_delete(rp->np,rp->fdict,NV_NOFREE);
16978462SApril.Chin@Sun.COM 			rp->fdict = 0;
16988462SApril.Chin@Sun.COM 		}
16998462SApril.Chin@Sun.COM 	}
17004887Schin 	while(pp)
17014887Schin 	{
17024887Schin 		if((pp->flags&PATH_FPATH) && !(pp->flags&PATH_BFPATH))
17034887Schin 		{
17044887Schin 			if(pp->flags&PATH_PATH)
17054887Schin 				pp->flags &= ~PATH_FPATH;
17064887Schin 			else
17074887Schin 			{
17084887Schin 				Pathcomp_t *ppsave=pp;
17094887Schin 				if(old)
17104887Schin 					old->next = pp->next;
17114887Schin 				else
17124887Schin 					first = pp->next;
17134887Schin 				pp = pp->next;
17144887Schin 				if(--ppsave->refcount<=0)
17154887Schin 				{
17164887Schin 					if(ppsave->lib)
17174887Schin 						free((void*)ppsave->lib);
17184887Schin 					free((void*)ppsave);
17194887Schin 				}
17204887Schin 				continue;
17214887Schin 			}
17224887Schin 
17234887Schin 		}
17244887Schin 		old = pp;
17254887Schin 		pp = pp->next;
17264887Schin 	}
17274887Schin 	return(first);
17284887Schin }
17294887Schin 
17304887Schin Pathcomp_t *path_dirfind(Pathcomp_t *first,const char *name,int c)
17314887Schin {
17324887Schin 	register Pathcomp_t *pp=first;
17334887Schin 	while(pp)
17344887Schin 	{
17354887Schin 		if(memcmp(name,pp->name,pp->len)==0 && name[pp->len]==c)
17364887Schin 			return(pp);
17374887Schin 		pp = pp->next;
17384887Schin 	}
17394887Schin 	return(0);
17404887Schin }
17414887Schin 
17424887Schin /*
17434887Schin  * get discipline for tracked alias
17444887Schin  */
17454887Schin static char *talias_get(Namval_t *np, Namfun_t *nvp)
17464887Schin {
17474887Schin 	Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp;
17484887Schin 	char *ptr;
17494887Schin 	if(!pp)
17504887Schin 		return(NULL);
17514887Schin 	path_nextcomp(pp,nv_name(np),pp);
17524887Schin 	ptr = stakfreeze(0);
17534887Schin 	return(ptr+PATH_OFFSET);
17544887Schin }
17554887Schin 
17564887Schin static void talias_put(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
17574887Schin {
17584887Schin 	if(!val && np->nvalue.cp)
17594887Schin 	{
17604887Schin 		Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp;
17614887Schin 		if(--pp->refcount<=0)
17624887Schin 			free((void*)pp);
17634887Schin 	}
17644887Schin 	nv_putv(np,val,flags,fp);
17654887Schin }
17664887Schin 
17674887Schin static const Namdisc_t talias_disc   = { 0, talias_put, talias_get   };
17684887Schin static Namfun_t  talias_init = { &talias_disc, 1 };
17694887Schin 
17704887Schin /*
17714887Schin  *  set tracked alias node <np> to value <pp>
17724887Schin  */
17734887Schin void path_alias(register Namval_t *np,register Pathcomp_t *pp)
17744887Schin {
17754887Schin 	if(pp)
17764887Schin 	{
17774887Schin 		struct stat statb;
17784887Schin 		char *sp;
17794887Schin 		nv_offattr(np,NV_NOPRINT);
17804887Schin 		nv_stack(np,&talias_init);
17814887Schin 		np->nvalue.cp = (char*)pp;
17824887Schin 		pp->refcount++;
17834887Schin 		nv_setattr(np,NV_TAGGED|NV_NOFREE);
17844887Schin 		path_nextcomp(pp,nv_name(np),pp);
17854887Schin 		sp = stakptr(PATH_OFFSET);
17864887Schin 		if(sp && lstat(sp,&statb)>=0 && S_ISLNK(statb.st_mode))
17874887Schin 			nv_setsize(np,statb.st_size+1);
17884887Schin 		else
17894887Schin 			nv_setsize(np,0);
17904887Schin 	}
17914887Schin 	else
17924887Schin 		nv_unset(np);
17934887Schin }
17944887Schin 
1795