1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1982-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                  David Korn <dgk@research.att.com>                   *
18*4887Schin *                                                                      *
19*4887Schin ***********************************************************************/
20*4887Schin #pragma prototyped
21*4887Schin /*
22*4887Schin  * David Korn
23*4887Schin  * AT&T Labs
24*4887Schin  *
25*4887Schin  */
26*4887Schin 
27*4887Schin #include	"defs.h"
28*4887Schin #include	<fcin.h>
29*4887Schin #include	<ls.h>
30*4887Schin #include	<nval.h>
31*4887Schin #include	<dlldefs.h>
32*4887Schin #include	"variables.h"
33*4887Schin #include	"path.h"
34*4887Schin #include	"io.h"
35*4887Schin #include	"jobs.h"
36*4887Schin #include	"history.h"
37*4887Schin #include	"test.h"
38*4887Schin #include	"FEATURE/externs"
39*4887Schin #if SHOPT_PFSH
40*4887Schin #   ifdef _hdr_exec_attr
41*4887Schin #	include	<exec_attr.h>
42*4887Schin #   else
43*4887Schin #	undef SHOPT_PFSH
44*4887Schin #   endif
45*4887Schin #endif
46*4887Schin 
47*4887Schin #define RW_ALL	(S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH)
48*4887Schin #define LIBCMD	"cmd"
49*4887Schin 
50*4887Schin 
51*4887Schin static int		canexecute(char*,int);
52*4887Schin static void		funload(Shell_t*,int,const char*);
53*4887Schin static void		exscript(Shell_t*,char*, char*[], char**);
54*4887Schin static int		path_chkpaths(Pathcomp_t*,Pathcomp_t*,Pathcomp_t*,int);
55*4887Schin 
56*4887Schin static const char	*std_path;
57*4887Schin 
58*4887Schin static int onstdpath(const char *name)
59*4887Schin {
60*4887Schin 	register const char *cp = std_path, *sp;
61*4887Schin 	if(cp)
62*4887Schin 		while(*cp)
63*4887Schin 		{
64*4887Schin 			for(sp=name; *sp && (*cp == *sp); sp++,cp++);
65*4887Schin 			if(*sp==0 && (*cp==0 || *cp==':'))
66*4887Schin 				return(1);
67*4887Schin 			while(*cp && *cp++!=':');
68*4887Schin 		}
69*4887Schin 	return(0);
70*4887Schin }
71*4887Schin 
72*4887Schin static int path_pfexecve(const char *path, char *argv[],char *const envp[])
73*4887Schin {
74*4887Schin #if SHOPT_PFSH
75*4887Schin 	char  resolvedpath[PATH_MAX + 1];
76*4887Schin 	if(!sh_isoption(SH_PFSH))
77*4887Schin 		return(execve(path, argv, envp));
78*4887Schin 	/* Solaris implements realpath(3C) using the resolvepath(2) */
79*4887Schin 	/* system call so we can save us to call access(2) first */
80*4887Schin 	if (!realpath(path, resolvedpath))
81*4887Schin 		return -1;
82*4887Schin 
83*4887Schin 	/* we can exec the command directly instead of via pfexec(1) if */
84*4887Schin 	/* there is a matching entry without attributes in exec_attr(4) */
85*4887Schin 	if (sh.user && *sh.user)
86*4887Schin 	{
87*4887Schin 		execattr_t *pf;
88*4887Schin 		if(pf=getexecuser(sh.user, KV_COMMAND, resolvedpath, GET_ONE))
89*4887Schin 		{
90*4887Schin 			if (!pf->attr || pf->attr->length == 0)
91*4887Schin 			{
92*4887Schin 				int r = execve(path, argv, envp);
93*4887Schin 				free_execattr(pf);
94*4887Schin 				return r;
95*4887Schin 			}
96*4887Schin 			free_execattr(pf);
97*4887Schin 		}
98*4887Schin 		else
99*4887Schin 		{
100*4887Schin 			errno = ENOENT;
101*4887Schin 			return -1;
102*4887Schin 		}
103*4887Schin 	}
104*4887Schin 	--argv;
105*4887Schin 	argv[0] = argv[1];
106*4887Schin 	argv[1] = resolvedpath;
107*4887Schin 	return(execve("/usr/bin/pfexec", argv, envp));
108*4887Schin #else
109*4887Schin 	return(execve(path, argv, envp));
110*4887Schin #endif
111*4887Schin }
112*4887Schin 
113*4887Schin 
114*4887Schin static pid_t _spawnveg(const char *path, char* const argv[], char* const envp[], pid_t pid)
115*4887Schin {
116*4887Schin 	int waitsafe = job.waitsafe;
117*4887Schin 	job_lock();
118*4887Schin 	pid = spawnveg(path,argv,envp,pid);
119*4887Schin 	job.waitsafe = waitsafe;
120*4887Schin 	job_unlock();
121*4887Schin 	return(pid);
122*4887Schin }
123*4887Schin /*
124*4887Schin  * used with command -x to run the command in multiple passes
125*4887Schin  * spawn is non-zero when invoked via spawn
126*4887Schin  * the exitval is set to the maximum for each execution
127*4887Schin  */
128*4887Schin static pid_t path_xargs(const char *path, char *argv[],char *const envp[], int spawn)
129*4887Schin {
130*4887Schin 	register char *cp, **av, **xv;
131*4887Schin 	char **avlast= &argv[sh.xargmax], **saveargs=0;
132*4887Schin 	char *const *ev;
133*4887Schin 	long size, left;
134*4887Schin 	int nlast=1,n,exitval=0;
135*4887Schin 	pid_t pid;
136*4887Schin 	if(sh.xargmin < 0)
137*4887Schin 		return((pid_t)-1);
138*4887Schin 	size = sh.lim.arg_max-1024;
139*4887Schin 	for(ev=envp; cp= *ev; ev++)
140*4887Schin 		size -= strlen(cp)-1;
141*4887Schin 	for(av=argv; (cp= *av) && av< &argv[sh.xargmin]; av++)
142*4887Schin 		size -= strlen(cp)-1;
143*4887Schin 	for(av=avlast; cp= *av; av++,nlast++)
144*4887Schin 		size -= strlen(cp)-1;
145*4887Schin 	av =  &argv[sh.xargmin];
146*4887Schin 	if(!spawn)
147*4887Schin 		job_clear();
148*4887Schin 	sh.exitval = 0;
149*4887Schin 	while(av<avlast)
150*4887Schin 	{
151*4887Schin 		for(xv=av,left=size; left>0 && av<avlast;)
152*4887Schin 			left -= strlen(*av++)+1;
153*4887Schin 		/* leave at least two for last */
154*4887Schin 		if(left<0 && (avlast-av)<2)
155*4887Schin 			av--;
156*4887Schin 		if(xv==&argv[sh.xargmin])
157*4887Schin 		{
158*4887Schin 			n = nlast*sizeof(char*);
159*4887Schin 			saveargs = (char**)malloc(n);
160*4887Schin 			memcpy((void*)saveargs, (void*)av, n);
161*4887Schin 			memcpy((void*)av,(void*)avlast,n);
162*4887Schin 		}
163*4887Schin 		else
164*4887Schin 		{
165*4887Schin 			for(n=sh.xargmin; xv < av; xv++)
166*4887Schin 				argv[n++] = *xv;
167*4887Schin 			for(xv=avlast; cp=  *xv; xv++)
168*4887Schin 				argv[n++] = cp;
169*4887Schin 			argv[n] = 0;
170*4887Schin 		}
171*4887Schin 		if(saveargs || av<avlast || (exitval && !spawn))
172*4887Schin 		{
173*4887Schin 			if((pid=_spawnveg(path,argv,envp,0)) < 0)
174*4887Schin 				return(-1);
175*4887Schin 			job_post(pid,0);
176*4887Schin 			job_wait(pid);
177*4887Schin 			if(sh.exitval>exitval)
178*4887Schin 				exitval = sh.exitval;
179*4887Schin 			if(saveargs)
180*4887Schin 			{
181*4887Schin 				memcpy((void*)av,saveargs,n);
182*4887Schin 				free((void*)saveargs);
183*4887Schin 				saveargs = 0;
184*4887Schin 			}
185*4887Schin 		}
186*4887Schin 		else if(spawn && !sh_isoption(SH_PFSH))
187*4887Schin 		{
188*4887Schin 			sh.xargexit = exitval;
189*4887Schin 			return(_spawnveg(path,argv,envp,spawn>>1));
190*4887Schin 		}
191*4887Schin 		else
192*4887Schin 			return((pid_t)path_pfexecve(path,argv,envp));
193*4887Schin 	}
194*4887Schin 	if(!spawn)
195*4887Schin 		exit(exitval);
196*4887Schin 	return((pid_t)-1);
197*4887Schin }
198*4887Schin 
199*4887Schin /*
200*4887Schin  * make sure PWD is set up correctly
201*4887Schin  * Return the present working directory
202*4887Schin  * Invokes getcwd() if flag==0 and if necessary
203*4887Schin  * Sets the PWD variable to this value
204*4887Schin  */
205*4887Schin char *path_pwd(int flag)
206*4887Schin {
207*4887Schin 	register char *cp;
208*4887Schin 	register char *dfault = (char*)e_dot;
209*4887Schin 	register int count = 0;
210*4887Schin 	Shell_t *shp = &sh;
211*4887Schin 	if(shp->pwd)
212*4887Schin 		return((char*)shp->pwd);
213*4887Schin 	while(1)
214*4887Schin 	{
215*4887Schin 		/* try from lowest to highest */
216*4887Schin 		switch(count++)
217*4887Schin 		{
218*4887Schin 			case 0:
219*4887Schin 				cp = nv_getval(PWDNOD);
220*4887Schin 				break;
221*4887Schin 			case 1:
222*4887Schin 				cp = nv_getval(HOME);
223*4887Schin 				break;
224*4887Schin 			case 2:
225*4887Schin 				cp = "/";
226*4887Schin 				break;
227*4887Schin 			case 3:
228*4887Schin 				cp = (char*)e_crondir;
229*4887Schin 				if(flag) /* skip next case when non-zero flag */
230*4887Schin 					++count;
231*4887Schin 				break;
232*4887Schin 			case 4:
233*4887Schin 			{
234*4887Schin 				if(cp=getcwd(NIL(char*),0))
235*4887Schin 				{
236*4887Schin 					nv_offattr(PWDNOD,NV_NOFREE);
237*4887Schin 					nv_unset(PWDNOD);
238*4887Schin 					PWDNOD->nvalue.cp = cp;
239*4887Schin 					goto skip;
240*4887Schin 				}
241*4887Schin 				break;
242*4887Schin 			}
243*4887Schin 			case 5:
244*4887Schin 				return(dfault);
245*4887Schin 		}
246*4887Schin 		if(cp && *cp=='/' && test_inode(cp,e_dot))
247*4887Schin 			break;
248*4887Schin 	}
249*4887Schin 	if(count>1)
250*4887Schin 	{
251*4887Schin 		nv_offattr(PWDNOD,NV_NOFREE);
252*4887Schin 		nv_putval(PWDNOD,cp,NV_RDONLY);
253*4887Schin 	}
254*4887Schin skip:
255*4887Schin 	nv_onattr(PWDNOD,NV_NOFREE|NV_EXPORT);
256*4887Schin 	shp->pwd = (char*)(PWDNOD->nvalue.cp);
257*4887Schin 	return(cp);
258*4887Schin }
259*4887Schin 
260*4887Schin static void free_bltin(Namval_t *np,void *data)
261*4887Schin {
262*4887Schin 	register Pathcomp_t *pp= (Pathcomp_t*)data;
263*4887Schin 	if(pp->flags&PATH_STD_DIR)
264*4887Schin 	{
265*4887Schin 		int offset=staktell();;
266*4887Schin 		if(strcmp(pp->name,"/bin")==0 || memcmp(pp->name,np->nvname,pp->len) || np->nvname[pp->len]!='/')
267*4887Schin 			return;
268*4887Schin 		stakputs("/bin");
269*4887Schin 		stakputs(np->nvname+pp->len+1);
270*4887Schin 		stakputc(0);
271*4887Schin 		sh_addbuiltin(stakptr(offset),np->nvalue.bfp,NiL);
272*4887Schin 		stakseek(offset);
273*4887Schin 		return;
274*4887Schin 	}
275*4887Schin 	if((void*)np->nvenv==pp->bltin_lib)
276*4887Schin 		dtdelete(sh_bltin_tree(),np);
277*4887Schin }
278*4887Schin 
279*4887Schin /*
280*4887Schin  * delete current Pathcomp_t structure
281*4887Schin  */
282*4887Schin void  path_delete(Pathcomp_t *first)
283*4887Schin {
284*4887Schin 	register Pathcomp_t *pp=first, *old=0, *ppnext;
285*4887Schin 	while(pp)
286*4887Schin 	{
287*4887Schin 		ppnext = pp->next;
288*4887Schin 		if(--pp->refcount<=0)
289*4887Schin 		{
290*4887Schin 			if(pp->lib)
291*4887Schin 				free((void*)pp->lib);
292*4887Schin 			if(pp->blib)
293*4887Schin 				free((void*)pp->blib);
294*4887Schin 			if(pp->bltin_lib || (pp->flags&PATH_STD_DIR))
295*4887Schin 			{
296*4887Schin 				nv_scan(sh_bltin_tree(),free_bltin,pp,0,0);
297*4887Schin 				if(pp->bltin_lib)
298*4887Schin 					dlclose(pp->bltin_lib);
299*4887Schin 			}
300*4887Schin 			free((void*)pp);
301*4887Schin 			if(old)
302*4887Schin 				old->next = ppnext;
303*4887Schin 		}
304*4887Schin 		else
305*4887Schin 			old = pp;
306*4887Schin 		pp = ppnext;
307*4887Schin 	}
308*4887Schin }
309*4887Schin 
310*4887Schin /*
311*4887Schin  * returns library variable from .paths
312*4887Schin  * The value might be returned on the stack overwriting path
313*4887Schin  */
314*4887Schin static char *path_lib(Pathcomp_t *pp, char *path)
315*4887Schin {
316*4887Schin 	register char *last = strrchr(path,'/');
317*4887Schin 	register int r;
318*4887Schin 	struct stat statb;
319*4887Schin 	if(last)
320*4887Schin 		*last = 0;
321*4887Schin 	else
322*4887Schin 		path = ".";
323*4887Schin 	r = stat(path,&statb);
324*4887Schin 	if(last)
325*4887Schin 		*last = '/';
326*4887Schin 	if(r>=0)
327*4887Schin 	{
328*4887Schin 		Pathcomp_t pcomp;
329*4887Schin 		char save[8];
330*4887Schin 		for( ;pp; pp=pp->next)
331*4887Schin 		{
332*4887Schin 			if(pp->ino==statb.st_ino && pp->dev==statb.st_dev)
333*4887Schin 				return(pp->lib);
334*4887Schin 		}
335*4887Schin 		pcomp.len = 0;
336*4887Schin 		if(last)
337*4887Schin 			pcomp.len = last-path;
338*4887Schin 		memcpy((void*)save, (void*)stakptr(PATH_OFFSET+pcomp.len),sizeof(save));
339*4887Schin 		if(path_chkpaths((Pathcomp_t*)0,(Pathcomp_t*)0,&pcomp,PATH_OFFSET))
340*4887Schin 			return(stakfreeze(1));
341*4887Schin 		memcpy((void*)stakptr(PATH_OFFSET+pcomp.len),(void*)save,sizeof(save));
342*4887Schin 	}
343*4887Schin 	return(0);
344*4887Schin }
345*4887Schin 
346*4887Schin #if 0
347*4887Schin void path_dump(register Pathcomp_t *pp)
348*4887Schin {
349*4887Schin 	sfprintf(sfstderr,"dump\n");
350*4887Schin 	while(pp)
351*4887Schin 	{
352*4887Schin 		sfprintf(sfstderr,"pp=%x dev=%d ino=%d len=%d flags=%o name=%.*s\n",
353*4887Schin 			pp,pp->dev,pp->ino,pp->len,pp->flags,pp->len,pp->name);
354*4887Schin 		pp = pp->next;
355*4887Schin 	}
356*4887Schin }
357*4887Schin #endif
358*4887Schin 
359*4887Schin /*
360*4887Schin  * write the next path to search on the current stack
361*4887Schin  * if last is given, all paths that come before <last> are skipped
362*4887Schin  * the next pathcomp is returned.
363*4887Schin  */
364*4887Schin Pathcomp_t *path_nextcomp(register Pathcomp_t *pp, const char *name, Pathcomp_t *last)
365*4887Schin {
366*4887Schin 	stakseek(PATH_OFFSET);
367*4887Schin 	if(*name=='/')
368*4887Schin 		pp = 0;
369*4887Schin 	else
370*4887Schin 	{
371*4887Schin 		for(;pp && pp!=last;pp=pp->next)
372*4887Schin 		{
373*4887Schin 			if(pp->flags&PATH_SKIP)
374*4887Schin 				continue;
375*4887Schin 			if(!last || *pp->name!='/')
376*4887Schin 				break;
377*4887Schin 		}
378*4887Schin 		if(!pp)		/* this should not happen */
379*4887Schin 			pp = last;
380*4887Schin 	}
381*4887Schin 	if(pp && (pp->name[0]!='.' || pp->name[1]))
382*4887Schin 	{
383*4887Schin 		if(*pp->name!='/')
384*4887Schin 		{
385*4887Schin 			stakputs(path_pwd(1));
386*4887Schin 			if(*stakptr(staktell()-1)!='/')
387*4887Schin 				stakputc('/');
388*4887Schin 		}
389*4887Schin 		stakwrite(pp->name,pp->len);
390*4887Schin 		if(pp->name[pp->len-1]!='/')
391*4887Schin 			stakputc('/');
392*4887Schin 	}
393*4887Schin 	stakputs(name);
394*4887Schin 	stakputc(0);
395*4887Schin 	while(pp && pp!=last && (pp=pp->next))
396*4887Schin 	{
397*4887Schin 		if(!(pp->flags&PATH_SKIP))
398*4887Schin 			return(pp);
399*4887Schin 	}
400*4887Schin 	return((Pathcomp_t*)0);
401*4887Schin }
402*4887Schin 
403*4887Schin static Pathcomp_t* defpath_init(Shell_t *shp)
404*4887Schin {
405*4887Schin 	Pathcomp_t *pp = (void*)path_addpath((Pathcomp_t*)0,(std_path),PATH_PATH);
406*4887Schin 	if(shp->defpathlist = (void*)pp)
407*4887Schin 		pp->shp = shp;
408*4887Schin 	return(pp);
409*4887Schin }
410*4887Schin 
411*4887Schin static void path_init(Shell_t *shp)
412*4887Schin {
413*4887Schin 	const char *val;
414*4887Schin 	Pathcomp_t *pp;
415*4887Schin 	if(!std_path && !(std_path=astconf("PATH",NIL(char*),NIL(char*))))
416*4887Schin 		std_path = e_defpath;
417*4887Schin 	if(val=nv_scoped((PATHNOD))->nvalue.cp)
418*4887Schin 	{
419*4887Schin 		pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_PATH);
420*4887Schin 		if(shp->pathlist = (void*)pp)
421*4887Schin 			pp->shp = shp;
422*4887Schin 	}
423*4887Schin 	else
424*4887Schin 	{
425*4887Schin 		if(!(pp=(Pathcomp_t*)shp->defpathlist))
426*4887Schin 			pp = defpath_init(shp);
427*4887Schin 		shp->pathlist = (void*)path_dup(pp);
428*4887Schin 	}
429*4887Schin 	if(val=nv_scoped((FPATHNOD))->nvalue.cp)
430*4887Schin 	{
431*4887Schin 		pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_FPATH);
432*4887Schin 		if(shp->pathlist = (void*)pp)
433*4887Schin 			pp->shp = shp;
434*4887Schin 	}
435*4887Schin }
436*4887Schin 
437*4887Schin /*
438*4887Schin  * returns that pathlist to search
439*4887Schin  */
440*4887Schin Pathcomp_t *path_get(register const char *name)
441*4887Schin {
442*4887Schin 	register Shell_t *shp = &sh;
443*4887Schin 	register Pathcomp_t *pp=0;
444*4887Schin 	if(*name && strchr(name,'/'))
445*4887Schin 		return(0);
446*4887Schin 	if(!sh_isstate(SH_DEFPATH))
447*4887Schin 	{
448*4887Schin 		if(!shp->pathlist)
449*4887Schin 			path_init(shp);
450*4887Schin 		pp = (Pathcomp_t*)shp->pathlist;
451*4887Schin 	}
452*4887Schin 	if(!pp && (!(PATHNOD)->nvalue.cp) || sh_isstate(SH_DEFPATH))
453*4887Schin 	{
454*4887Schin 		if(!(pp=(Pathcomp_t*)shp->defpathlist))
455*4887Schin 			pp = defpath_init(shp);
456*4887Schin 	}
457*4887Schin 	return(pp);
458*4887Schin }
459*4887Schin 
460*4887Schin /*
461*4887Schin  * open file corresponding to name using path give by <pp>
462*4887Schin  */
463*4887Schin static int	path_opentype(const char *name, register Pathcomp_t *pp, int fun)
464*4887Schin {
465*4887Schin 	register int fd= -1;
466*4887Schin 	struct stat statb;
467*4887Schin 	Pathcomp_t *oldpp;
468*4887Schin 	Shell_t *shp;
469*4887Schin 	if(pp)
470*4887Schin 		shp = pp->shp;
471*4887Schin 	else
472*4887Schin 	{
473*4887Schin 		shp = sh_getinterp();
474*4887Schin 		if(!shp->pathlist)
475*4887Schin 			path_init(shp);
476*4887Schin 	}
477*4887Schin 	if(!fun && strchr(name,'/'))
478*4887Schin 	{
479*4887Schin 		if(sh_isoption(SH_RESTRICTED))
480*4887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_restricted,name);
481*4887Schin 	}
482*4887Schin 	do
483*4887Schin 	{
484*4887Schin 		pp = path_nextcomp(oldpp=pp,name,0);
485*4887Schin 		while(oldpp && (oldpp->flags&PATH_SKIP))
486*4887Schin 			oldpp = oldpp->next;
487*4887Schin 		if(fun && (!oldpp || !(oldpp->flags&PATH_FPATH)))
488*4887Schin 			continue;
489*4887Schin 		if((fd = sh_open(path_relative(stakptr(PATH_OFFSET)),O_RDONLY,0)) >= 0)
490*4887Schin 		{
491*4887Schin 			if(fstat(fd,&statb)<0 || S_ISDIR(statb.st_mode))
492*4887Schin 			{
493*4887Schin 				errno = EISDIR;
494*4887Schin 				sh_close(fd);
495*4887Schin 				fd = -1;
496*4887Schin 			}
497*4887Schin 		}
498*4887Schin 	}
499*4887Schin 	while( fd<0 && pp);
500*4887Schin 	if(fd>=0 && (fd = sh_iomovefd(fd)) > 0)
501*4887Schin 	{
502*4887Schin 		fcntl(fd,F_SETFD,FD_CLOEXEC);
503*4887Schin 		shp->fdstatus[fd] |= IOCLEX;
504*4887Schin 	}
505*4887Schin 	return(fd);
506*4887Schin }
507*4887Schin 
508*4887Schin /*
509*4887Schin  * open file corresponding to name using path give by <pp>
510*4887Schin  */
511*4887Schin int	path_open(const char *name, register Pathcomp_t *pp)
512*4887Schin {
513*4887Schin 	return(path_opentype(name,pp,0));
514*4887Schin }
515*4887Schin 
516*4887Schin /*
517*4887Schin  * given a pathname return the base name
518*4887Schin  */
519*4887Schin 
520*4887Schin char	*path_basename(register const char *name)
521*4887Schin {
522*4887Schin 	register const char *start = name;
523*4887Schin 	while (*name)
524*4887Schin 		if ((*name++ == '/') && *name)	/* don't trim trailing / */
525*4887Schin 			start = name;
526*4887Schin 	return ((char*)start);
527*4887Schin }
528*4887Schin 
529*4887Schin char *path_fullname(const char *name)
530*4887Schin {
531*4887Schin 	int len=strlen(name)+1,dirlen=0;
532*4887Schin 	char *path,*pwd;
533*4887Schin 	if(*name!='/')
534*4887Schin 	{
535*4887Schin 		pwd = path_pwd(1);
536*4887Schin 		dirlen = strlen(pwd)+1;
537*4887Schin 	}
538*4887Schin 	path = (char*)malloc(len+dirlen);
539*4887Schin 	if(dirlen)
540*4887Schin 	{
541*4887Schin 		memcpy((void*)path,(void*)pwd,dirlen);
542*4887Schin 		path[dirlen-1] = '/';
543*4887Schin 	}
544*4887Schin 	memcpy((void*)&path[dirlen],(void*)name,len);
545*4887Schin 	pathcanon(path,0);
546*4887Schin 	return(path);
547*4887Schin }
548*4887Schin 
549*4887Schin /*
550*4887Schin  * load functions from file <fno>
551*4887Schin  */
552*4887Schin static void funload(Shell_t *shp,int fno, const char *name)
553*4887Schin {
554*4887Schin 	char *oldname=shp->st.filename, buff[IOBSIZE+1];
555*4887Schin 	int savestates = sh_getstate();
556*4887Schin 	sh_onstate(SH_NOLOG);
557*4887Schin 	sh_onstate(SH_NOALIAS);
558*4887Schin 	shp->readscript = (char*)name;
559*4887Schin 	shp->st.filename = path_fullname(stakptr(PATH_OFFSET));
560*4887Schin 	error_info.line = 0;
561*4887Schin 	sh_eval(sfnew(NIL(Sfio_t*),buff,IOBSIZE,fno,SF_READ),0);
562*4887Schin 	shp->readscript = 0;
563*4887Schin 	free((void*)shp->st.filename);
564*4887Schin 	shp->st.filename = oldname;
565*4887Schin 	sh_setstate(savestates);
566*4887Schin }
567*4887Schin 
568*4887Schin /*
569*4887Schin  * do a path search and track alias if requested
570*4887Schin  * if flag is 0, or if name not found, then try autoloading function
571*4887Schin  * if flag==2, returns 1 if name found on FPATH
572*4887Schin  * returns 1, if function was autoloaded.
573*4887Schin  * If endpath!=NULL, Path search ends when path matches endpath.
574*4887Schin  */
575*4887Schin 
576*4887Schin int	path_search(register const char *name,Pathcomp_t *endpath, int flag)
577*4887Schin {
578*4887Schin 	register Namval_t *np;
579*4887Schin 	register int fno;
580*4887Schin 	Pathcomp_t *pp=0;
581*4887Schin 	Shell_t *shp = &sh;
582*4887Schin 	if(name && strchr(name,'/'))
583*4887Schin 	{
584*4887Schin 		stakseek(PATH_OFFSET);
585*4887Schin 		stakputs(name);
586*4887Schin 		if(canexecute(stakptr(PATH_OFFSET),0)<0)
587*4887Schin 		{
588*4887Schin 			*stakptr(PATH_OFFSET) = 0;
589*4887Schin 			return(0);
590*4887Schin 		}
591*4887Schin 		if(*name=='/')
592*4887Schin 			return(1);
593*4887Schin 		stakseek(PATH_OFFSET);
594*4887Schin 		stakputs(path_pwd(1));
595*4887Schin 		stakputc('/');
596*4887Schin 		stakputs(name);
597*4887Schin 		stakputc(0);
598*4887Schin 		return(0);
599*4887Schin 	}
600*4887Schin 	if(sh_isstate(SH_DEFPATH))
601*4887Schin 	{
602*4887Schin 		if(!shp->defpathlist)
603*4887Schin 			defpath_init(shp);
604*4887Schin 	}
605*4887Schin 	else if(!shp->pathlist)
606*4887Schin 		path_init(shp);
607*4887Schin 	if(flag)
608*4887Schin 	{
609*4887Schin 		if(!(pp=path_absolute(name,endpath)) && endpath)
610*4887Schin 			pp = path_absolute(name,NIL(Pathcomp_t*));
611*4887Schin 		if(!pp && (np=nv_search(name,sh.fun_tree,HASH_NOSCOPE))&&np->nvalue.ip)
612*4887Schin 			return(1);
613*4887Schin 		if(!pp)
614*4887Schin 			*stakptr(PATH_OFFSET) = 0;
615*4887Schin 	}
616*4887Schin 	if(flag==0 || !pp || (pp->flags&PATH_FPATH))
617*4887Schin 	{
618*4887Schin 		if(!pp)
619*4887Schin 			pp=sh_isstate(SH_DEFPATH)?shp->defpathlist:shp->pathlist;
620*4887Schin 		if(pp && strmatch(name,e_alphanum)  && (fno=path_opentype(name,pp,1))>=0)
621*4887Schin 		{
622*4887Schin 			if(flag==2)
623*4887Schin 			{
624*4887Schin 				sh_close(fno);
625*4887Schin 				return(1);
626*4887Schin 			}
627*4887Schin 			funload(shp,fno,name);
628*4887Schin 			return(1);
629*4887Schin 		}
630*4887Schin 		*stakptr(PATH_OFFSET) = 0;
631*4887Schin 		return(0);
632*4887Schin 	}
633*4887Schin 	else if(pp && !sh_isstate(SH_DEFPATH) && *name!='/')
634*4887Schin 	{
635*4887Schin 		if(np=nv_search(name,shp->track_tree,NV_ADD))
636*4887Schin 			path_alias(np,pp);
637*4887Schin 	}
638*4887Schin 	return(0);
639*4887Schin }
640*4887Schin 
641*4887Schin 
642*4887Schin /*
643*4887Schin  * do a path search and find the full pathname of file name
644*4887Schin  * end search of path matches endpath without checking execute permission
645*4887Schin  */
646*4887Schin 
647*4887Schin Pathcomp_t *path_absolute(register const char *name, Pathcomp_t *endpath)
648*4887Schin {
649*4887Schin 	register int	f,isfun;
650*4887Schin 	int		noexec=0;
651*4887Schin 	Pathcomp_t	*pp,*oldpp;
652*4887Schin 	Shell_t		*shp = &sh;
653*4887Schin 	Namval_t	*np;
654*4887Schin 	shp->path_err = ENOENT;
655*4887Schin 	if(!(pp=path_get("")))
656*4887Schin 		return(0);
657*4887Schin 	shp->path_err = 0;
658*4887Schin 	while(1)
659*4887Schin 	{
660*4887Schin 		sh_sigcheck();
661*4887Schin 		isfun = (pp->flags&PATH_FPATH);
662*4887Schin 		if(oldpp=pp)
663*4887Schin 			pp = path_nextcomp(pp,name,0);
664*4887Schin 		if(endpath)
665*4887Schin 			return(endpath);
666*4887Schin 		if(!isfun && !sh_isoption(SH_RESTRICTED))
667*4887Schin 		{
668*4887Schin 			if(nv_search(stakptr(PATH_OFFSET),sh.bltin_tree,0))
669*4887Schin 				return(oldpp);
670*4887Schin 			if(oldpp->blib)
671*4887Schin 			{
672*4887Schin 				typedef int (*Fptr_t)(int, char*[], void*);
673*4887Schin 				Fptr_t addr;
674*4887Schin 				int n = staktell();
675*4887Schin 				char *cp;
676*4887Schin 				stakputs("b_");
677*4887Schin 				stakputs(name);
678*4887Schin 				stakputc(0);
679*4887Schin 				if(!oldpp->bltin_lib)
680*4887Schin 				{
681*4887Schin 					if(cp = strrchr(oldpp->blib,'/'))
682*4887Schin 						cp++;
683*4887Schin 					else
684*4887Schin 						cp = oldpp->blib;
685*4887Schin 					if(strcmp(cp,LIBCMD)==0 && (addr=(Fptr_t)dlllook((void*)0,stakptr(n))))
686*4887Schin 					{
687*4887Schin 						np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL);
688*4887Schin 						np->nvfun = (Namfun_t*)np->nvname;
689*4887Schin 						return(oldpp);
690*4887Schin 					}
691*4887Schin #if (_AST_VERSION>=20040404)
692*4887Schin 					if (oldpp->bltin_lib = dllplug(SH_ID, oldpp->blib, NiL, RTLD_LAZY, NiL, 0))
693*4887Schin #else
694*4887Schin 					if (oldpp->bltin_lib = dllfind(oldpp->blib, NiL, RTLD_LAZY, NiL, 0))
695*4887Schin #endif
696*4887Schin 						sh_addlib(oldpp->bltin_lib);
697*4887Schin 				}
698*4887Schin 				if((addr=(Fptr_t)dlllook(oldpp->bltin_lib,stakptr(n))) &&
699*4887Schin 				   (!(np = sh_addbuiltin(stakptr(PATH_OFFSET),NiL,NiL)) || np->nvalue.bfp!=addr) &&
700*4887Schin 				   (np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL)))
701*4887Schin 				{
702*4887Schin 					np->nvenv = oldpp->bltin_lib;
703*4887Schin 					return(oldpp);
704*4887Schin 				}
705*4887Schin 			}
706*4887Schin 		}
707*4887Schin 		f = canexecute(stakptr(PATH_OFFSET),isfun);
708*4887Schin 		if(isfun && f>=0)
709*4887Schin 		{
710*4887Schin 			nv_onattr(nv_open(name,shp->fun_tree,NV_NOARRAY|NV_IDENT|NV_NOSCOPE),NV_LTOU|NV_FUNCTION);
711*4887Schin 			close(f);
712*4887Schin 			f = -1;
713*4887Schin 			return(0);
714*4887Schin 		}
715*4887Schin 		else if(f>=0 && (oldpp->flags & PATH_STD_DIR))
716*4887Schin 		{
717*4887Schin 			int offset = staktell();
718*4887Schin 			stakputs("/bin/");
719*4887Schin 			stakputs(name);
720*4887Schin 			stakputc(0);
721*4887Schin 			np = nv_search(stakptr(offset),sh.bltin_tree,0);
722*4887Schin 			stakseek(offset);
723*4887Schin 			if(np)
724*4887Schin 			{
725*4887Schin 				np = sh_addbuiltin(stakptr(PATH_OFFSET),np->nvalue.bfp,NiL);
726*4887Schin 				np->nvfun = (Namfun_t*)np->nvname;
727*4887Schin 			}
728*4887Schin 		}
729*4887Schin 		if(!pp || f>=0)
730*4887Schin 			break;
731*4887Schin 		if(errno!=ENOENT)
732*4887Schin 			noexec = errno;
733*4887Schin 	}
734*4887Schin 	if(f<0)
735*4887Schin 	{
736*4887Schin 		if(!endpath)
737*4887Schin 			shp->path_err = (noexec?noexec:ENOENT);
738*4887Schin 		return(0);
739*4887Schin 	}
740*4887Schin 	stakputc(0);
741*4887Schin 	return(oldpp);
742*4887Schin }
743*4887Schin 
744*4887Schin /*
745*4887Schin  * returns 0 if path can execute
746*4887Schin  * sets exec_err if file is found but can't be executable
747*4887Schin  */
748*4887Schin #undef S_IXALL
749*4887Schin #ifdef S_IXUSR
750*4887Schin #   define S_IXALL	(S_IXUSR|S_IXGRP|S_IXOTH)
751*4887Schin #else
752*4887Schin #   ifdef S_IEXEC
753*4887Schin #	define S_IXALL	(S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6))
754*4887Schin #   else
755*4887Schin #	define S_IXALL	0111
756*4887Schin #   endif /*S_EXEC */
757*4887Schin #endif /* S_IXUSR */
758*4887Schin 
759*4887Schin static int canexecute(register char *path, int isfun)
760*4887Schin {
761*4887Schin 	struct stat statb;
762*4887Schin 	register int fd=0;
763*4887Schin 	path = path_relative(path);
764*4887Schin 	if(isfun)
765*4887Schin 	{
766*4887Schin 		if((fd=open(path,O_RDONLY,0))<0 || fstat(fd,&statb)<0)
767*4887Schin 			goto err;
768*4887Schin 	}
769*4887Schin 	else if(stat(path,&statb) < 0)
770*4887Schin 	{
771*4887Schin #if _WINIX
772*4887Schin 		/* check for .exe or .bat suffix */
773*4887Schin 		char *cp;
774*4887Schin 		if(errno==ENOENT && (!(cp=strrchr(path,'.')) || strlen(cp)>4 || strchr(cp,'/')))
775*4887Schin 		{
776*4887Schin 			int offset = staktell()-1;
777*4887Schin 			stakseek(offset);
778*4887Schin 			stakputs(".bat");
779*4887Schin 			path = stakptr(PATH_OFFSET);
780*4887Schin 			if(stat(path,&statb) < 0)
781*4887Schin 			{
782*4887Schin 				if(errno!=ENOENT)
783*4887Schin 					goto err;
784*4887Schin 				memcpy(stakptr(offset),".sh",4);
785*4887Schin 				if(stat(path,&statb) < 0)
786*4887Schin 					goto err;
787*4887Schin 			}
788*4887Schin 		}
789*4887Schin 		else
790*4887Schin #endif /* _WINIX */
791*4887Schin 		goto err;
792*4887Schin 	}
793*4887Schin 	errno = EPERM;
794*4887Schin 	if(S_ISDIR(statb.st_mode))
795*4887Schin 		errno = EISDIR;
796*4887Schin 	else if((statb.st_mode&S_IXALL)==S_IXALL || sh_access(path,X_OK)>=0)
797*4887Schin 		return(fd);
798*4887Schin 	if(isfun && fd>=0)
799*4887Schin 		sh_close(fd);
800*4887Schin err:
801*4887Schin 	return(-1);
802*4887Schin }
803*4887Schin 
804*4887Schin /*
805*4887Schin  * Return path relative to present working directory
806*4887Schin  */
807*4887Schin 
808*4887Schin char *path_relative(register const char* file)
809*4887Schin {
810*4887Schin 	register const char *pwd;
811*4887Schin 	register const char *fp = file;
812*4887Schin 	/* can't relpath when sh.pwd not set */
813*4887Schin 	if(!(pwd=sh.pwd))
814*4887Schin 		return((char*)fp);
815*4887Schin 	while(*pwd==*fp)
816*4887Schin 	{
817*4887Schin 		if(*pwd++==0)
818*4887Schin 			return((char*)e_dot);
819*4887Schin 		fp++;
820*4887Schin 	}
821*4887Schin 	if(*pwd==0 && *fp == '/')
822*4887Schin 	{
823*4887Schin 		while(*++fp=='/');
824*4887Schin 		if(*fp)
825*4887Schin 			return((char*)fp);
826*4887Schin 		return((char*)e_dot);
827*4887Schin 	}
828*4887Schin 	return((char*)file);
829*4887Schin }
830*4887Schin 
831*4887Schin void	path_exec(register const char *arg0,register char *argv[],struct argnod *local)
832*4887Schin {
833*4887Schin 	char **envp;
834*4887Schin 	const char *opath;
835*4887Schin 	Pathcomp_t *libpath, *pp=0;
836*4887Schin 	Shell_t *shp = &sh;
837*4887Schin 	int slash=0;
838*4887Schin 	nv_setlist(local,NV_EXPORT|NV_IDENT|NV_ASSIGN);
839*4887Schin 	envp = sh_envgen();
840*4887Schin 	if(strchr(arg0,'/'))
841*4887Schin 	{
842*4887Schin 		slash=1;
843*4887Schin 		/* name containing / not allowed for restricted shell */
844*4887Schin 		if(sh_isoption(SH_RESTRICTED))
845*4887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_restricted,arg0);
846*4887Schin 	}
847*4887Schin 	else
848*4887Schin 		pp=path_get(arg0);
849*4887Schin 	shp->path_err= ENOENT;
850*4887Schin 	sfsync(NIL(Sfio_t*));
851*4887Schin 	timerdel(NIL(void*));
852*4887Schin 	/* find first path that has a library component */
853*4887Schin 	if(pp || slash) do
854*4887Schin 	{
855*4887Schin 		sh_sigcheck();
856*4887Schin 		if(libpath=pp)
857*4887Schin 		{
858*4887Schin 			pp = path_nextcomp(pp,arg0,0);
859*4887Schin 			opath = stakfreeze(1)+PATH_OFFSET;
860*4887Schin 		}
861*4887Schin 		else
862*4887Schin 			opath = arg0;
863*4887Schin 		path_spawn(opath,argv,envp,libpath,0);
864*4887Schin 		while(pp && (pp->flags&PATH_FPATH))
865*4887Schin 			pp = path_nextcomp(pp,arg0,0);
866*4887Schin 	}
867*4887Schin 	while(pp);
868*4887Schin 	/* force an exit */
869*4887Schin 	((struct checkpt*)shp->jmplist)->mode = SH_JMPEXIT;
870*4887Schin 	if((errno=shp->path_err)==ENOENT)
871*4887Schin 		errormsg(SH_DICT,ERROR_exit(ERROR_NOENT),e_found,arg0);
872*4887Schin 	else
873*4887Schin 		errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,arg0);
874*4887Schin }
875*4887Schin 
876*4887Schin pid_t path_spawn(const char *opath,register char **argv, char **envp, Pathcomp_t *libpath, int spawn)
877*4887Schin {
878*4887Schin 	Shell_t *shp = sh_getinterp();
879*4887Schin 	register char *path;
880*4887Schin 	char **xp=0, *xval, *libenv = (libpath?libpath->lib:0);
881*4887Schin 	Namval_t*	np;
882*4887Schin 	char		*s, *v;
883*4887Schin 	int		r, n;
884*4887Schin 	pid_t		pid= -1;
885*4887Schin 	/* leave room for inserting _= pathname in environment */
886*4887Schin 	envp--;
887*4887Schin #if _lib_readlink
888*4887Schin 	/* save original pathname */
889*4887Schin 	stakseek(PATH_OFFSET);
890*4887Schin 	stakputs(opath);
891*4887Schin 	opath = stakfreeze(1)+PATH_OFFSET;
892*4887Schin 	np=nv_search(argv[0],shp->track_tree,0);
893*4887Schin 	while(libpath && !libpath->lib)
894*4887Schin 		libpath=libpath->next;
895*4887Schin 	if(libpath && (!np || nv_size(np)>0))
896*4887Schin 	{
897*4887Schin 		/* check for symlink and use symlink name */
898*4887Schin 		char buff[PATH_MAX+1];
899*4887Schin 		char save[PATH_MAX+1];
900*4887Schin 		stakseek(PATH_OFFSET);
901*4887Schin 		stakputs(opath);
902*4887Schin 		path = stakptr(PATH_OFFSET);
903*4887Schin 		while((n=readlink(path,buff,PATH_MAX))>0)
904*4887Schin 		{
905*4887Schin 			buff[n] = 0;
906*4887Schin 			n = PATH_OFFSET;
907*4887Schin 			r = 0;
908*4887Schin 			if((v=strrchr(path,'/')) && *buff!='/')
909*4887Schin 			{
910*4887Schin 				if(buff[0]=='.' && buff[1]=='.' && (r = strlen(path) + 1) <= PATH_MAX)
911*4887Schin 					memcpy(save, path, r);
912*4887Schin 				else
913*4887Schin 					r = 0;
914*4887Schin 				n += (v+1-path);
915*4887Schin 			}
916*4887Schin 			stakseek(n);
917*4887Schin 			stakputs(buff);
918*4887Schin 			stakputc(0);
919*4887Schin 			path = stakptr(PATH_OFFSET);
920*4887Schin 			if(v && buff[0]=='.' && buff[1]=='.')
921*4887Schin 			{
922*4887Schin 				pathcanon(path, 0);
923*4887Schin 				if(r && access(path,X_OK))
924*4887Schin 				{
925*4887Schin 					memcpy(path, save, r);
926*4887Schin 					break;
927*4887Schin 				}
928*4887Schin 			}
929*4887Schin 			if(libenv = path_lib(libpath,path))
930*4887Schin 				break;
931*4887Schin 		}
932*4887Schin 		stakseek(0);
933*4887Schin 	}
934*4887Schin #endif
935*4887Schin 	if(libenv && (v = strchr(libenv,'=')))
936*4887Schin 	{
937*4887Schin 		n = v - libenv;
938*4887Schin 		*v = 0;
939*4887Schin 		np = nv_open(libenv,shp->var_tree,0);
940*4887Schin 		*v = '=';
941*4887Schin 		s = nv_getval(np);
942*4887Schin 		stakputs(libenv);
943*4887Schin 		if(s)
944*4887Schin 		{
945*4887Schin 			stakputc(':');
946*4887Schin 			stakputs(s);
947*4887Schin 		}
948*4887Schin 		v = stakfreeze(1);
949*4887Schin 		r = 1;
950*4887Schin 		xp = envp + 2;
951*4887Schin 		while (s = *xp++)
952*4887Schin 		{
953*4887Schin 			if (strneq(s, v, n) && s[n] == '=')
954*4887Schin 			{
955*4887Schin 				xval = *--xp;
956*4887Schin 				*xp = v;
957*4887Schin 				r = 0;
958*4887Schin 				break;
959*4887Schin 			}
960*4887Schin 		}
961*4887Schin 		if (r)
962*4887Schin 		{
963*4887Schin 			*envp-- = v;
964*4887Schin 			xp = 0;
965*4887Schin 		}
966*4887Schin 	}
967*4887Schin 	if(!opath)
968*4887Schin 		opath = stakptr(PATH_OFFSET);
969*4887Schin 	envp[0] =  (char*)opath-PATH_OFFSET;
970*4887Schin 	envp[0][0] =  '_';
971*4887Schin 	envp[0][1] =  '=';
972*4887Schin 	sfsync(sfstderr);
973*4887Schin 	sh_sigcheck();
974*4887Schin 	path = path_relative(opath);
975*4887Schin #ifdef SHELLMAGIC
976*4887Schin 	if(*path!='/' && path!=opath)
977*4887Schin 	{
978*4887Schin 		/*
979*4887Schin 		 * The following code because execv(foo,) and execv(./foo,)
980*4887Schin 		 * may not yield the same results
981*4887Schin 		 */
982*4887Schin 		char *sp = (char*)malloc(strlen(path)+3);
983*4887Schin 		sp[0] = '.';
984*4887Schin 		sp[1] = '/';
985*4887Schin 		strcpy(sp+2,path);
986*4887Schin 		path = sp;
987*4887Schin 	}
988*4887Schin #endif /* SHELLMAGIC */
989*4887Schin 	if(sh_isoption(SH_RESTRICTED))
990*4887Schin 	{
991*4887Schin 		int fd;
992*4887Schin 		if((fd = sh_open(opath,O_RDONLY,0)) >= 0)
993*4887Schin 		{
994*4887Schin 			char buff[PATH_MAX];
995*4887Schin 			n = read(fd,buff,sizeof(buff));
996*4887Schin 			close(fd);
997*4887Schin 			if(n>2 && buff[0]=='#' && buff[1]=='!')
998*4887Schin 			{
999*4887Schin 				for(s=buff; n>0 && *s!='\n'; n--,s++)
1000*4887Schin 				{
1001*4887Schin 					if(*s=='/')
1002*4887Schin 						errormsg(SH_DICT,ERROR_exit(1),e_restricted,opath);
1003*4887Schin 				}
1004*4887Schin 			}
1005*4887Schin 		}
1006*4887Schin 	}
1007*4887Schin 	if(spawn && !sh_isoption(SH_PFSH))
1008*4887Schin 		pid = _spawnveg(opath, &argv[0],envp, spawn>>1);
1009*4887Schin 	else
1010*4887Schin 		path_pfexecve(opath, &argv[0] ,envp);
1011*4887Schin 	if(xp)
1012*4887Schin 		*xp = xval;
1013*4887Schin #ifdef SHELLMAGIC
1014*4887Schin 	if(*path=='.' && path!=opath)
1015*4887Schin 	{
1016*4887Schin 		free(path);
1017*4887Schin 		path = path_relative(opath);
1018*4887Schin 	}
1019*4887Schin #endif /* SHELLMAGIC */
1020*4887Schin 	if(pid>0)
1021*4887Schin 		return(pid);
1022*4887Schin retry:
1023*4887Schin 	switch(sh.path_err = errno)
1024*4887Schin 	{
1025*4887Schin #ifdef apollo
1026*4887Schin 	    /*
1027*4887Schin   	     * On apollo's execve will fail with eacces when
1028*4887Schin 	     * file has execute but not read permissions. So,
1029*4887Schin 	     * for now we will pretend that EACCES and ENOEXEC
1030*4887Schin  	     * mean the same thing.
1031*4887Schin  	     */
1032*4887Schin 	    case EACCES:
1033*4887Schin #endif /* apollo */
1034*4887Schin 	    case ENOEXEC:
1035*4887Schin #if SHOPT_SUID_EXEC
1036*4887Schin 	    case EPERM:
1037*4887Schin 		/* some systems return EPERM if setuid bit is on */
1038*4887Schin #endif
1039*4887Schin 		errno = ENOEXEC;
1040*4887Schin 		if(spawn)
1041*4887Schin 		{
1042*4887Schin #ifdef _lib_fork
1043*4887Schin 			if(sh.subshell)
1044*4887Schin 				return(-1);
1045*4887Schin 			do
1046*4887Schin 			{
1047*4887Schin 				if((pid=fork())>0)
1048*4887Schin 					return(pid);
1049*4887Schin 			}
1050*4887Schin 			while(_sh_fork(pid,0,(int*)0) < 0);
1051*4887Schin #else
1052*4887Schin 			return(-1);
1053*4887Schin #endif
1054*4887Schin 		}
1055*4887Schin 		exscript(shp,path,argv,envp);
1056*4887Schin #ifndef apollo
1057*4887Schin 	    case EACCES:
1058*4887Schin 	    {
1059*4887Schin 		struct stat statb;
1060*4887Schin 		if(stat(path,&statb)>=0)
1061*4887Schin 		{
1062*4887Schin 			if(S_ISDIR(statb.st_mode))
1063*4887Schin 				errno = EISDIR;
1064*4887Schin #ifdef S_ISSOCK
1065*4887Schin 			if(S_ISSOCK(statb.st_mode))
1066*4887Schin 				exscript(shp,path,argv,envp);
1067*4887Schin #endif
1068*4887Schin 		}
1069*4887Schin 	    }
1070*4887Schin 		/* FALL THROUGH */
1071*4887Schin #endif /* !apollo */
1072*4887Schin #ifdef ENAMETOOLONG
1073*4887Schin 	    case ENAMETOOLONG:
1074*4887Schin #endif /* ENAMETOOLONG */
1075*4887Schin #if !SHOPT_SUID_EXEC
1076*4887Schin 	    case EPERM:
1077*4887Schin #endif
1078*4887Schin 		shp->path_err = errno;
1079*4887Schin 		return(-1);
1080*4887Schin 	    case ENOTDIR:
1081*4887Schin 	    case ENOENT:
1082*4887Schin 	    case EINTR:
1083*4887Schin #ifdef EMLINK
1084*4887Schin 	    case EMLINK:
1085*4887Schin #endif /* EMLINK */
1086*4887Schin 		return(-1);
1087*4887Schin 	    case E2BIG:
1088*4887Schin 		if(sh.xargmin)
1089*4887Schin 		{
1090*4887Schin 			pid = path_xargs(opath, &argv[0] ,envp,spawn);
1091*4887Schin 			if(pid<0)
1092*4887Schin 				goto retry;
1093*4887Schin 			return(pid);
1094*4887Schin 		}
1095*4887Schin 	    default:
1096*4887Schin 		errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path);
1097*4887Schin 	}
1098*4887Schin 	return 0;
1099*4887Schin }
1100*4887Schin 
1101*4887Schin /*
1102*4887Schin  * File is executable but not machine code.
1103*4887Schin  * Assume file is a Shell script and execute it.
1104*4887Schin  */
1105*4887Schin 
1106*4887Schin static void exscript(Shell_t *shp,register char *path,register char *argv[],char **envp)
1107*4887Schin {
1108*4887Schin 	register Sfio_t *sp;
1109*4887Schin 	path = path_relative(path);
1110*4887Schin 	shp->comdiv=0;
1111*4887Schin 	shp->bckpid = 0;
1112*4887Schin 	shp->st.ioset=0;
1113*4887Schin 	/* clean up any cooperating processes */
1114*4887Schin 	if(shp->cpipe[0]>0)
1115*4887Schin 		sh_pclose(shp->cpipe);
1116*4887Schin 	if(shp->cpid && shp->outpipe)
1117*4887Schin 		sh_close(*shp->outpipe);
1118*4887Schin 	shp->cpid = 0;
1119*4887Schin 	if(sp=fcfile())
1120*4887Schin 		while(sfstack(sp,SF_POPSTACK));
1121*4887Schin 	job_clear();
1122*4887Schin 	if(shp->infd>0 && (shp->fdstatus[shp->infd]&IOCLEX))
1123*4887Schin 		sh_close(shp->infd);
1124*4887Schin 	sh_setstate(sh_state(SH_FORKED));
1125*4887Schin 	sfsync(sfstderr);
1126*4887Schin #if SHOPT_SUID_EXEC && !SHOPT_PFSH
1127*4887Schin 	/* check if file cannot open for read or script is setuid/setgid  */
1128*4887Schin 	{
1129*4887Schin 		static char name[] = "/tmp/euidXXXXXXXXXX";
1130*4887Schin 		register int n;
1131*4887Schin 		register uid_t euserid;
1132*4887Schin 		char *savet=0;
1133*4887Schin 		struct stat statb;
1134*4887Schin 		if((n=sh_open(path,O_RDONLY,0)) >= 0)
1135*4887Schin 		{
1136*4887Schin 			/* move <n> if n=0,1,2 */
1137*4887Schin 			n = sh_iomovefd(n);
1138*4887Schin 			if(fstat(n,&statb)>=0 && !(statb.st_mode&(S_ISUID|S_ISGID)))
1139*4887Schin 				goto openok;
1140*4887Schin 			sh_close(n);
1141*4887Schin 		}
1142*4887Schin 		if((euserid=geteuid()) != shp->userid)
1143*4887Schin 		{
1144*4887Schin 			strncpy(name+9,fmtbase((long)getpid(),10,0),sizeof(name)-10);
1145*4887Schin 			/* create a suid open file with owner equal effective uid */
1146*4887Schin 			if((n=open(name,O_CREAT|O_TRUNC|O_WRONLY,S_ISUID|S_IXUSR)) < 0)
1147*4887Schin 				goto fail;
1148*4887Schin 			unlink(name);
1149*4887Schin 			/* make sure that file has right owner */
1150*4887Schin 			if(fstat(n,&statb)<0 || statb.st_uid != euserid)
1151*4887Schin 				goto fail;
1152*4887Schin 			if(n!=10)
1153*4887Schin 			{
1154*4887Schin 				sh_close(10);
1155*4887Schin 				fcntl(n, F_DUPFD, 10);
1156*4887Schin 				sh_close(n);
1157*4887Schin 				n=10;
1158*4887Schin 			}
1159*4887Schin 		}
1160*4887Schin 		savet = *--argv;
1161*4887Schin 		*argv = path;
1162*4887Schin 		path_pfexecve(e_suidexec,argv,envp);
1163*4887Schin 	fail:
1164*4887Schin 		/*
1165*4887Schin 		 *  The following code is just for compatibility
1166*4887Schin 		 */
1167*4887Schin 		if((n=open(path,O_RDONLY,0)) < 0)
1168*4887Schin 			errormsg(SH_DICT,ERROR_system(1),e_open,path);
1169*4887Schin 		if(savet)
1170*4887Schin 			*argv++ = savet;
1171*4887Schin 	openok:
1172*4887Schin 		shp->infd = n;
1173*4887Schin 	}
1174*4887Schin #else
1175*4887Schin 	shp->infd = sh_chkopen(path);
1176*4887Schin #endif
1177*4887Schin 	shp->infd = sh_iomovefd(shp->infd);
1178*4887Schin #if SHOPT_ACCT
1179*4887Schin 	sh_accbegin(path) ;  /* reset accounting */
1180*4887Schin #endif	/* SHOPT_ACCT */
1181*4887Schin 	shp->arglist = sh_argcreate(argv);
1182*4887Schin 	shp->lastarg = strdup(path);
1183*4887Schin 	/* save name of calling command */
1184*4887Schin 	shp->readscript = error_info.id;
1185*4887Schin 	/* close history file if name has changed */
1186*4887Schin 	if(shp->hist_ptr && (path=nv_getval(HISTFILE)) && strcmp(path,shp->hist_ptr->histname))
1187*4887Schin 	{
1188*4887Schin 		hist_close(shp->hist_ptr);
1189*4887Schin 		(HISTCUR)->nvalue.lp = 0;
1190*4887Schin 	}
1191*4887Schin 	sh_offstate(SH_FORKED);
1192*4887Schin 	siglongjmp(*shp->jmplist,SH_JMPSCRIPT);
1193*4887Schin }
1194*4887Schin 
1195*4887Schin #if SHOPT_ACCT
1196*4887Schin #   include <sys/acct.h>
1197*4887Schin #   include "FEATURE/time"
1198*4887Schin 
1199*4887Schin     static struct acct sabuf;
1200*4887Schin     static struct tms buffer;
1201*4887Schin     static clock_t	before;
1202*4887Schin     static char *SHACCT; /* set to value of SHACCT environment variable */
1203*4887Schin     static shaccton;	/* non-zero causes accounting record to be written */
1204*4887Schin     static int compress(time_t);
1205*4887Schin     /*
1206*4887Schin      *	initialize accounting, i.e., see if SHACCT variable set
1207*4887Schin      */
1208*4887Schin     void sh_accinit(void)
1209*4887Schin     {
1210*4887Schin 	SHACCT = getenv("SHACCT");
1211*4887Schin     }
1212*4887Schin     /*
1213*4887Schin     * suspend accounting unitl turned on by sh_accbegin()
1214*4887Schin     */
1215*4887Schin     void sh_accsusp(void)
1216*4887Schin     {
1217*4887Schin 	shaccton=0;
1218*4887Schin #ifdef AEXPAND
1219*4887Schin 	sabuf.ac_flag |= AEXPND;
1220*4887Schin #endif /* AEXPAND */
1221*4887Schin     }
1222*4887Schin 
1223*4887Schin     /*
1224*4887Schin      * begin an accounting record by recording start time
1225*4887Schin      */
1226*4887Schin     void sh_accbegin(const char *cmdname)
1227*4887Schin     {
1228*4887Schin 	if(SHACCT)
1229*4887Schin 	{
1230*4887Schin 		sabuf.ac_btime = time(NIL(time_t *));
1231*4887Schin 		before = times(&buffer);
1232*4887Schin 		sabuf.ac_uid = getuid();
1233*4887Schin 		sabuf.ac_gid = getgid();
1234*4887Schin 		strncpy(sabuf.ac_comm, (char*)path_basename(cmdname),
1235*4887Schin 			sizeof(sabuf.ac_comm));
1236*4887Schin 		shaccton = 1;
1237*4887Schin 	}
1238*4887Schin     }
1239*4887Schin     /*
1240*4887Schin      * terminate an accounting record and append to accounting file
1241*4887Schin      */
1242*4887Schin     void	sh_accend(void)
1243*4887Schin     {
1244*4887Schin 	int	fd;
1245*4887Schin 	clock_t	after;
1246*4887Schin 
1247*4887Schin 	if(shaccton)
1248*4887Schin 	{
1249*4887Schin 		after = times(&buffer);
1250*4887Schin 		sabuf.ac_utime = compress(buffer.tms_utime + buffer.tms_cutime);
1251*4887Schin 		sabuf.ac_stime = compress(buffer.tms_stime + buffer.tms_cstime);
1252*4887Schin 		sabuf.ac_etime = compress( (time_t)(after-before));
1253*4887Schin 		fd = open( SHACCT , O_WRONLY | O_APPEND | O_CREAT,RW_ALL);
1254*4887Schin 		write(fd, (const char*)&sabuf, sizeof( sabuf ));
1255*4887Schin 		close( fd);
1256*4887Schin 	}
1257*4887Schin     }
1258*4887Schin 
1259*4887Schin     /*
1260*4887Schin      * Produce a pseudo-floating point representation
1261*4887Schin      * with 3 bits base-8 exponent, 13 bits fraction.
1262*4887Schin      */
1263*4887Schin     static int compress(register time_t t)
1264*4887Schin     {
1265*4887Schin 	register int exp = 0, rund = 0;
1266*4887Schin 
1267*4887Schin 	while (t >= 8192)
1268*4887Schin 	{
1269*4887Schin 		exp++;
1270*4887Schin 		rund = t&04;
1271*4887Schin 		t >>= 3;
1272*4887Schin 	}
1273*4887Schin 	if (rund)
1274*4887Schin 	{
1275*4887Schin 		t++;
1276*4887Schin 		if (t >= 8192)
1277*4887Schin 		{
1278*4887Schin 			t >>= 3;
1279*4887Schin 			exp++;
1280*4887Schin 		}
1281*4887Schin 	}
1282*4887Schin 	return((exp<<13) + t);
1283*4887Schin     }
1284*4887Schin #endif	/* SHOPT_ACCT */
1285*4887Schin 
1286*4887Schin 
1287*4887Schin 
1288*4887Schin /*
1289*4887Schin  * add a pathcomponent to the path search list and eliminate duplicates
1290*4887Schin  * and non-existing absolute paths.
1291*4887Schin  */
1292*4887Schin static Pathcomp_t *path_addcomp(Pathcomp_t *first, Pathcomp_t *old,const char *name, int flag)
1293*4887Schin {
1294*4887Schin 	register Pathcomp_t *pp, *oldpp;
1295*4887Schin 	struct stat statb;
1296*4887Schin 	int len, offset=staktell();
1297*4887Schin 	if(!(flag&PATH_BFPATH))
1298*4887Schin 	{
1299*4887Schin 		register const char *cp = name;
1300*4887Schin 		while(*cp && *cp!=':')
1301*4887Schin 			stakputc(*cp++);
1302*4887Schin 		len = staktell()-offset;
1303*4887Schin 		stakputc(0);
1304*4887Schin 		stakseek(offset);
1305*4887Schin 		name = (const char*)stakptr(offset);
1306*4887Schin 	}
1307*4887Schin 	else
1308*4887Schin 		len = strlen(name);
1309*4887Schin 	for(pp=first; pp; pp=pp->next)
1310*4887Schin 	{
1311*4887Schin 		if(memcmp(name,pp->name,len)==0 && (pp->name[len]==':' || pp->name[len]==0))
1312*4887Schin 		{
1313*4887Schin 			pp->flags |= flag;
1314*4887Schin 			return(first);
1315*4887Schin 		}
1316*4887Schin 	}
1317*4887Schin 	if(old && (old=path_dirfind(old,name,0)))
1318*4887Schin 	{
1319*4887Schin 		statb.st_ino = old->ino;
1320*4887Schin 		statb.st_dev = old->dev;
1321*4887Schin 		if(old->ino==0 && old->dev==0)
1322*4887Schin 			flag |= PATH_SKIP;
1323*4887Schin 	}
1324*4887Schin 	else if(stat(name,&statb)<0 || !S_ISDIR(statb.st_mode))
1325*4887Schin 	{
1326*4887Schin 		if(*name=='/')
1327*4887Schin 		{
1328*4887Schin 			if(strcmp(name,SH_CMDLIB_DIR))
1329*4887Schin 				return(first);
1330*4887Schin 			statb.st_dev = 1;
1331*4887Schin 		}
1332*4887Schin 		else
1333*4887Schin 		{
1334*4887Schin 			flag |= PATH_SKIP;
1335*4887Schin 			statb.st_dev = 0;
1336*4887Schin 		}
1337*4887Schin 		statb.st_ino = 0;
1338*4887Schin 	}
1339*4887Schin 	if(*name=='/' && onstdpath(name))
1340*4887Schin 		flag |= PATH_STD_DIR;
1341*4887Schin 	for(pp=first, oldpp=0; pp; oldpp=pp, pp=pp->next)
1342*4887Schin 	{
1343*4887Schin 		if(pp->ino==statb.st_ino && pp->dev==statb.st_dev)
1344*4887Schin 		{
1345*4887Schin 			/* if both absolute paths, eliminate second */
1346*4887Schin 			pp->flags |= flag;
1347*4887Schin 			if(*name=='/' && *pp->name=='/')
1348*4887Schin 				return(first);
1349*4887Schin 			/* keep the path but mark it as skip */
1350*4887Schin 			flag |= PATH_SKIP;
1351*4887Schin 		}
1352*4887Schin 	}
1353*4887Schin 	pp = newof((Pathcomp_t*)0,Pathcomp_t,1,len+1);
1354*4887Schin 	pp->refcount = 1;
1355*4887Schin 	memcpy((char*)(pp+1),name,len+1);
1356*4887Schin 	pp->name = (char*)(pp+1);
1357*4887Schin 	pp->len = len;
1358*4887Schin 	pp->dev = statb.st_dev;
1359*4887Schin 	pp->ino = statb.st_ino;
1360*4887Schin 	if(oldpp)
1361*4887Schin 		oldpp->next = pp;
1362*4887Schin 	else
1363*4887Schin 		first = pp;
1364*4887Schin 	pp->flags = flag;
1365*4887Schin 	if(pp->ino==0 && pp->dev==1)
1366*4887Schin 	{
1367*4887Schin 		pp->flags |= PATH_BUILTIN_LIB;
1368*4887Schin 		pp->blib = malloc(4);
1369*4887Schin 		strcpy(pp->blib,LIBCMD);
1370*4887Schin 		return(first);
1371*4887Schin 	}
1372*4887Schin 	if((flag&(PATH_PATH|PATH_SKIP))==PATH_PATH)
1373*4887Schin 		path_chkpaths(first,old,pp,offset);
1374*4887Schin 	return(first);
1375*4887Schin }
1376*4887Schin 
1377*4887Schin /*
1378*4887Schin  * This function checks for the .paths file in directory in <pp>
1379*4887Schin  * it assumes that the directory is on the stack at <offset>
1380*4887Schin  */
1381*4887Schin static int path_chkpaths(Pathcomp_t *first, Pathcomp_t* old,Pathcomp_t *pp, int offset)
1382*4887Schin {
1383*4887Schin 	struct stat statb;
1384*4887Schin 	int k,m,n,fd;
1385*4887Schin 	char *sp,*cp,*ep;
1386*4887Schin 	stakseek(offset+pp->len);
1387*4887Schin 	if(pp->len==1 && *stakptr(offset)=='/')
1388*4887Schin 		stakseek(offset);
1389*4887Schin 	stakputs("/.paths");
1390*4887Schin 	if((fd=open(stakptr(offset),O_RDONLY))>=0)
1391*4887Schin 	{
1392*4887Schin 		fstat(fd,&statb);
1393*4887Schin 		n = statb.st_size;
1394*4887Schin 		stakseek(offset+pp->len+n+2);
1395*4887Schin 		sp = stakptr(offset+pp->len);
1396*4887Schin 		*sp++ = '/';
1397*4887Schin 		n=read(fd,cp=sp,n);
1398*4887Schin 		sp[n] = 0;
1399*4887Schin 		close(fd);
1400*4887Schin 		for(ep=0; n--; cp++)
1401*4887Schin 		{
1402*4887Schin 			if(*cp=='=')
1403*4887Schin 			{
1404*4887Schin 				ep = cp+1;
1405*4887Schin 				continue;
1406*4887Schin 			}
1407*4887Schin 			else if(*cp!='\r' &&  *cp!='\n')
1408*4887Schin 				continue;
1409*4887Schin 			if(*sp=='#' || sp==cp)
1410*4887Schin 			{
1411*4887Schin 				sp = cp+1;
1412*4887Schin 				continue;
1413*4887Schin 			}
1414*4887Schin 			*cp = 0;
1415*4887Schin 			m = ep ? (ep-sp) : 0;
1416*4887Schin 			if(!m || m==6 && memcmp((void*)sp,(void*)"FPATH=",6)==0)
1417*4887Schin 			{
1418*4887Schin 				if(first)
1419*4887Schin 				{
1420*4887Schin 					char *ptr = stakptr(offset+pp->len+1);
1421*4887Schin 					if(ep)
1422*4887Schin 						strcpy(ptr,ep);
1423*4887Schin 					path_addcomp(first,old,stakptr(offset),PATH_FPATH|PATH_BFPATH);
1424*4887Schin 				}
1425*4887Schin 			}
1426*4887Schin 			else if(m==12 && memcmp((void*)sp,(void*)"BUILTIN_LIB=",12)==0)
1427*4887Schin 			{
1428*4887Schin 				if(!(pp->flags & PATH_BUILTIN_LIB))
1429*4887Schin 				{
1430*4887Schin 					pp->flags |= PATH_BUILTIN_LIB;
1431*4887Schin 					if (*ep == '.' && !*(ep + 1))
1432*4887Schin 						pp->flags |= PATH_STD_DIR;
1433*4887Schin 					else
1434*4887Schin 					{
1435*4887Schin 						k = strlen(ep)+1;
1436*4887Schin 						if (*ep != '/')
1437*4887Schin 							k +=  pp->len+1;
1438*4887Schin 						pp->blib = sp = malloc(k);
1439*4887Schin 						if (*ep != '/')
1440*4887Schin 						{
1441*4887Schin 							strcpy(pp->blib,pp->name);
1442*4887Schin 							sp += pp->len;
1443*4887Schin 							*sp++ = '/';
1444*4887Schin 						}
1445*4887Schin 						strcpy(sp,ep);
1446*4887Schin 					}
1447*4887Schin 				}
1448*4887Schin 			}
1449*4887Schin 			else if(m)
1450*4887Schin 			{
1451*4887Schin 				pp->lib = (char*)malloc(cp-sp+pp->len+2);
1452*4887Schin 				memcpy((void*)pp->lib,(void*)sp,m);
1453*4887Schin 				memcpy((void*)&pp->lib[m],stakptr(offset),pp->len);
1454*4887Schin 				pp->lib[k=m+pp->len] = '/';
1455*4887Schin 				strcpy((void*)&pp->lib[k+1],ep);
1456*4887Schin 				pathcanon(&pp->lib[m],0);
1457*4887Schin 				if(!first)
1458*4887Schin 				{
1459*4887Schin 					stakseek(0);
1460*4887Schin 					stakputs(pp->lib);
1461*4887Schin 					free((void*)pp->lib);
1462*4887Schin 					return(1);
1463*4887Schin 				}
1464*4887Schin 			}
1465*4887Schin 			sp = cp+1;
1466*4887Schin 			ep = 0;
1467*4887Schin 		}
1468*4887Schin 	}
1469*4887Schin 	return(0);
1470*4887Schin }
1471*4887Schin 
1472*4887Schin 
1473*4887Schin Pathcomp_t *path_addpath(Pathcomp_t *first, register const char *path,int type)
1474*4887Schin {
1475*4887Schin 	register const char *cp;
1476*4887Schin 	Pathcomp_t *old=0;
1477*4887Schin 	int offset = staktell();
1478*4887Schin 	char *savptr;
1479*4887Schin 
1480*4887Schin 	if(!path && type!=PATH_PATH)
1481*4887Schin 		return(first);
1482*4887Schin 	if(type!=PATH_FPATH)
1483*4887Schin 	{
1484*4887Schin 		old = first;
1485*4887Schin 		first = 0;
1486*4887Schin 	}
1487*4887Schin 	if(offset)
1488*4887Schin 		savptr = stakfreeze(0);
1489*4887Schin 	if(path) while(*(cp=path))
1490*4887Schin 	{
1491*4887Schin 		if(*cp==':')
1492*4887Schin 		{
1493*4887Schin 			if(type!=PATH_FPATH)
1494*4887Schin 				first = path_addcomp(first,old,".",type);
1495*4887Schin 			while(*++path == ':');
1496*4887Schin 		}
1497*4887Schin 		else
1498*4887Schin 		{
1499*4887Schin 			int c;
1500*4887Schin 			while(*path && *path!=':')
1501*4887Schin 				path++;
1502*4887Schin 			c = *path++;
1503*4887Schin 			first = path_addcomp(first,old,cp,type);
1504*4887Schin 			if(c==0)
1505*4887Schin 				break;
1506*4887Schin 			if(*path==0)
1507*4887Schin 				path--;
1508*4887Schin 		}
1509*4887Schin 	}
1510*4887Schin 	if(old)
1511*4887Schin 	{
1512*4887Schin 		if(!first && !path)
1513*4887Schin 		{
1514*4887Schin 			Pathcomp_t *pp = (Pathcomp_t*)old->shp->defpathlist;
1515*4887Schin 			if(!pp)
1516*4887Schin 				pp = defpath_init(old->shp);
1517*4887Schin 			first = path_dup(pp);
1518*4887Schin 		}
1519*4887Schin 		if(cp=(FPATHNOD)->nvalue.cp)
1520*4887Schin 			first = (void*)path_addpath((Pathcomp_t*)first,cp,PATH_FPATH);
1521*4887Schin 		path_delete(old);
1522*4887Schin 	}
1523*4887Schin 	if(offset)
1524*4887Schin 		stakset(savptr,offset);
1525*4887Schin 	else
1526*4887Schin 		stakseek(0);
1527*4887Schin 	return(first);
1528*4887Schin }
1529*4887Schin 
1530*4887Schin /*
1531*4887Schin  * duplicate the path give by <first> by incremented reference counts
1532*4887Schin  */
1533*4887Schin Pathcomp_t *path_dup(Pathcomp_t *first)
1534*4887Schin {
1535*4887Schin 	register Pathcomp_t *pp=first;
1536*4887Schin 	while(pp)
1537*4887Schin 	{
1538*4887Schin 		pp->refcount++;
1539*4887Schin 		pp = pp->next;
1540*4887Schin 	}
1541*4887Schin 	return(first);
1542*4887Schin }
1543*4887Schin 
1544*4887Schin /*
1545*4887Schin  * called whenever the directory is changed
1546*4887Schin  */
1547*4887Schin void path_newdir(Pathcomp_t *first)
1548*4887Schin {
1549*4887Schin 	register Pathcomp_t *pp=first, *next, *pq;
1550*4887Schin 	struct stat statb;
1551*4887Schin 	for(pp=first; pp; pp=pp->next)
1552*4887Schin 	{
1553*4887Schin 		pp->flags &= ~PATH_SKIP;
1554*4887Schin 		if(*pp->name=='/')
1555*4887Schin 			continue;
1556*4887Schin 		/* delete .paths component */
1557*4887Schin 		if((next=pp->next) && (next->flags&PATH_BFPATH))
1558*4887Schin 		{
1559*4887Schin 			pp->next = next->next;
1560*4887Schin 			if(--next->refcount<=0)
1561*4887Schin 				free((void*)next);
1562*4887Schin 		}
1563*4887Schin 		if(stat(pp->name,&statb)<0 || !S_ISDIR(statb.st_mode))
1564*4887Schin 		{
1565*4887Schin 			pp->dev = 0;
1566*4887Schin 			pp->ino = 0;
1567*4887Schin 			continue;
1568*4887Schin 		}
1569*4887Schin 		pp->dev = statb.st_dev;
1570*4887Schin 		pp->ino = statb.st_ino;
1571*4887Schin 		for(pq=first;pq!=pp;pq=pq->next)
1572*4887Schin 		{
1573*4887Schin 			if(pp->ino==pq->ino && pp->dev==pq->dev)
1574*4887Schin 				pp->flags |= PATH_SKIP;
1575*4887Schin 		}
1576*4887Schin 		for(pq=pp;pq=pq->next;)
1577*4887Schin 		{
1578*4887Schin 			if(pp->ino==pq->ino && pp->dev==pq->dev)
1579*4887Schin 				pq->flags |= PATH_SKIP;
1580*4887Schin 		}
1581*4887Schin 		if((pp->flags&(PATH_PATH|PATH_SKIP))==PATH_PATH)
1582*4887Schin 		{
1583*4887Schin 			/* try to insert .paths component */
1584*4887Schin 			int offset = staktell();
1585*4887Schin 			stakputs(pp->name);
1586*4887Schin 			stakseek(offset);
1587*4887Schin 			next = pp->next;
1588*4887Schin 			pp->next = 0;
1589*4887Schin 			path_chkpaths(first,(Pathcomp_t*)0,pp,offset);
1590*4887Schin 			if(pp->next)
1591*4887Schin 				pp = pp->next;
1592*4887Schin 			pp->next = next;
1593*4887Schin 		}
1594*4887Schin 	}
1595*4887Schin #if 0
1596*4887Schin 	path_dump(first);
1597*4887Schin #endif
1598*4887Schin }
1599*4887Schin 
1600*4887Schin Pathcomp_t *path_unsetfpath(Pathcomp_t *first)
1601*4887Schin {
1602*4887Schin 	register Pathcomp_t *pp=first, *old=0;
1603*4887Schin 	while(pp)
1604*4887Schin 	{
1605*4887Schin 		if((pp->flags&PATH_FPATH) && !(pp->flags&PATH_BFPATH))
1606*4887Schin 		{
1607*4887Schin 			if(pp->flags&PATH_PATH)
1608*4887Schin 				pp->flags &= ~PATH_FPATH;
1609*4887Schin 			else
1610*4887Schin 			{
1611*4887Schin 				Pathcomp_t *ppsave=pp;
1612*4887Schin 				if(old)
1613*4887Schin 					old->next = pp->next;
1614*4887Schin 				else
1615*4887Schin 					first = pp->next;
1616*4887Schin 				pp = pp->next;
1617*4887Schin 				if(--ppsave->refcount<=0)
1618*4887Schin 				{
1619*4887Schin 					if(ppsave->lib)
1620*4887Schin 						free((void*)ppsave->lib);
1621*4887Schin 					free((void*)ppsave);
1622*4887Schin 				}
1623*4887Schin 				continue;
1624*4887Schin 			}
1625*4887Schin 
1626*4887Schin 		}
1627*4887Schin 		old = pp;
1628*4887Schin 		pp = pp->next;
1629*4887Schin 	}
1630*4887Schin 	return(first);
1631*4887Schin }
1632*4887Schin 
1633*4887Schin Pathcomp_t *path_dirfind(Pathcomp_t *first,const char *name,int c)
1634*4887Schin {
1635*4887Schin 	register Pathcomp_t *pp=first;
1636*4887Schin 	while(pp)
1637*4887Schin 	{
1638*4887Schin 		if(memcmp(name,pp->name,pp->len)==0 && name[pp->len]==c)
1639*4887Schin 			return(pp);
1640*4887Schin 		pp = pp->next;
1641*4887Schin 	}
1642*4887Schin 	return(0);
1643*4887Schin }
1644*4887Schin 
1645*4887Schin /*
1646*4887Schin  * get discipline for tracked alias
1647*4887Schin  */
1648*4887Schin static char *talias_get(Namval_t *np, Namfun_t *nvp)
1649*4887Schin {
1650*4887Schin 	Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp;
1651*4887Schin 	char *ptr;
1652*4887Schin 	if(!pp)
1653*4887Schin 		return(NULL);
1654*4887Schin 	path_nextcomp(pp,nv_name(np),pp);
1655*4887Schin 	ptr = stakfreeze(0);
1656*4887Schin 	return(ptr+PATH_OFFSET);
1657*4887Schin }
1658*4887Schin 
1659*4887Schin static void talias_put(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
1660*4887Schin {
1661*4887Schin 	if(!val && np->nvalue.cp)
1662*4887Schin 	{
1663*4887Schin 		Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp;
1664*4887Schin 		if(--pp->refcount<=0)
1665*4887Schin 			free((void*)pp);
1666*4887Schin 	}
1667*4887Schin 	nv_putv(np,val,flags,fp);
1668*4887Schin }
1669*4887Schin 
1670*4887Schin static const Namdisc_t talias_disc   = { 0, talias_put, talias_get   };
1671*4887Schin static Namfun_t  talias_init = { &talias_disc, 1 };
1672*4887Schin 
1673*4887Schin /*
1674*4887Schin  *  set tracked alias node <np> to value <pp>
1675*4887Schin  */
1676*4887Schin void path_alias(register Namval_t *np,register Pathcomp_t *pp)
1677*4887Schin {
1678*4887Schin 	if(pp)
1679*4887Schin 	{
1680*4887Schin 		struct stat statb;
1681*4887Schin 		char *sp;
1682*4887Schin 		nv_offattr(np,NV_NOPRINT);
1683*4887Schin 		nv_stack(np,&talias_init);
1684*4887Schin 		np->nvalue.cp = (char*)pp;
1685*4887Schin 		pp->refcount++;
1686*4887Schin 		nv_setattr(np,NV_TAGGED|NV_NOFREE);
1687*4887Schin 		path_nextcomp(pp,nv_name(np),pp);
1688*4887Schin 		sp = stakptr(PATH_OFFSET);
1689*4887Schin 		if(sp && lstat(sp,&statb)>=0 && S_ISLNK(statb.st_mode))
1690*4887Schin 			nv_setsize(np,statb.st_size+1);
1691*4887Schin 		else
1692*4887Schin 			nv_setsize(np,0);
1693*4887Schin 	}
1694*4887Schin 	else
1695*4887Schin 		nv_unset(np);
1696*4887Schin }
1697*4887Schin 
1698