xref: /titanic_51/usr/src/lib/libshell/common/sh/path.c (revision 3ce7283d71d01ba5f0245dc25366a3791a324d04)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
43e14f97fSRoger A. Faulkner *          Copyright (c) 1982-2010 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6da2e3ebdSchin *                  Common Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
18da2e3ebdSchin *                                                                      *
19da2e3ebdSchin ***********************************************************************/
20da2e3ebdSchin #pragma prototyped
21da2e3ebdSchin /*
22da2e3ebdSchin  * David Korn
23da2e3ebdSchin  * AT&T Labs
24da2e3ebdSchin  *
25da2e3ebdSchin  */
26da2e3ebdSchin 
27da2e3ebdSchin #include	"defs.h"
28da2e3ebdSchin #include	<fcin.h>
29da2e3ebdSchin #include	<ls.h>
30da2e3ebdSchin #include	<nval.h>
31da2e3ebdSchin #include	"variables.h"
32da2e3ebdSchin #include	"path.h"
33da2e3ebdSchin #include	"io.h"
34da2e3ebdSchin #include	"jobs.h"
35da2e3ebdSchin #include	"history.h"
36da2e3ebdSchin #include	"test.h"
377c2fbfb3SApril Chin #include	"FEATURE/dynamic"
38da2e3ebdSchin #include	"FEATURE/externs"
39da2e3ebdSchin #if SHOPT_PFSH
40da2e3ebdSchin #   ifdef _hdr_exec_attr
41da2e3ebdSchin #	include	<exec_attr.h>
42da2e3ebdSchin #   endif
437c2fbfb3SApril Chin #   if     _lib_vfork
447c2fbfb3SApril Chin #	include     <ast_vfork.h>
457c2fbfb3SApril Chin #   else
467c2fbfb3SApril Chin #	define vfork()      fork()
477c2fbfb3SApril Chin #   endif
48da2e3ebdSchin #endif
49da2e3ebdSchin 
50da2e3ebdSchin #define RW_ALL	(S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH)
51da2e3ebdSchin #define LIBCMD	"cmd"
52da2e3ebdSchin 
53da2e3ebdSchin 
54da2e3ebdSchin static int		canexecute(char*,int);
55da2e3ebdSchin static void		funload(Shell_t*,int,const char*);
56da2e3ebdSchin static void		exscript(Shell_t*,char*, char*[], char**);
57da2e3ebdSchin static int		path_chkpaths(Pathcomp_t*,Pathcomp_t*,Pathcomp_t*,int);
5834f9b3eeSRoland Mainz static void		path_checkdup(register Pathcomp_t*);
59da2e3ebdSchin 
60da2e3ebdSchin static const char	*std_path;
61da2e3ebdSchin 
onstdpath(const char * name)62da2e3ebdSchin static int onstdpath(const char *name)
63da2e3ebdSchin {
64da2e3ebdSchin 	register const char *cp = std_path, *sp;
65da2e3ebdSchin 	if(cp)
66da2e3ebdSchin 		while(*cp)
67da2e3ebdSchin 		{
68da2e3ebdSchin 			for(sp=name; *sp && (*cp == *sp); sp++,cp++);
69da2e3ebdSchin 			if(*sp==0 && (*cp==0 || *cp==':'))
70da2e3ebdSchin 				return(1);
71da2e3ebdSchin 			while(*cp && *cp++!=':');
72da2e3ebdSchin 		}
73da2e3ebdSchin 	return(0);
74da2e3ebdSchin }
75da2e3ebdSchin 
path_pfexecve(const char * path,char * argv[],char * const envp[],int spawn)767c2fbfb3SApril Chin static pid_t path_pfexecve(const char *path, char *argv[],char *const envp[],int spawn)
77da2e3ebdSchin {
78da2e3ebdSchin #if SHOPT_PFSH
797c2fbfb3SApril Chin 	pid_t	pid;
80da2e3ebdSchin 	char  resolvedpath[PATH_MAX + 1];
817c2fbfb3SApril Chin 	if(spawn)
827c2fbfb3SApril Chin 	{
837c2fbfb3SApril Chin 		while((pid = vfork()) < 0)
847c2fbfb3SApril Chin 			_sh_fork(pid, 0, (int*)0);
857c2fbfb3SApril Chin 		if(pid)
867c2fbfb3SApril Chin 			return(pid);
877c2fbfb3SApril Chin 	}
88da2e3ebdSchin 	if(!sh_isoption(SH_PFSH))
89da2e3ebdSchin 		return(execve(path, argv, envp));
90da2e3ebdSchin 	/* Solaris implements realpath(3C) using the resolvepath(2) */
91da2e3ebdSchin 	/* system call so we can save us to call access(2) first */
92da2e3ebdSchin 	if (!realpath(path, resolvedpath))
93da2e3ebdSchin 		return -1;
94da2e3ebdSchin 
95da2e3ebdSchin 	/* we can exec the command directly instead of via pfexec(1) if */
96da2e3ebdSchin 	/* there is a matching entry without attributes in exec_attr(4) */
97da2e3ebdSchin 	if (sh.user && *sh.user)
98da2e3ebdSchin 	{
99da2e3ebdSchin 		execattr_t *pf;
100da2e3ebdSchin 		if(pf=getexecuser(sh.user, KV_COMMAND, resolvedpath, GET_ONE))
101da2e3ebdSchin 		{
102da2e3ebdSchin 			if (!pf->attr || pf->attr->length == 0)
103da2e3ebdSchin 			{
104da2e3ebdSchin 				int r = execve(path, argv, envp);
105da2e3ebdSchin 				free_execattr(pf);
106da2e3ebdSchin 				return r;
107da2e3ebdSchin 			}
108da2e3ebdSchin 			free_execattr(pf);
109da2e3ebdSchin 		}
110da2e3ebdSchin 		else
111da2e3ebdSchin 		{
112da2e3ebdSchin 			errno = ENOENT;
113da2e3ebdSchin 			return -1;
114da2e3ebdSchin 		}
115da2e3ebdSchin 	}
116da2e3ebdSchin 	--argv;
117da2e3ebdSchin 	argv[0] = argv[1];
118da2e3ebdSchin 	argv[1] = resolvedpath;
119da2e3ebdSchin 	return(execve("/usr/bin/pfexec", argv, envp));
120da2e3ebdSchin #else
121da2e3ebdSchin 	return(execve(path, argv, envp));
122da2e3ebdSchin #endif
123da2e3ebdSchin }
124da2e3ebdSchin 
125da2e3ebdSchin 
_spawnveg(const char * path,char * const argv[],char * const envp[],pid_t pgid)1267c2fbfb3SApril Chin static pid_t _spawnveg(const char *path, char* const argv[], char* const envp[], pid_t pgid)
127da2e3ebdSchin {
128da2e3ebdSchin 	int waitsafe = job.waitsafe;
1297c2fbfb3SApril Chin 	pid_t pid;
130da2e3ebdSchin 	job_lock();
1317c2fbfb3SApril Chin 	while(1)
1327c2fbfb3SApril Chin 	{
1337c2fbfb3SApril Chin 		sh_stats(STAT_SPAWN);
1347c2fbfb3SApril Chin 		pid = spawnveg(path,argv,envp,pgid);
1357c2fbfb3SApril Chin 		if(pid>=0 || errno!=EAGAIN)
1367c2fbfb3SApril Chin 			break;
1377c2fbfb3SApril Chin 		_sh_fork(pid, 0, (int*)0);
1387c2fbfb3SApril Chin 	}
139da2e3ebdSchin 	job.waitsafe = waitsafe;
1403e14f97fSRoger A. Faulkner 	if(pid>0)
1413e14f97fSRoger A. Faulkner 		job_fork(pid);
1423e14f97fSRoger A. Faulkner 	else
143da2e3ebdSchin 		job_unlock();
144da2e3ebdSchin 	return(pid);
145da2e3ebdSchin }
146da2e3ebdSchin /*
147da2e3ebdSchin  * used with command -x to run the command in multiple passes
148da2e3ebdSchin  * spawn is non-zero when invoked via spawn
149da2e3ebdSchin  * the exitval is set to the maximum for each execution
150da2e3ebdSchin  */
path_xargs(const char * path,char * argv[],char * const envp[],int spawn)151da2e3ebdSchin static pid_t path_xargs(const char *path, char *argv[],char *const envp[], int spawn)
152da2e3ebdSchin {
153da2e3ebdSchin 	register char *cp, **av, **xv;
154da2e3ebdSchin 	char **avlast= &argv[sh.xargmax], **saveargs=0;
155da2e3ebdSchin 	char *const *ev;
156da2e3ebdSchin 	long size, left;
157da2e3ebdSchin 	int nlast=1,n,exitval=0;
158da2e3ebdSchin 	pid_t pid;
159da2e3ebdSchin 	if(sh.xargmin < 0)
160da2e3ebdSchin 		return((pid_t)-1);
161da2e3ebdSchin 	size = sh.lim.arg_max-1024;
162da2e3ebdSchin 	for(ev=envp; cp= *ev; ev++)
163da2e3ebdSchin 		size -= strlen(cp)-1;
164da2e3ebdSchin 	for(av=argv; (cp= *av) && av< &argv[sh.xargmin]; av++)
165da2e3ebdSchin 		size -= strlen(cp)-1;
166da2e3ebdSchin 	for(av=avlast; cp= *av; av++,nlast++)
167da2e3ebdSchin 		size -= strlen(cp)-1;
168da2e3ebdSchin 	av =  &argv[sh.xargmin];
169da2e3ebdSchin 	if(!spawn)
170da2e3ebdSchin 		job_clear();
171da2e3ebdSchin 	sh.exitval = 0;
172da2e3ebdSchin 	while(av<avlast)
173da2e3ebdSchin 	{
174da2e3ebdSchin 		for(xv=av,left=size; left>0 && av<avlast;)
175da2e3ebdSchin 			left -= strlen(*av++)+1;
176da2e3ebdSchin 		/* leave at least two for last */
177da2e3ebdSchin 		if(left<0 && (avlast-av)<2)
178da2e3ebdSchin 			av--;
179da2e3ebdSchin 		if(xv==&argv[sh.xargmin])
180da2e3ebdSchin 		{
181da2e3ebdSchin 			n = nlast*sizeof(char*);
182da2e3ebdSchin 			saveargs = (char**)malloc(n);
183da2e3ebdSchin 			memcpy((void*)saveargs, (void*)av, n);
184da2e3ebdSchin 			memcpy((void*)av,(void*)avlast,n);
185da2e3ebdSchin 		}
186da2e3ebdSchin 		else
187da2e3ebdSchin 		{
188da2e3ebdSchin 			for(n=sh.xargmin; xv < av; xv++)
189da2e3ebdSchin 				argv[n++] = *xv;
190da2e3ebdSchin 			for(xv=avlast; cp=  *xv; xv++)
191da2e3ebdSchin 				argv[n++] = cp;
192da2e3ebdSchin 			argv[n] = 0;
193da2e3ebdSchin 		}
194da2e3ebdSchin 		if(saveargs || av<avlast || (exitval && !spawn))
195da2e3ebdSchin 		{
196da2e3ebdSchin 			if((pid=_spawnveg(path,argv,envp,0)) < 0)
197da2e3ebdSchin 				return(-1);
198da2e3ebdSchin 			job_post(pid,0);
199da2e3ebdSchin 			job_wait(pid);
200da2e3ebdSchin 			if(sh.exitval>exitval)
201da2e3ebdSchin 				exitval = sh.exitval;
202da2e3ebdSchin 			if(saveargs)
203da2e3ebdSchin 			{
204da2e3ebdSchin 				memcpy((void*)av,saveargs,n);
205da2e3ebdSchin 				free((void*)saveargs);
206da2e3ebdSchin 				saveargs = 0;
207da2e3ebdSchin 			}
208da2e3ebdSchin 		}
209da2e3ebdSchin 		else if(spawn && !sh_isoption(SH_PFSH))
210da2e3ebdSchin 		{
211da2e3ebdSchin 			sh.xargexit = exitval;
212da2e3ebdSchin 			return(_spawnveg(path,argv,envp,spawn>>1));
213da2e3ebdSchin 		}
214da2e3ebdSchin 		else
2157c2fbfb3SApril Chin 			return(path_pfexecve(path,argv,envp,spawn));
216da2e3ebdSchin 	}
217da2e3ebdSchin 	if(!spawn)
218da2e3ebdSchin 		exit(exitval);
219da2e3ebdSchin 	return((pid_t)-1);
220da2e3ebdSchin }
221da2e3ebdSchin 
222da2e3ebdSchin /*
223da2e3ebdSchin  * make sure PWD is set up correctly
224da2e3ebdSchin  * Return the present working directory
225da2e3ebdSchin  * Invokes getcwd() if flag==0 and if necessary
226da2e3ebdSchin  * Sets the PWD variable to this value
227da2e3ebdSchin  */
path_pwd(int flag)228da2e3ebdSchin char *path_pwd(int flag)
229da2e3ebdSchin {
230da2e3ebdSchin 	register char *cp;
231da2e3ebdSchin 	register char *dfault = (char*)e_dot;
232da2e3ebdSchin 	register int count = 0;
233da2e3ebdSchin 	Shell_t *shp = &sh;
234da2e3ebdSchin 	if(shp->pwd)
235da2e3ebdSchin 		return((char*)shp->pwd);
236da2e3ebdSchin 	while(1)
237da2e3ebdSchin 	{
238da2e3ebdSchin 		/* try from lowest to highest */
239da2e3ebdSchin 		switch(count++)
240da2e3ebdSchin 		{
241da2e3ebdSchin 			case 0:
242da2e3ebdSchin 				cp = nv_getval(PWDNOD);
243da2e3ebdSchin 				break;
244da2e3ebdSchin 			case 1:
245da2e3ebdSchin 				cp = nv_getval(HOME);
246da2e3ebdSchin 				break;
247da2e3ebdSchin 			case 2:
248da2e3ebdSchin 				cp = "/";
249da2e3ebdSchin 				break;
250da2e3ebdSchin 			case 3:
251da2e3ebdSchin 				cp = (char*)e_crondir;
252da2e3ebdSchin 				if(flag) /* skip next case when non-zero flag */
253da2e3ebdSchin 					++count;
254da2e3ebdSchin 				break;
255da2e3ebdSchin 			case 4:
256da2e3ebdSchin 			{
257da2e3ebdSchin 				if(cp=getcwd(NIL(char*),0))
258da2e3ebdSchin 				{
259da2e3ebdSchin 					nv_offattr(PWDNOD,NV_NOFREE);
260da2e3ebdSchin 					nv_unset(PWDNOD);
261da2e3ebdSchin 					PWDNOD->nvalue.cp = cp;
262da2e3ebdSchin 					goto skip;
263da2e3ebdSchin 				}
264da2e3ebdSchin 				break;
265da2e3ebdSchin 			}
266da2e3ebdSchin 			case 5:
267da2e3ebdSchin 				return(dfault);
268da2e3ebdSchin 		}
269da2e3ebdSchin 		if(cp && *cp=='/' && test_inode(cp,e_dot))
270da2e3ebdSchin 			break;
271da2e3ebdSchin 	}
272da2e3ebdSchin 	if(count>1)
273da2e3ebdSchin 	{
274da2e3ebdSchin 		nv_offattr(PWDNOD,NV_NOFREE);
275da2e3ebdSchin 		nv_putval(PWDNOD,cp,NV_RDONLY);
276da2e3ebdSchin 	}
277da2e3ebdSchin skip:
278da2e3ebdSchin 	nv_onattr(PWDNOD,NV_NOFREE|NV_EXPORT);
279da2e3ebdSchin 	shp->pwd = (char*)(PWDNOD->nvalue.cp);
280da2e3ebdSchin 	return(cp);
281da2e3ebdSchin }
282da2e3ebdSchin 
free_bltin(Namval_t * np,void * data)283da2e3ebdSchin static void free_bltin(Namval_t *np,void *data)
284da2e3ebdSchin {
285da2e3ebdSchin 	register Pathcomp_t *pp= (Pathcomp_t*)data;
286da2e3ebdSchin 	if(pp->flags&PATH_STD_DIR)
287da2e3ebdSchin 	{
288da2e3ebdSchin 		int offset=staktell();;
289da2e3ebdSchin 		if(strcmp(pp->name,"/bin")==0 || memcmp(pp->name,np->nvname,pp->len) || np->nvname[pp->len]!='/')
290da2e3ebdSchin 			return;
291da2e3ebdSchin 		stakputs("/bin");
292da2e3ebdSchin 		stakputs(np->nvname+pp->len+1);
293da2e3ebdSchin 		stakputc(0);
294da2e3ebdSchin 		sh_addbuiltin(stakptr(offset),np->nvalue.bfp,NiL);
295da2e3ebdSchin 		stakseek(offset);
296da2e3ebdSchin 		return;
297da2e3ebdSchin 	}
298da2e3ebdSchin 	if((void*)np->nvenv==pp->bltin_lib)
2997c2fbfb3SApril Chin 		nv_delete(np,sh_bltin_tree(),NV_NOFREE);
300da2e3ebdSchin }
301da2e3ebdSchin 
302da2e3ebdSchin /*
303da2e3ebdSchin  * delete current Pathcomp_t structure
304da2e3ebdSchin  */
path_delete(Pathcomp_t * first)305da2e3ebdSchin void  path_delete(Pathcomp_t *first)
306da2e3ebdSchin {
307da2e3ebdSchin 	register Pathcomp_t *pp=first, *old=0, *ppnext;
308da2e3ebdSchin 	while(pp)
309da2e3ebdSchin 	{
310da2e3ebdSchin 		ppnext = pp->next;
311da2e3ebdSchin 		if(--pp->refcount<=0)
312da2e3ebdSchin 		{
313da2e3ebdSchin 			if(pp->lib)
314da2e3ebdSchin 				free((void*)pp->lib);
315da2e3ebdSchin 			if(pp->blib)
316da2e3ebdSchin 				free((void*)pp->blib);
317da2e3ebdSchin 			if(pp->bltin_lib || (pp->flags&PATH_STD_DIR))
318da2e3ebdSchin 			{
319da2e3ebdSchin 				nv_scan(sh_bltin_tree(),free_bltin,pp,0,0);
3207c2fbfb3SApril Chin #if SHOPT_DYNAMIC
321da2e3ebdSchin 				if(pp->bltin_lib)
322da2e3ebdSchin 					dlclose(pp->bltin_lib);
3237c2fbfb3SApril Chin #endif /* SHOPT_DYNAMIC */
324da2e3ebdSchin 			}
325da2e3ebdSchin 			free((void*)pp);
326da2e3ebdSchin 			if(old)
327da2e3ebdSchin 				old->next = ppnext;
328da2e3ebdSchin 		}
329da2e3ebdSchin 		else
330da2e3ebdSchin 			old = pp;
331da2e3ebdSchin 		pp = ppnext;
332da2e3ebdSchin 	}
333da2e3ebdSchin }
334da2e3ebdSchin 
335da2e3ebdSchin /*
336da2e3ebdSchin  * returns library variable from .paths
337da2e3ebdSchin  * The value might be returned on the stack overwriting path
338da2e3ebdSchin  */
path_lib(Pathcomp_t * pp,char * path)339da2e3ebdSchin static char *path_lib(Pathcomp_t *pp, char *path)
340da2e3ebdSchin {
341da2e3ebdSchin 	register char *last = strrchr(path,'/');
342da2e3ebdSchin 	register int r;
343da2e3ebdSchin 	struct stat statb;
344da2e3ebdSchin 	if(last)
345da2e3ebdSchin 		*last = 0;
346da2e3ebdSchin 	else
347da2e3ebdSchin 		path = ".";
348da2e3ebdSchin 	r = stat(path,&statb);
349da2e3ebdSchin 	if(last)
350da2e3ebdSchin 		*last = '/';
351da2e3ebdSchin 	if(r>=0)
352da2e3ebdSchin 	{
353da2e3ebdSchin 		Pathcomp_t pcomp;
354da2e3ebdSchin 		char save[8];
355da2e3ebdSchin 		for( ;pp; pp=pp->next)
356da2e3ebdSchin 		{
35734f9b3eeSRoland Mainz 			path_checkdup(pp);
3587c2fbfb3SApril Chin 			if(pp->ino==statb.st_ino && pp->dev==statb.st_dev && pp->mtime==statb.st_mtime)
359da2e3ebdSchin 				return(pp->lib);
360da2e3ebdSchin 		}
361da2e3ebdSchin 		pcomp.len = 0;
362da2e3ebdSchin 		if(last)
363da2e3ebdSchin 			pcomp.len = last-path;
364da2e3ebdSchin 		memcpy((void*)save, (void*)stakptr(PATH_OFFSET+pcomp.len),sizeof(save));
365da2e3ebdSchin 		if(path_chkpaths((Pathcomp_t*)0,(Pathcomp_t*)0,&pcomp,PATH_OFFSET))
366da2e3ebdSchin 			return(stakfreeze(1));
367da2e3ebdSchin 		memcpy((void*)stakptr(PATH_OFFSET+pcomp.len),(void*)save,sizeof(save));
368da2e3ebdSchin 	}
369da2e3ebdSchin 	return(0);
370da2e3ebdSchin }
371da2e3ebdSchin 
372da2e3ebdSchin #if 0
373da2e3ebdSchin void path_dump(register Pathcomp_t *pp)
374da2e3ebdSchin {
375da2e3ebdSchin 	sfprintf(sfstderr,"dump\n");
376da2e3ebdSchin 	while(pp)
377da2e3ebdSchin 	{
378da2e3ebdSchin 		sfprintf(sfstderr,"pp=%x dev=%d ino=%d len=%d flags=%o name=%.*s\n",
379da2e3ebdSchin 			pp,pp->dev,pp->ino,pp->len,pp->flags,pp->len,pp->name);
380da2e3ebdSchin 		pp = pp->next;
381da2e3ebdSchin 	}
382da2e3ebdSchin }
383da2e3ebdSchin #endif
384da2e3ebdSchin 
385da2e3ebdSchin /*
38634f9b3eeSRoland Mainz  * check for duplicate directories on PATH
38734f9b3eeSRoland Mainz  */
path_checkdup(register Pathcomp_t * pp)38834f9b3eeSRoland Mainz static void path_checkdup(register Pathcomp_t *pp)
38934f9b3eeSRoland Mainz {
39034f9b3eeSRoland Mainz 	register char		*name = pp->name;
39134f9b3eeSRoland Mainz 	register Pathcomp_t	*oldpp,*first;
39234f9b3eeSRoland Mainz 	register int		flag=0;
39334f9b3eeSRoland Mainz 	struct stat 		statb;
39434f9b3eeSRoland Mainz 	if(stat(name,&statb)<0 || !S_ISDIR(statb.st_mode))
39534f9b3eeSRoland Mainz 	{
39634f9b3eeSRoland Mainz 		pp->flags |= PATH_SKIP;
39734f9b3eeSRoland Mainz 		pp->dev = *name=='/';
39834f9b3eeSRoland Mainz 		return;
39934f9b3eeSRoland Mainz 	}
40034f9b3eeSRoland Mainz 	pp->mtime = statb.st_mtime;
40134f9b3eeSRoland Mainz 	pp->ino = statb.st_ino;
40234f9b3eeSRoland Mainz 	pp->dev = statb.st_dev;
40334f9b3eeSRoland Mainz 	if(*name=='/' && onstdpath(name))
40434f9b3eeSRoland Mainz 		flag = PATH_STD_DIR;
40534f9b3eeSRoland Mainz 	first = (pp->flags&PATH_CDPATH)?pp->shp->cdpathlist:path_get("");
40634f9b3eeSRoland Mainz 	for(oldpp=first; oldpp && oldpp!=pp; oldpp=oldpp->next)
40734f9b3eeSRoland Mainz 	{
40834f9b3eeSRoland Mainz 		if(pp->ino==oldpp->ino && pp->dev==oldpp->dev && pp->mtime==oldpp->mtime)
40934f9b3eeSRoland Mainz 		{
41034f9b3eeSRoland Mainz 			flag |= PATH_SKIP;
41134f9b3eeSRoland Mainz 			break;
41234f9b3eeSRoland Mainz 		}
41334f9b3eeSRoland Mainz 	}
41434f9b3eeSRoland Mainz 	pp->flags |= flag;
41534f9b3eeSRoland Mainz 	if(((pp->flags&(PATH_PATH|PATH_SKIP))==PATH_PATH))
41634f9b3eeSRoland Mainz 	{
41734f9b3eeSRoland Mainz 		int offset = staktell();
41834f9b3eeSRoland Mainz 		stakputs(name);
41934f9b3eeSRoland Mainz 		path_chkpaths(first,0,pp,offset);
42034f9b3eeSRoland Mainz 		stakseek(offset);
42134f9b3eeSRoland Mainz 	}
42234f9b3eeSRoland Mainz }
42334f9b3eeSRoland Mainz 
42434f9b3eeSRoland Mainz /*
425da2e3ebdSchin  * write the next path to search on the current stack
426da2e3ebdSchin  * if last is given, all paths that come before <last> are skipped
427da2e3ebdSchin  * the next pathcomp is returned.
428da2e3ebdSchin  */
path_nextcomp(register Pathcomp_t * pp,const char * name,Pathcomp_t * last)429da2e3ebdSchin Pathcomp_t *path_nextcomp(register Pathcomp_t *pp, const char *name, Pathcomp_t *last)
430da2e3ebdSchin {
43134f9b3eeSRoland Mainz 	Pathcomp_t	*ppnext;
432da2e3ebdSchin 	stakseek(PATH_OFFSET);
433da2e3ebdSchin 	if(*name=='/')
434da2e3ebdSchin 		pp = 0;
435da2e3ebdSchin 	else
436da2e3ebdSchin 	{
43734f9b3eeSRoland Mainz 		for(;pp && pp!=last;pp=ppnext)
438da2e3ebdSchin 		{
43934f9b3eeSRoland Mainz 			if(ppnext=pp->next)
44034f9b3eeSRoland Mainz 				ppnext->shp = pp->shp;
44134f9b3eeSRoland Mainz 			if(!pp->dev && !pp->ino)
44234f9b3eeSRoland Mainz 				path_checkdup(pp);
443da2e3ebdSchin 			if(pp->flags&PATH_SKIP)
444da2e3ebdSchin 				continue;
445da2e3ebdSchin 			if(!last || *pp->name!='/')
446da2e3ebdSchin 				break;
447da2e3ebdSchin 		}
448da2e3ebdSchin 		if(!pp)		/* this should not happen */
449da2e3ebdSchin 			pp = last;
450da2e3ebdSchin 	}
451da2e3ebdSchin 	if(pp && (pp->name[0]!='.' || pp->name[1]))
452da2e3ebdSchin 	{
453da2e3ebdSchin 		if(*pp->name!='/')
454da2e3ebdSchin 		{
455da2e3ebdSchin 			stakputs(path_pwd(1));
456da2e3ebdSchin 			if(*stakptr(staktell()-1)!='/')
457da2e3ebdSchin 				stakputc('/');
458da2e3ebdSchin 		}
459da2e3ebdSchin 		stakwrite(pp->name,pp->len);
460da2e3ebdSchin 		if(pp->name[pp->len-1]!='/')
461da2e3ebdSchin 			stakputc('/');
462da2e3ebdSchin 	}
463da2e3ebdSchin 	stakputs(name);
464da2e3ebdSchin 	stakputc(0);
465da2e3ebdSchin 	while(pp && pp!=last && (pp=pp->next))
466da2e3ebdSchin 	{
467da2e3ebdSchin 		if(!(pp->flags&PATH_SKIP))
468da2e3ebdSchin 			return(pp);
469da2e3ebdSchin 	}
470da2e3ebdSchin 	return((Pathcomp_t*)0);
471da2e3ebdSchin }
472da2e3ebdSchin 
defpath_init(Shell_t * shp)473da2e3ebdSchin static Pathcomp_t* defpath_init(Shell_t *shp)
474da2e3ebdSchin {
475da2e3ebdSchin 	Pathcomp_t *pp = (void*)path_addpath((Pathcomp_t*)0,(std_path),PATH_PATH);
476da2e3ebdSchin 	if(shp->defpathlist = (void*)pp)
477da2e3ebdSchin 		pp->shp = shp;
478da2e3ebdSchin 	return(pp);
479da2e3ebdSchin }
480da2e3ebdSchin 
path_init(Shell_t * shp)481da2e3ebdSchin static void path_init(Shell_t *shp)
482da2e3ebdSchin {
483da2e3ebdSchin 	const char *val;
484da2e3ebdSchin 	Pathcomp_t *pp;
485da2e3ebdSchin 	if(!std_path && !(std_path=astconf("PATH",NIL(char*),NIL(char*))))
486da2e3ebdSchin 		std_path = e_defpath;
4877c2fbfb3SApril Chin 	if(val=sh_scoped(shp,(PATHNOD))->nvalue.cp)
488da2e3ebdSchin 	{
489da2e3ebdSchin 		pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_PATH);
490da2e3ebdSchin 		if(shp->pathlist = (void*)pp)
491da2e3ebdSchin 			pp->shp = shp;
492da2e3ebdSchin 	}
493da2e3ebdSchin 	else
494da2e3ebdSchin 	{
495da2e3ebdSchin 		if(!(pp=(Pathcomp_t*)shp->defpathlist))
496da2e3ebdSchin 			pp = defpath_init(shp);
497da2e3ebdSchin 		shp->pathlist = (void*)path_dup(pp);
498da2e3ebdSchin 	}
4997c2fbfb3SApril Chin 	if(val=sh_scoped(shp,(FPATHNOD))->nvalue.cp)
500da2e3ebdSchin 	{
501da2e3ebdSchin 		pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_FPATH);
502da2e3ebdSchin 		if(shp->pathlist = (void*)pp)
503da2e3ebdSchin 			pp->shp = shp;
504da2e3ebdSchin 	}
505da2e3ebdSchin }
506da2e3ebdSchin 
507da2e3ebdSchin /*
508da2e3ebdSchin  * returns that pathlist to search
509da2e3ebdSchin  */
path_get(register const char * name)510da2e3ebdSchin Pathcomp_t *path_get(register const char *name)
511da2e3ebdSchin {
512da2e3ebdSchin 	register Shell_t *shp = &sh;
513da2e3ebdSchin 	register Pathcomp_t *pp=0;
514da2e3ebdSchin 	if(*name && strchr(name,'/'))
515da2e3ebdSchin 		return(0);
516da2e3ebdSchin 	if(!sh_isstate(SH_DEFPATH))
517da2e3ebdSchin 	{
518da2e3ebdSchin 		if(!shp->pathlist)
519da2e3ebdSchin 			path_init(shp);
520da2e3ebdSchin 		pp = (Pathcomp_t*)shp->pathlist;
521da2e3ebdSchin 	}
522da2e3ebdSchin 	if(!pp && (!(PATHNOD)->nvalue.cp) || sh_isstate(SH_DEFPATH))
523da2e3ebdSchin 	{
524da2e3ebdSchin 		if(!(pp=(Pathcomp_t*)shp->defpathlist))
525da2e3ebdSchin 			pp = defpath_init(shp);
526da2e3ebdSchin 	}
527da2e3ebdSchin 	return(pp);
528da2e3ebdSchin }
529da2e3ebdSchin 
530da2e3ebdSchin /*
531da2e3ebdSchin  * open file corresponding to name using path give by <pp>
532da2e3ebdSchin  */
path_opentype(const char * name,register Pathcomp_t * pp,int fun)533da2e3ebdSchin static int	path_opentype(const char *name, register Pathcomp_t *pp, int fun)
534da2e3ebdSchin {
535da2e3ebdSchin 	register int fd= -1;
536da2e3ebdSchin 	struct stat statb;
537da2e3ebdSchin 	Pathcomp_t *oldpp;
538da2e3ebdSchin 	Shell_t *shp;
539da2e3ebdSchin 	if(pp)
540da2e3ebdSchin 		shp = pp->shp;
541da2e3ebdSchin 	else
542da2e3ebdSchin 	{
543da2e3ebdSchin 		shp = sh_getinterp();
544da2e3ebdSchin 		if(!shp->pathlist)
545da2e3ebdSchin 			path_init(shp);
546da2e3ebdSchin 	}
547da2e3ebdSchin 	if(!fun && strchr(name,'/'))
548da2e3ebdSchin 	{
549da2e3ebdSchin 		if(sh_isoption(SH_RESTRICTED))
550da2e3ebdSchin 			errormsg(SH_DICT,ERROR_exit(1),e_restricted,name);
551da2e3ebdSchin 	}
552da2e3ebdSchin 	do
553da2e3ebdSchin 	{
554da2e3ebdSchin 		pp = path_nextcomp(oldpp=pp,name,0);
555da2e3ebdSchin 		while(oldpp && (oldpp->flags&PATH_SKIP))
556da2e3ebdSchin 			oldpp = oldpp->next;
557da2e3ebdSchin 		if(fun && (!oldpp || !(oldpp->flags&PATH_FPATH)))
558da2e3ebdSchin 			continue;
559da2e3ebdSchin 		if((fd = sh_open(path_relative(stakptr(PATH_OFFSET)),O_RDONLY,0)) >= 0)
560da2e3ebdSchin 		{
561da2e3ebdSchin 			if(fstat(fd,&statb)<0 || S_ISDIR(statb.st_mode))
562da2e3ebdSchin 			{
563da2e3ebdSchin 				errno = EISDIR;
564da2e3ebdSchin 				sh_close(fd);
565da2e3ebdSchin 				fd = -1;
566da2e3ebdSchin 			}
567da2e3ebdSchin 		}
568da2e3ebdSchin 	}
569da2e3ebdSchin 	while( fd<0 && pp);
570da2e3ebdSchin 	if(fd>=0 && (fd = sh_iomovefd(fd)) > 0)
571da2e3ebdSchin 	{
572da2e3ebdSchin 		fcntl(fd,F_SETFD,FD_CLOEXEC);
57334f9b3eeSRoland Mainz 		if(!shp)
57434f9b3eeSRoland Mainz 		{
57534f9b3eeSRoland Mainz 			shp = sh_getinterp();
57634f9b3eeSRoland Mainz #if _UWIN
57734f9b3eeSRoland Mainz 			close(0x10001); /* this results in a /var/log/uwin message with "0x10001" for debugging */
57834f9b3eeSRoland Mainz #endif
57934f9b3eeSRoland Mainz 		}
580da2e3ebdSchin 		shp->fdstatus[fd] |= IOCLEX;
581da2e3ebdSchin 	}
582da2e3ebdSchin 	return(fd);
583da2e3ebdSchin }
584da2e3ebdSchin 
585da2e3ebdSchin /*
586da2e3ebdSchin  * open file corresponding to name using path give by <pp>
587da2e3ebdSchin  */
path_open(const char * name,register Pathcomp_t * pp)588da2e3ebdSchin int	path_open(const char *name, register Pathcomp_t *pp)
589da2e3ebdSchin {
590da2e3ebdSchin 	return(path_opentype(name,pp,0));
591da2e3ebdSchin }
592da2e3ebdSchin 
593da2e3ebdSchin /*
594da2e3ebdSchin  * given a pathname return the base name
595da2e3ebdSchin  */
596da2e3ebdSchin 
path_basename(register const char * name)597da2e3ebdSchin char	*path_basename(register const char *name)
598da2e3ebdSchin {
599da2e3ebdSchin 	register const char *start = name;
600da2e3ebdSchin 	while (*name)
601da2e3ebdSchin 		if ((*name++ == '/') && *name)	/* don't trim trailing / */
602da2e3ebdSchin 			start = name;
603da2e3ebdSchin 	return ((char*)start);
604da2e3ebdSchin }
605da2e3ebdSchin 
path_fullname(const char * name)606da2e3ebdSchin char *path_fullname(const char *name)
607da2e3ebdSchin {
608da2e3ebdSchin 	int len=strlen(name)+1,dirlen=0;
609da2e3ebdSchin 	char *path,*pwd;
610da2e3ebdSchin 	if(*name!='/')
611da2e3ebdSchin 	{
612da2e3ebdSchin 		pwd = path_pwd(1);
613da2e3ebdSchin 		dirlen = strlen(pwd)+1;
614da2e3ebdSchin 	}
615da2e3ebdSchin 	path = (char*)malloc(len+dirlen);
616da2e3ebdSchin 	if(dirlen)
617da2e3ebdSchin 	{
618da2e3ebdSchin 		memcpy((void*)path,(void*)pwd,dirlen);
619da2e3ebdSchin 		path[dirlen-1] = '/';
620da2e3ebdSchin 	}
621da2e3ebdSchin 	memcpy((void*)&path[dirlen],(void*)name,len);
622da2e3ebdSchin 	pathcanon(path,0);
623da2e3ebdSchin 	return(path);
624da2e3ebdSchin }
625da2e3ebdSchin 
626da2e3ebdSchin /*
627da2e3ebdSchin  * load functions from file <fno>
628da2e3ebdSchin  */
funload(Shell_t * shp,int fno,const char * name)629da2e3ebdSchin static void funload(Shell_t *shp,int fno, const char *name)
630da2e3ebdSchin {
6317c2fbfb3SApril Chin 	char		*pname,*oldname=shp->st.filename, buff[IOBSIZE+1];
6327c2fbfb3SApril Chin 	Namval_t	*np;
6337c2fbfb3SApril Chin 	struct Ufunction *rp;
6347c2fbfb3SApril Chin 	int		 savestates = sh_getstate(), oldload=shp->funload;
6357c2fbfb3SApril Chin 	pname = path_fullname(stakptr(PATH_OFFSET));
6367c2fbfb3SApril Chin 	if(shp->fpathdict && (rp = dtmatch(shp->fpathdict,(void*)pname)))
6377c2fbfb3SApril Chin 	{
63834f9b3eeSRoland Mainz 		Dt_t	*funtree = sh_subfuntree(1);
6397c2fbfb3SApril Chin 		do
6407c2fbfb3SApril Chin 		{
64134f9b3eeSRoland Mainz 			if((np = dtsearch(funtree,rp->np)) && is_afunction(np))
6427c2fbfb3SApril Chin 			{
6437c2fbfb3SApril Chin 				if(np->nvalue.rp)
6447c2fbfb3SApril Chin 					np->nvalue.rp->fdict = 0;
64534f9b3eeSRoland Mainz 				nv_delete(np,funtree,NV_NOFREE);
6467c2fbfb3SApril Chin 			}
64734f9b3eeSRoland Mainz 			dtinsert(funtree,rp->np);
64834f9b3eeSRoland Mainz 			rp->fdict = funtree;
6497c2fbfb3SApril Chin 		}
6507c2fbfb3SApril Chin 		while((rp=dtnext(shp->fpathdict,rp)) && strcmp(pname,rp->fname)==0);
6517c2fbfb3SApril Chin 		return;
6527c2fbfb3SApril Chin 	}
653da2e3ebdSchin 	sh_onstate(SH_NOLOG);
654da2e3ebdSchin 	sh_onstate(SH_NOALIAS);
655da2e3ebdSchin 	shp->readscript = (char*)name;
6567c2fbfb3SApril Chin 	shp->st.filename = pname;
6577c2fbfb3SApril Chin 	shp->funload = 1;
658da2e3ebdSchin 	error_info.line = 0;
65934f9b3eeSRoland Mainz 	sh_eval(sfnew(NIL(Sfio_t*),buff,IOBSIZE,fno,SF_READ),SH_FUNEVAL);
660da2e3ebdSchin 	shp->readscript = 0;
661da2e3ebdSchin 	free((void*)shp->st.filename);
6627c2fbfb3SApril Chin 	shp->funload = oldload;
663da2e3ebdSchin 	shp->st.filename = oldname;
664da2e3ebdSchin 	sh_setstate(savestates);
665da2e3ebdSchin }
666da2e3ebdSchin 
667da2e3ebdSchin /*
668da2e3ebdSchin  * do a path search and track alias if requested
669da2e3ebdSchin  * if flag is 0, or if name not found, then try autoloading function
6707c2fbfb3SApril Chin  * if flag==2 or 3, returns 1 if name found on FPATH
6717c2fbfb3SApril Chin  * if flag==3 no tracked alias will be set
672da2e3ebdSchin  * returns 1, if function was autoloaded.
6737c2fbfb3SApril Chin  * If oldpp is not NULL, it will contain a pointer to the path component
6747c2fbfb3SApril Chin  *    where it was found.
675da2e3ebdSchin  */
676da2e3ebdSchin 
path_search(register const char * name,Pathcomp_t ** oldpp,int flag)6777c2fbfb3SApril Chin int	path_search(register const char *name,Pathcomp_t **oldpp, int flag)
678da2e3ebdSchin {
679da2e3ebdSchin 	register Namval_t *np;
680da2e3ebdSchin 	register int fno;
681da2e3ebdSchin 	Pathcomp_t *pp=0;
682da2e3ebdSchin 	Shell_t *shp = &sh;
683da2e3ebdSchin 	if(name && strchr(name,'/'))
684da2e3ebdSchin 	{
685da2e3ebdSchin 		stakseek(PATH_OFFSET);
686da2e3ebdSchin 		stakputs(name);
687da2e3ebdSchin 		if(canexecute(stakptr(PATH_OFFSET),0)<0)
688da2e3ebdSchin 		{
689da2e3ebdSchin 			*stakptr(PATH_OFFSET) = 0;
690da2e3ebdSchin 			return(0);
691da2e3ebdSchin 		}
692da2e3ebdSchin 		if(*name=='/')
693da2e3ebdSchin 			return(1);
694da2e3ebdSchin 		stakseek(PATH_OFFSET);
695da2e3ebdSchin 		stakputs(path_pwd(1));
696da2e3ebdSchin 		stakputc('/');
697da2e3ebdSchin 		stakputs(name);
698da2e3ebdSchin 		stakputc(0);
699da2e3ebdSchin 		return(0);
700da2e3ebdSchin 	}
701da2e3ebdSchin 	if(sh_isstate(SH_DEFPATH))
702da2e3ebdSchin 	{
703da2e3ebdSchin 		if(!shp->defpathlist)
704da2e3ebdSchin 			defpath_init(shp);
705da2e3ebdSchin 	}
706da2e3ebdSchin 	else if(!shp->pathlist)
707da2e3ebdSchin 		path_init(shp);
708da2e3ebdSchin 	if(flag)
709da2e3ebdSchin 	{
71034f9b3eeSRoland Mainz 		if((np=nv_search(name,shp->track_tree,0)) && !nv_isattr(np,NV_NOALIAS) && (pp=(Pathcomp_t*)np->nvalue.cp))
71134f9b3eeSRoland Mainz 		{
71234f9b3eeSRoland Mainz 			stakseek(PATH_OFFSET);
71334f9b3eeSRoland Mainz 			path_nextcomp(pp,name,pp);
71434f9b3eeSRoland Mainz 			stakputc(0);
71534f9b3eeSRoland Mainz 			return(0);
71634f9b3eeSRoland Mainz 		}
7177c2fbfb3SApril Chin 		pp = path_absolute(name,oldpp?*oldpp:NIL(Pathcomp_t*));
7187c2fbfb3SApril Chin 		if(oldpp)
7197c2fbfb3SApril Chin 			*oldpp = pp;
72034f9b3eeSRoland Mainz 		if(!pp && (np=nv_search(name,shp->fun_tree,HASH_NOSCOPE))&&np->nvalue.ip)
721da2e3ebdSchin 			return(1);
722da2e3ebdSchin 		if(!pp)
723da2e3ebdSchin 			*stakptr(PATH_OFFSET) = 0;
724da2e3ebdSchin 	}
725da2e3ebdSchin 	if(flag==0 || !pp || (pp->flags&PATH_FPATH))
726da2e3ebdSchin 	{
727da2e3ebdSchin 		if(!pp)
728da2e3ebdSchin 			pp=sh_isstate(SH_DEFPATH)?shp->defpathlist:shp->pathlist;
729da2e3ebdSchin 		if(pp && strmatch(name,e_alphanum)  && (fno=path_opentype(name,pp,1))>=0)
730da2e3ebdSchin 		{
731da2e3ebdSchin 			if(flag==2)
732da2e3ebdSchin 			{
733da2e3ebdSchin 				sh_close(fno);
734da2e3ebdSchin 				return(1);
735da2e3ebdSchin 			}
736da2e3ebdSchin 			funload(shp,fno,name);
737da2e3ebdSchin 			return(1);
738da2e3ebdSchin 		}
739da2e3ebdSchin 		*stakptr(PATH_OFFSET) = 0;
740da2e3ebdSchin 		return(0);
741da2e3ebdSchin 	}
7427c2fbfb3SApril Chin 	else if(pp && !sh_isstate(SH_DEFPATH) && *name!='/' && flag<3)
743da2e3ebdSchin 	{
744da2e3ebdSchin 		if(np=nv_search(name,shp->track_tree,NV_ADD))
745da2e3ebdSchin 			path_alias(np,pp);
746da2e3ebdSchin 	}
747da2e3ebdSchin 	return(0);
748da2e3ebdSchin }
749da2e3ebdSchin 
750da2e3ebdSchin /*
751da2e3ebdSchin  * do a path search and find the full pathname of file name
752da2e3ebdSchin  */
path_absolute(register const char * name,Pathcomp_t * pp)7537c2fbfb3SApril Chin Pathcomp_t *path_absolute(register const char *name, Pathcomp_t *pp)
754da2e3ebdSchin {
755da2e3ebdSchin 	register int	f,isfun;
756da2e3ebdSchin 	int		noexec=0;
7577c2fbfb3SApril Chin 	Pathcomp_t	*oldpp;
758da2e3ebdSchin 	Shell_t		*shp = &sh;
759da2e3ebdSchin 	Namval_t	*np;
760da2e3ebdSchin 	shp->path_err = ENOENT;
7617c2fbfb3SApril Chin 	if(!pp && !(pp=path_get("")))
762da2e3ebdSchin 		return(0);
763da2e3ebdSchin 	shp->path_err = 0;
764da2e3ebdSchin 	while(1)
765da2e3ebdSchin 	{
766da2e3ebdSchin 		sh_sigcheck();
767da2e3ebdSchin 		isfun = (pp->flags&PATH_FPATH);
768da2e3ebdSchin 		if(oldpp=pp)
76934f9b3eeSRoland Mainz 		{
770da2e3ebdSchin 			pp = path_nextcomp(pp,name,0);
77134f9b3eeSRoland Mainz 			while(oldpp->flags&PATH_SKIP)
77234f9b3eeSRoland Mainz 			{
77334f9b3eeSRoland Mainz 				if(!(oldpp=oldpp->next))
77434f9b3eeSRoland Mainz 				{
77534f9b3eeSRoland Mainz 					shp->path_err = ENOENT;
77634f9b3eeSRoland Mainz 					return(0);
77734f9b3eeSRoland Mainz 				}
77834f9b3eeSRoland Mainz 			}
77934f9b3eeSRoland Mainz 		}
78034f9b3eeSRoland Mainz 
781da2e3ebdSchin 		if(!isfun && !sh_isoption(SH_RESTRICTED))
782da2e3ebdSchin 		{
7837c2fbfb3SApril Chin 			if(*stakptr(PATH_OFFSET)=='/' && nv_search(stakptr(PATH_OFFSET),sh.bltin_tree,0))
784da2e3ebdSchin 				return(oldpp);
7857c2fbfb3SApril Chin #if SHOPT_DYNAMIC
786da2e3ebdSchin 			if(oldpp->blib)
787da2e3ebdSchin 			{
788da2e3ebdSchin 				typedef int (*Fptr_t)(int, char*[], void*);
789da2e3ebdSchin 				Fptr_t addr;
790da2e3ebdSchin 				int n = staktell();
79134f9b3eeSRoland Mainz 				int libcmd;
792da2e3ebdSchin 				char *cp;
793da2e3ebdSchin 				stakputs("b_");
794da2e3ebdSchin 				stakputs(name);
795da2e3ebdSchin 				stakputc(0);
796da2e3ebdSchin 				if(!oldpp->bltin_lib)
797da2e3ebdSchin 				{
798da2e3ebdSchin 					if(cp = strrchr(oldpp->blib,'/'))
799da2e3ebdSchin 						cp++;
800da2e3ebdSchin 					else
801da2e3ebdSchin 						cp = oldpp->blib;
80234f9b3eeSRoland Mainz 					if((libcmd = !strcmp(cp,LIBCMD)) && (addr=(Fptr_t)dlllook((void*)0,stakptr(n))))
803da2e3ebdSchin 					{
8047c2fbfb3SApril Chin 						if((np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL)) && nv_isattr(np,NV_BLTINOPT))
805da2e3ebdSchin 							return(oldpp);
806da2e3ebdSchin 					}
807da2e3ebdSchin #if (_AST_VERSION>=20040404)
808da2e3ebdSchin 					if (oldpp->bltin_lib = dllplug(SH_ID, oldpp->blib, NiL, RTLD_LAZY, NiL, 0))
809da2e3ebdSchin #else
810da2e3ebdSchin 					if (oldpp->bltin_lib = dllfind(oldpp->blib, NiL, RTLD_LAZY, NiL, 0))
811da2e3ebdSchin #endif
81234f9b3eeSRoland Mainz 					{
81334f9b3eeSRoland Mainz 						/*
81434f9b3eeSRoland Mainz 						 * this detects the 2007-05-11 builtin context change and also
81534f9b3eeSRoland Mainz 						 * the 2008-03-30 opt_info.num change that hit libcmd::b_head
81634f9b3eeSRoland Mainz 						 */
81734f9b3eeSRoland Mainz 
81834f9b3eeSRoland Mainz 						if (libcmd && !dlllook(oldpp->bltin_lib, "b_pids"))
81934f9b3eeSRoland Mainz 						{
82034f9b3eeSRoland Mainz 							dlclose(oldpp->bltin_lib);
82134f9b3eeSRoland Mainz 							oldpp->bltin_lib = 0;
82234f9b3eeSRoland Mainz 							oldpp->blib = 0;
82334f9b3eeSRoland Mainz 						}
82434f9b3eeSRoland Mainz 						else
825da2e3ebdSchin 							sh_addlib(oldpp->bltin_lib);
826da2e3ebdSchin 					}
82734f9b3eeSRoland Mainz 				}
828da2e3ebdSchin 				if((addr=(Fptr_t)dlllook(oldpp->bltin_lib,stakptr(n))) &&
829da2e3ebdSchin 				   (!(np = sh_addbuiltin(stakptr(PATH_OFFSET),NiL,NiL)) || np->nvalue.bfp!=addr) &&
830da2e3ebdSchin 				   (np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL)))
831da2e3ebdSchin 				{
832da2e3ebdSchin 					np->nvenv = oldpp->bltin_lib;
833da2e3ebdSchin 					return(oldpp);
834da2e3ebdSchin 				}
835da2e3ebdSchin 			}
8367c2fbfb3SApril Chin #endif /* SHOPT_DYNAMIC */
837da2e3ebdSchin 		}
8387c2fbfb3SApril Chin 		sh_stats(STAT_PATHS);
839da2e3ebdSchin 		f = canexecute(stakptr(PATH_OFFSET),isfun);
840da2e3ebdSchin 		if(isfun && f>=0)
841da2e3ebdSchin 		{
84234f9b3eeSRoland Mainz 			nv_onattr(nv_open(name,sh_subfuntree(1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE),NV_LTOU|NV_FUNCTION);
84334f9b3eeSRoland Mainz 			funload(shp,f,name);
844da2e3ebdSchin 			close(f);
845da2e3ebdSchin 			f = -1;
846da2e3ebdSchin 			return(0);
847da2e3ebdSchin 		}
848da2e3ebdSchin 		else if(f>=0 && (oldpp->flags & PATH_STD_DIR))
849da2e3ebdSchin 		{
8507c2fbfb3SApril Chin 			int n = staktell();
851da2e3ebdSchin 			stakputs("/bin/");
852da2e3ebdSchin 			stakputs(name);
853da2e3ebdSchin 			stakputc(0);
8547c2fbfb3SApril Chin 			np = nv_search(stakptr(n),sh.bltin_tree,0);
8557c2fbfb3SApril Chin 			stakseek(n);
856da2e3ebdSchin 			if(np)
857da2e3ebdSchin 			{
8587c2fbfb3SApril Chin 				n = np->nvflag;
8597c2fbfb3SApril Chin 				np = sh_addbuiltin(stakptr(PATH_OFFSET),np->nvalue.bfp,nv_context(np));
8607c2fbfb3SApril Chin 				np->nvflag = n;
861da2e3ebdSchin 			}
862da2e3ebdSchin 		}
863da2e3ebdSchin 		if(!pp || f>=0)
864da2e3ebdSchin 			break;
865da2e3ebdSchin 		if(errno!=ENOENT)
866da2e3ebdSchin 			noexec = errno;
867da2e3ebdSchin 	}
868da2e3ebdSchin 	if(f<0)
869da2e3ebdSchin 	{
870da2e3ebdSchin 		shp->path_err = (noexec?noexec:ENOENT);
871da2e3ebdSchin 		return(0);
872da2e3ebdSchin 	}
873da2e3ebdSchin 	stakputc(0);
874da2e3ebdSchin 	return(oldpp);
875da2e3ebdSchin }
876da2e3ebdSchin 
877da2e3ebdSchin /*
878da2e3ebdSchin  * returns 0 if path can execute
879da2e3ebdSchin  * sets exec_err if file is found but can't be executable
880da2e3ebdSchin  */
881da2e3ebdSchin #undef S_IXALL
882da2e3ebdSchin #ifdef S_IXUSR
883da2e3ebdSchin #   define S_IXALL	(S_IXUSR|S_IXGRP|S_IXOTH)
884da2e3ebdSchin #else
885da2e3ebdSchin #   ifdef S_IEXEC
886da2e3ebdSchin #	define S_IXALL	(S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6))
887da2e3ebdSchin #   else
888da2e3ebdSchin #	define S_IXALL	0111
889da2e3ebdSchin #   endif /*S_EXEC */
890da2e3ebdSchin #endif /* S_IXUSR */
891da2e3ebdSchin 
canexecute(register char * path,int isfun)892da2e3ebdSchin static int canexecute(register char *path, int isfun)
893da2e3ebdSchin {
894da2e3ebdSchin 	struct stat statb;
895da2e3ebdSchin 	register int fd=0;
896da2e3ebdSchin 	path = path_relative(path);
897da2e3ebdSchin 	if(isfun)
898da2e3ebdSchin 	{
899da2e3ebdSchin 		if((fd=open(path,O_RDONLY,0))<0 || fstat(fd,&statb)<0)
900da2e3ebdSchin 			goto err;
901da2e3ebdSchin 	}
902da2e3ebdSchin 	else if(stat(path,&statb) < 0)
903da2e3ebdSchin 	{
904da2e3ebdSchin #if _WINIX
905da2e3ebdSchin 		/* check for .exe or .bat suffix */
906da2e3ebdSchin 		char *cp;
907da2e3ebdSchin 		if(errno==ENOENT && (!(cp=strrchr(path,'.')) || strlen(cp)>4 || strchr(cp,'/')))
908da2e3ebdSchin 		{
909da2e3ebdSchin 			int offset = staktell()-1;
910da2e3ebdSchin 			stakseek(offset);
911da2e3ebdSchin 			stakputs(".bat");
912da2e3ebdSchin 			path = stakptr(PATH_OFFSET);
913da2e3ebdSchin 			if(stat(path,&statb) < 0)
914da2e3ebdSchin 			{
915da2e3ebdSchin 				if(errno!=ENOENT)
916da2e3ebdSchin 					goto err;
917da2e3ebdSchin 				memcpy(stakptr(offset),".sh",4);
918da2e3ebdSchin 				if(stat(path,&statb) < 0)
919da2e3ebdSchin 					goto err;
920da2e3ebdSchin 			}
921da2e3ebdSchin 		}
922da2e3ebdSchin 		else
923da2e3ebdSchin #endif /* _WINIX */
924da2e3ebdSchin 		goto err;
925da2e3ebdSchin 	}
926da2e3ebdSchin 	errno = EPERM;
927da2e3ebdSchin 	if(S_ISDIR(statb.st_mode))
928da2e3ebdSchin 		errno = EISDIR;
929da2e3ebdSchin 	else if((statb.st_mode&S_IXALL)==S_IXALL || sh_access(path,X_OK)>=0)
930da2e3ebdSchin 		return(fd);
931da2e3ebdSchin 	if(isfun && fd>=0)
932da2e3ebdSchin 		sh_close(fd);
933da2e3ebdSchin err:
934da2e3ebdSchin 	return(-1);
935da2e3ebdSchin }
936da2e3ebdSchin 
937da2e3ebdSchin /*
938da2e3ebdSchin  * Return path relative to present working directory
939da2e3ebdSchin  */
940da2e3ebdSchin 
path_relative(register const char * file)941da2e3ebdSchin char *path_relative(register const char* file)
942da2e3ebdSchin {
943da2e3ebdSchin 	register const char *pwd;
944da2e3ebdSchin 	register const char *fp = file;
945da2e3ebdSchin 	/* can't relpath when sh.pwd not set */
946da2e3ebdSchin 	if(!(pwd=sh.pwd))
947da2e3ebdSchin 		return((char*)fp);
948da2e3ebdSchin 	while(*pwd==*fp)
949da2e3ebdSchin 	{
950da2e3ebdSchin 		if(*pwd++==0)
951da2e3ebdSchin 			return((char*)e_dot);
952da2e3ebdSchin 		fp++;
953da2e3ebdSchin 	}
954da2e3ebdSchin 	if(*pwd==0 && *fp == '/')
955da2e3ebdSchin 	{
956da2e3ebdSchin 		while(*++fp=='/');
957da2e3ebdSchin 		if(*fp)
958da2e3ebdSchin 			return((char*)fp);
959da2e3ebdSchin 		return((char*)e_dot);
960da2e3ebdSchin 	}
961da2e3ebdSchin 	return((char*)file);
962da2e3ebdSchin }
963da2e3ebdSchin 
path_exec(register const char * arg0,register char * argv[],struct argnod * local)964da2e3ebdSchin void	path_exec(register const char *arg0,register char *argv[],struct argnod *local)
965da2e3ebdSchin {
966da2e3ebdSchin 	char **envp;
967da2e3ebdSchin 	const char *opath;
968da2e3ebdSchin 	Pathcomp_t *libpath, *pp=0;
969da2e3ebdSchin 	Shell_t *shp = &sh;
970da2e3ebdSchin 	int slash=0;
97134f9b3eeSRoland Mainz 	nv_setlist(local,NV_EXPORT|NV_IDENT|NV_ASSIGN,0);
972da2e3ebdSchin 	envp = sh_envgen();
973da2e3ebdSchin 	if(strchr(arg0,'/'))
974da2e3ebdSchin 	{
975da2e3ebdSchin 		slash=1;
976da2e3ebdSchin 		/* name containing / not allowed for restricted shell */
977da2e3ebdSchin 		if(sh_isoption(SH_RESTRICTED))
978da2e3ebdSchin 			errormsg(SH_DICT,ERROR_exit(1),e_restricted,arg0);
979da2e3ebdSchin 	}
980da2e3ebdSchin 	else
981da2e3ebdSchin 		pp=path_get(arg0);
982da2e3ebdSchin 	shp->path_err= ENOENT;
983da2e3ebdSchin 	sfsync(NIL(Sfio_t*));
984da2e3ebdSchin 	timerdel(NIL(void*));
985da2e3ebdSchin 	/* find first path that has a library component */
98634f9b3eeSRoland Mainz 	while(pp && (pp->flags&PATH_SKIP))
98734f9b3eeSRoland Mainz 		pp = pp->next;
988da2e3ebdSchin 	if(pp || slash) do
989da2e3ebdSchin 	{
990da2e3ebdSchin 		sh_sigcheck();
991da2e3ebdSchin 		if(libpath=pp)
992da2e3ebdSchin 		{
993da2e3ebdSchin 			pp = path_nextcomp(pp,arg0,0);
994da2e3ebdSchin 			opath = stakfreeze(1)+PATH_OFFSET;
995da2e3ebdSchin 		}
996da2e3ebdSchin 		else
997da2e3ebdSchin 			opath = arg0;
998da2e3ebdSchin 		path_spawn(opath,argv,envp,libpath,0);
999da2e3ebdSchin 		while(pp && (pp->flags&PATH_FPATH))
1000da2e3ebdSchin 			pp = path_nextcomp(pp,arg0,0);
1001da2e3ebdSchin 	}
1002da2e3ebdSchin 	while(pp);
1003da2e3ebdSchin 	/* force an exit */
1004da2e3ebdSchin 	((struct checkpt*)shp->jmplist)->mode = SH_JMPEXIT;
1005da2e3ebdSchin 	if((errno=shp->path_err)==ENOENT)
1006da2e3ebdSchin 		errormsg(SH_DICT,ERROR_exit(ERROR_NOENT),e_found,arg0);
1007da2e3ebdSchin 	else
1008da2e3ebdSchin 		errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,arg0);
1009da2e3ebdSchin }
1010da2e3ebdSchin 
path_spawn(const char * opath,register char ** argv,char ** envp,Pathcomp_t * libpath,int spawn)1011da2e3ebdSchin pid_t path_spawn(const char *opath,register char **argv, char **envp, Pathcomp_t *libpath, int spawn)
1012da2e3ebdSchin {
1013da2e3ebdSchin 	Shell_t *shp = sh_getinterp();
1014da2e3ebdSchin 	register char *path;
1015da2e3ebdSchin 	char **xp=0, *xval, *libenv = (libpath?libpath->lib:0);
1016da2e3ebdSchin 	Namval_t*	np;
1017da2e3ebdSchin 	char		*s, *v;
101834f9b3eeSRoland Mainz 	int		r, n, pidsize;
1019da2e3ebdSchin 	pid_t		pid= -1;
1020da2e3ebdSchin 	/* leave room for inserting _= pathname in environment */
1021da2e3ebdSchin 	envp--;
1022da2e3ebdSchin #if _lib_readlink
1023da2e3ebdSchin 	/* save original pathname */
1024da2e3ebdSchin 	stakseek(PATH_OFFSET);
102534f9b3eeSRoland Mainz 	pidsize = sfprintf(stkstd,"*%d*",spawn?getpid():getppid());
1026da2e3ebdSchin 	stakputs(opath);
102734f9b3eeSRoland Mainz 	opath = stakfreeze(1)+PATH_OFFSET+pidsize;
1028da2e3ebdSchin 	np=nv_search(argv[0],shp->track_tree,0);
1029da2e3ebdSchin 	while(libpath && !libpath->lib)
1030da2e3ebdSchin 		libpath=libpath->next;
1031da2e3ebdSchin 	if(libpath && (!np || nv_size(np)>0))
1032da2e3ebdSchin 	{
1033da2e3ebdSchin 		/* check for symlink and use symlink name */
1034da2e3ebdSchin 		char buff[PATH_MAX+1];
1035da2e3ebdSchin 		char save[PATH_MAX+1];
1036da2e3ebdSchin 		stakseek(PATH_OFFSET);
1037da2e3ebdSchin 		stakputs(opath);
1038da2e3ebdSchin 		path = stakptr(PATH_OFFSET);
1039da2e3ebdSchin 		while((n=readlink(path,buff,PATH_MAX))>0)
1040da2e3ebdSchin 		{
1041da2e3ebdSchin 			buff[n] = 0;
1042da2e3ebdSchin 			n = PATH_OFFSET;
1043da2e3ebdSchin 			r = 0;
1044da2e3ebdSchin 			if((v=strrchr(path,'/')) && *buff!='/')
1045da2e3ebdSchin 			{
1046da2e3ebdSchin 				if(buff[0]=='.' && buff[1]=='.' && (r = strlen(path) + 1) <= PATH_MAX)
1047da2e3ebdSchin 					memcpy(save, path, r);
1048da2e3ebdSchin 				else
1049da2e3ebdSchin 					r = 0;
1050da2e3ebdSchin 				n += (v+1-path);
1051da2e3ebdSchin 			}
1052da2e3ebdSchin 			stakseek(n);
1053da2e3ebdSchin 			stakputs(buff);
1054da2e3ebdSchin 			stakputc(0);
1055da2e3ebdSchin 			path = stakptr(PATH_OFFSET);
1056da2e3ebdSchin 			if(v && buff[0]=='.' && buff[1]=='.')
1057da2e3ebdSchin 			{
1058da2e3ebdSchin 				pathcanon(path, 0);
1059da2e3ebdSchin 				if(r && access(path,X_OK))
1060da2e3ebdSchin 				{
1061da2e3ebdSchin 					memcpy(path, save, r);
1062da2e3ebdSchin 					break;
1063da2e3ebdSchin 				}
1064da2e3ebdSchin 			}
1065da2e3ebdSchin 			if(libenv = path_lib(libpath,path))
1066da2e3ebdSchin 				break;
1067da2e3ebdSchin 		}
1068da2e3ebdSchin 		stakseek(0);
1069da2e3ebdSchin 	}
1070da2e3ebdSchin #endif
1071da2e3ebdSchin 	if(libenv && (v = strchr(libenv,'=')))
1072da2e3ebdSchin 	{
1073da2e3ebdSchin 		n = v - libenv;
1074da2e3ebdSchin 		*v = 0;
1075da2e3ebdSchin 		np = nv_open(libenv,shp->var_tree,0);
1076da2e3ebdSchin 		*v = '=';
1077da2e3ebdSchin 		s = nv_getval(np);
1078da2e3ebdSchin 		stakputs(libenv);
1079da2e3ebdSchin 		if(s)
1080da2e3ebdSchin 		{
1081da2e3ebdSchin 			stakputc(':');
1082da2e3ebdSchin 			stakputs(s);
1083da2e3ebdSchin 		}
1084da2e3ebdSchin 		v = stakfreeze(1);
1085da2e3ebdSchin 		r = 1;
10867c2fbfb3SApril Chin 		xp = envp + 1;
1087da2e3ebdSchin 		while (s = *xp++)
1088da2e3ebdSchin 		{
1089da2e3ebdSchin 			if (strneq(s, v, n) && s[n] == '=')
1090da2e3ebdSchin 			{
1091da2e3ebdSchin 				xval = *--xp;
1092da2e3ebdSchin 				*xp = v;
1093da2e3ebdSchin 				r = 0;
1094da2e3ebdSchin 				break;
1095da2e3ebdSchin 			}
1096da2e3ebdSchin 		}
1097da2e3ebdSchin 		if (r)
1098da2e3ebdSchin 		{
1099da2e3ebdSchin 			*envp-- = v;
1100da2e3ebdSchin 			xp = 0;
1101da2e3ebdSchin 		}
1102da2e3ebdSchin 	}
1103da2e3ebdSchin 	if(!opath)
1104da2e3ebdSchin 		opath = stakptr(PATH_OFFSET);
110534f9b3eeSRoland Mainz 	envp[0] =  (char*)opath-(PATH_OFFSET+pidsize);
1106da2e3ebdSchin 	envp[0][0] =  '_';
1107da2e3ebdSchin 	envp[0][1] =  '=';
1108da2e3ebdSchin 	sfsync(sfstderr);
1109da2e3ebdSchin 	sh_sigcheck();
1110da2e3ebdSchin 	path = path_relative(opath);
1111da2e3ebdSchin #ifdef SHELLMAGIC
1112da2e3ebdSchin 	if(*path!='/' && path!=opath)
1113da2e3ebdSchin 	{
1114da2e3ebdSchin 		/*
1115da2e3ebdSchin 		 * The following code because execv(foo,) and execv(./foo,)
1116da2e3ebdSchin 		 * may not yield the same results
1117da2e3ebdSchin 		 */
1118da2e3ebdSchin 		char *sp = (char*)malloc(strlen(path)+3);
1119da2e3ebdSchin 		sp[0] = '.';
1120da2e3ebdSchin 		sp[1] = '/';
1121da2e3ebdSchin 		strcpy(sp+2,path);
1122da2e3ebdSchin 		path = sp;
1123da2e3ebdSchin 	}
1124da2e3ebdSchin #endif /* SHELLMAGIC */
1125da2e3ebdSchin 	if(spawn && !sh_isoption(SH_PFSH))
1126da2e3ebdSchin 		pid = _spawnveg(opath, &argv[0],envp, spawn>>1);
1127da2e3ebdSchin 	else
11287c2fbfb3SApril Chin 		pid = path_pfexecve(opath, &argv[0] ,envp,spawn);
1129da2e3ebdSchin 	if(xp)
1130da2e3ebdSchin 		*xp = xval;
1131da2e3ebdSchin #ifdef SHELLMAGIC
1132da2e3ebdSchin 	if(*path=='.' && path!=opath)
1133da2e3ebdSchin 	{
1134da2e3ebdSchin 		free(path);
1135da2e3ebdSchin 		path = path_relative(opath);
1136da2e3ebdSchin 	}
1137da2e3ebdSchin #endif /* SHELLMAGIC */
1138da2e3ebdSchin 	if(pid>0)
1139da2e3ebdSchin 		return(pid);
1140da2e3ebdSchin retry:
1141da2e3ebdSchin 	switch(sh.path_err = errno)
1142da2e3ebdSchin 	{
1143da2e3ebdSchin #ifdef apollo
1144da2e3ebdSchin 	    /*
1145da2e3ebdSchin   	     * On apollo's execve will fail with eacces when
1146da2e3ebdSchin 	     * file has execute but not read permissions. So,
1147da2e3ebdSchin 	     * for now we will pretend that EACCES and ENOEXEC
1148da2e3ebdSchin  	     * mean the same thing.
1149da2e3ebdSchin  	     */
1150da2e3ebdSchin 	    case EACCES:
1151da2e3ebdSchin #endif /* apollo */
1152da2e3ebdSchin 	    case ENOEXEC:
1153da2e3ebdSchin #if SHOPT_SUID_EXEC
1154da2e3ebdSchin 	    case EPERM:
1155da2e3ebdSchin 		/* some systems return EPERM if setuid bit is on */
1156da2e3ebdSchin #endif
1157da2e3ebdSchin 		errno = ENOEXEC;
1158da2e3ebdSchin 		if(spawn)
1159da2e3ebdSchin 		{
1160da2e3ebdSchin #ifdef _lib_fork
1161da2e3ebdSchin 			if(sh.subshell)
1162da2e3ebdSchin 				return(-1);
1163da2e3ebdSchin 			do
1164da2e3ebdSchin 			{
1165da2e3ebdSchin 				if((pid=fork())>0)
1166da2e3ebdSchin 					return(pid);
1167da2e3ebdSchin 			}
1168da2e3ebdSchin 			while(_sh_fork(pid,0,(int*)0) < 0);
11697c2fbfb3SApril Chin 			((struct checkpt*)shp->jmplist)->mode = SH_JMPEXIT;
1170da2e3ebdSchin #else
1171da2e3ebdSchin 			return(-1);
1172da2e3ebdSchin #endif
1173da2e3ebdSchin 		}
1174da2e3ebdSchin 		exscript(shp,path,argv,envp);
1175da2e3ebdSchin #ifndef apollo
1176*3ce7283dSToomas Soome 	    case EACCES:
1177da2e3ebdSchin 	    {
1178da2e3ebdSchin 		struct stat statb;
1179da2e3ebdSchin 		if(stat(path,&statb)>=0)
1180da2e3ebdSchin 		{
1181da2e3ebdSchin 			if(S_ISDIR(statb.st_mode))
1182da2e3ebdSchin 				errno = EISDIR;
1183da2e3ebdSchin #ifdef S_ISSOCK
1184da2e3ebdSchin 			if(S_ISSOCK(statb.st_mode))
1185da2e3ebdSchin 				exscript(shp,path,argv,envp);
1186da2e3ebdSchin #endif
1187da2e3ebdSchin 		}
1188da2e3ebdSchin 	    }
1189da2e3ebdSchin 		/* FALL THROUGH */
1190da2e3ebdSchin #endif /* !apollo */
1191da2e3ebdSchin #ifdef ENAMETOOLONG
1192*3ce7283dSToomas Soome 	    case ENAMETOOLONG:
1193da2e3ebdSchin #endif /* ENAMETOOLONG */
1194da2e3ebdSchin #if !SHOPT_SUID_EXEC
1195da2e3ebdSchin 	    case EPERM:
1196da2e3ebdSchin #endif
1197da2e3ebdSchin 		shp->path_err = errno;
1198da2e3ebdSchin 		return(-1);
1199da2e3ebdSchin 	    case ENOTDIR:
1200da2e3ebdSchin 	    case ENOENT:
1201da2e3ebdSchin 	    case EINTR:
1202da2e3ebdSchin #ifdef EMLINK
1203da2e3ebdSchin 	    case EMLINK:
1204da2e3ebdSchin #endif /* EMLINK */
1205da2e3ebdSchin 		return(-1);
1206da2e3ebdSchin 	    case E2BIG:
1207da2e3ebdSchin 		if(sh.xargmin)
1208da2e3ebdSchin 		{
1209da2e3ebdSchin 			pid = path_xargs(opath, &argv[0] ,envp,spawn);
1210da2e3ebdSchin 			if(pid<0)
1211da2e3ebdSchin 				goto retry;
1212da2e3ebdSchin 			return(pid);
1213da2e3ebdSchin 		}
1214da2e3ebdSchin 	    default:
1215*3ce7283dSToomas Soome 		errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path);
1216da2e3ebdSchin 	}
1217da2e3ebdSchin 	return 0;
1218da2e3ebdSchin }
1219da2e3ebdSchin 
1220da2e3ebdSchin /*
1221da2e3ebdSchin  * File is executable but not machine code.
1222da2e3ebdSchin  * Assume file is a Shell script and execute it.
1223da2e3ebdSchin  */
1224da2e3ebdSchin 
exscript(Shell_t * shp,register char * path,register char * argv[],char ** envp)1225da2e3ebdSchin static void exscript(Shell_t *shp,register char *path,register char *argv[],char **envp)
1226da2e3ebdSchin {
1227da2e3ebdSchin 	register Sfio_t *sp;
1228da2e3ebdSchin 	path = path_relative(path);
1229da2e3ebdSchin 	shp->comdiv=0;
1230da2e3ebdSchin 	shp->bckpid = 0;
1231da2e3ebdSchin 	shp->st.ioset=0;
1232da2e3ebdSchin 	/* clean up any cooperating processes */
1233da2e3ebdSchin 	if(shp->cpipe[0]>0)
1234da2e3ebdSchin 		sh_pclose(shp->cpipe);
1235da2e3ebdSchin 	if(shp->cpid && shp->outpipe)
1236da2e3ebdSchin 		sh_close(*shp->outpipe);
1237da2e3ebdSchin 	shp->cpid = 0;
1238da2e3ebdSchin 	if(sp=fcfile())
1239da2e3ebdSchin 		while(sfstack(sp,SF_POPSTACK));
1240da2e3ebdSchin 	job_clear();
1241da2e3ebdSchin 	if(shp->infd>0 && (shp->fdstatus[shp->infd]&IOCLEX))
1242da2e3ebdSchin 		sh_close(shp->infd);
1243da2e3ebdSchin 	sh_setstate(sh_state(SH_FORKED));
1244da2e3ebdSchin 	sfsync(sfstderr);
1245da2e3ebdSchin #if SHOPT_SUID_EXEC && !SHOPT_PFSH
1246da2e3ebdSchin 	/* check if file cannot open for read or script is setuid/setgid  */
1247da2e3ebdSchin 	{
1248da2e3ebdSchin 		static char name[] = "/tmp/euidXXXXXXXXXX";
1249da2e3ebdSchin 		register int n;
1250da2e3ebdSchin 		register uid_t euserid;
1251da2e3ebdSchin 		char *savet=0;
1252da2e3ebdSchin 		struct stat statb;
1253da2e3ebdSchin 		if((n=sh_open(path,O_RDONLY,0)) >= 0)
1254da2e3ebdSchin 		{
1255da2e3ebdSchin 			/* move <n> if n=0,1,2 */
1256da2e3ebdSchin 			n = sh_iomovefd(n);
1257da2e3ebdSchin 			if(fstat(n,&statb)>=0 && !(statb.st_mode&(S_ISUID|S_ISGID)))
1258da2e3ebdSchin 				goto openok;
1259da2e3ebdSchin 			sh_close(n);
1260da2e3ebdSchin 		}
1261da2e3ebdSchin 		if((euserid=geteuid()) != shp->userid)
1262da2e3ebdSchin 		{
1263da2e3ebdSchin 			strncpy(name+9,fmtbase((long)getpid(),10,0),sizeof(name)-10);
1264da2e3ebdSchin 			/* create a suid open file with owner equal effective uid */
1265da2e3ebdSchin 			if((n=open(name,O_CREAT|O_TRUNC|O_WRONLY,S_ISUID|S_IXUSR)) < 0)
1266da2e3ebdSchin 				goto fail;
1267da2e3ebdSchin 			unlink(name);
1268da2e3ebdSchin 			/* make sure that file has right owner */
1269da2e3ebdSchin 			if(fstat(n,&statb)<0 || statb.st_uid != euserid)
1270da2e3ebdSchin 				goto fail;
1271da2e3ebdSchin 			if(n!=10)
1272da2e3ebdSchin 			{
1273da2e3ebdSchin 				sh_close(10);
1274da2e3ebdSchin 				fcntl(n, F_DUPFD, 10);
1275da2e3ebdSchin 				sh_close(n);
1276da2e3ebdSchin 				n=10;
1277da2e3ebdSchin 			}
1278da2e3ebdSchin 		}
1279da2e3ebdSchin 		savet = *--argv;
1280da2e3ebdSchin 		*argv = path;
1281da2e3ebdSchin 		path_pfexecve(e_suidexec,argv,envp,0);
1282da2e3ebdSchin 	fail:
12837c2fbfb3SApril Chin 		/*
1284da2e3ebdSchin 		 *  The following code is just for compatibility
1285da2e3ebdSchin 		 */
1286da2e3ebdSchin 		if((n=open(path,O_RDONLY,0)) < 0)
1287da2e3ebdSchin 			errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path);
1288da2e3ebdSchin 		if(savet)
12897c2fbfb3SApril Chin 			*argv++ = savet;
1290da2e3ebdSchin 	openok:
1291da2e3ebdSchin 		shp->infd = n;
1292da2e3ebdSchin 	}
1293da2e3ebdSchin #else
1294da2e3ebdSchin 	if((shp->infd = sh_open(path,O_RDONLY,0)) < 0)
1295da2e3ebdSchin 		errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path);
12967c2fbfb3SApril Chin #endif
12977c2fbfb3SApril Chin 	shp->infd = sh_iomovefd(shp->infd);
1298da2e3ebdSchin #if SHOPT_ACCT
1299da2e3ebdSchin 	sh_accbegin(path) ;  /* reset accounting */
1300da2e3ebdSchin #endif	/* SHOPT_ACCT */
1301da2e3ebdSchin 	shp->arglist = sh_argcreate(argv);
1302da2e3ebdSchin 	shp->lastarg = strdup(path);
1303da2e3ebdSchin 	/* save name of calling command */
1304da2e3ebdSchin 	shp->readscript = error_info.id;
1305da2e3ebdSchin 	/* close history file if name has changed */
1306da2e3ebdSchin 	if(shp->hist_ptr && (path=nv_getval(HISTFILE)) && strcmp(path,shp->hist_ptr->histname))
1307da2e3ebdSchin 	{
1308da2e3ebdSchin 		hist_close(shp->hist_ptr);
1309da2e3ebdSchin 		(HISTCUR)->nvalue.lp = 0;
1310da2e3ebdSchin 	}
1311da2e3ebdSchin 	sh_offstate(SH_FORKED);
1312da2e3ebdSchin 	if(shp->sigflag[SIGCHLD]==SH_SIGOFF)
1313da2e3ebdSchin 		shp->sigflag[SIGCHLD] = SH_SIGFAULT;
131434f9b3eeSRoland Mainz 	siglongjmp(*shp->jmplist,SH_JMPSCRIPT);
131534f9b3eeSRoland Mainz }
1316da2e3ebdSchin 
1317da2e3ebdSchin #if SHOPT_ACCT
1318da2e3ebdSchin #   include <sys/acct.h>
1319da2e3ebdSchin #   include "FEATURE/time"
1320da2e3ebdSchin 
1321da2e3ebdSchin     static struct acct sabuf;
1322da2e3ebdSchin     static struct tms buffer;
1323da2e3ebdSchin     static clock_t	before;
1324da2e3ebdSchin     static char *SHACCT; /* set to value of SHACCT environment variable */
1325da2e3ebdSchin     static shaccton;	/* non-zero causes accounting record to be written */
1326da2e3ebdSchin     static int compress(time_t);
1327da2e3ebdSchin     /*
1328da2e3ebdSchin      *	initialize accounting, i.e., see if SHACCT variable set
1329da2e3ebdSchin      */
sh_accinit(void)1330da2e3ebdSchin     void sh_accinit(void)
1331da2e3ebdSchin     {
1332da2e3ebdSchin 	SHACCT = getenv("SHACCT");
1333da2e3ebdSchin     }
1334da2e3ebdSchin     /*
1335da2e3ebdSchin     * suspend accounting until turned on by sh_accbegin()
1336da2e3ebdSchin     */
sh_accsusp(void)13377c2fbfb3SApril Chin     void sh_accsusp(void)
1338da2e3ebdSchin     {
1339da2e3ebdSchin 	shaccton=0;
1340da2e3ebdSchin #ifdef AEXPAND
1341da2e3ebdSchin 	sabuf.ac_flag |= AEXPND;
1342da2e3ebdSchin #endif /* AEXPAND */
1343da2e3ebdSchin     }
1344da2e3ebdSchin 
1345da2e3ebdSchin     /*
1346da2e3ebdSchin      * begin an accounting record by recording start time
1347da2e3ebdSchin      */
sh_accbegin(const char * cmdname)1348da2e3ebdSchin     void sh_accbegin(const char *cmdname)
1349da2e3ebdSchin     {
1350da2e3ebdSchin 	if(SHACCT)
1351da2e3ebdSchin 	{
1352da2e3ebdSchin 		sabuf.ac_btime = time(NIL(time_t *));
1353da2e3ebdSchin 		before = times(&buffer);
1354da2e3ebdSchin 		sabuf.ac_uid = getuid();
1355da2e3ebdSchin 		sabuf.ac_gid = getgid();
1356da2e3ebdSchin 		strncpy(sabuf.ac_comm, (char*)path_basename(cmdname),
1357da2e3ebdSchin 			sizeof(sabuf.ac_comm));
1358da2e3ebdSchin 		shaccton = 1;
1359da2e3ebdSchin 	}
1360da2e3ebdSchin     }
1361da2e3ebdSchin     /*
1362da2e3ebdSchin      * terminate an accounting record and append to accounting file
1363da2e3ebdSchin      */
sh_accend(void)1364da2e3ebdSchin     void	sh_accend(void)
1365da2e3ebdSchin     {
1366da2e3ebdSchin 	int	fd;
1367da2e3ebdSchin 	clock_t	after;
1368da2e3ebdSchin 
1369da2e3ebdSchin 	if(shaccton)
1370da2e3ebdSchin 	{
1371da2e3ebdSchin 		after = times(&buffer);
1372da2e3ebdSchin 		sabuf.ac_utime = compress(buffer.tms_utime + buffer.tms_cutime);
1373da2e3ebdSchin 		sabuf.ac_stime = compress(buffer.tms_stime + buffer.tms_cstime);
1374da2e3ebdSchin 		sabuf.ac_etime = compress( (time_t)(after-before));
1375da2e3ebdSchin 		fd = open( SHACCT , O_WRONLY | O_APPEND | O_CREAT,RW_ALL);
1376da2e3ebdSchin 		write(fd, (const char*)&sabuf, sizeof( sabuf ));
1377da2e3ebdSchin 		close( fd);
1378da2e3ebdSchin 	}
1379da2e3ebdSchin     }
1380da2e3ebdSchin 
1381da2e3ebdSchin     /*
1382da2e3ebdSchin      * Produce a pseudo-floating point representation
1383da2e3ebdSchin      * with 3 bits base-8 exponent, 13 bits fraction.
1384da2e3ebdSchin      */
compress(register time_t t)1385da2e3ebdSchin     static int compress(register time_t t)
1386da2e3ebdSchin     {
1387da2e3ebdSchin 	register int exp = 0, rund = 0;
1388da2e3ebdSchin 
1389da2e3ebdSchin 	while (t >= 8192)
1390da2e3ebdSchin 	{
1391da2e3ebdSchin 		exp++;
1392da2e3ebdSchin 		rund = t&04;
1393da2e3ebdSchin 		t >>= 3;
1394da2e3ebdSchin 	}
1395da2e3ebdSchin 	if (rund)
1396da2e3ebdSchin 	{
1397da2e3ebdSchin 		t++;
1398da2e3ebdSchin 		if (t >= 8192)
1399da2e3ebdSchin 		{
1400da2e3ebdSchin 			t >>= 3;
1401da2e3ebdSchin 			exp++;
1402da2e3ebdSchin 		}
1403da2e3ebdSchin 	}
1404da2e3ebdSchin 	return((exp<<13) + t);
1405da2e3ebdSchin     }
1406da2e3ebdSchin #endif	/* SHOPT_ACCT */
1407da2e3ebdSchin 
1408da2e3ebdSchin 
1409da2e3ebdSchin 
1410da2e3ebdSchin /*
1411da2e3ebdSchin  * add a pathcomponent to the path search list and eliminate duplicates
1412da2e3ebdSchin  * and non-existing absolute paths.
1413da2e3ebdSchin  */
path_addcomp(Pathcomp_t * first,Pathcomp_t * old,const char * name,int flag)1414da2e3ebdSchin static Pathcomp_t *path_addcomp(Pathcomp_t *first, Pathcomp_t *old,const char *name, int flag)
1415da2e3ebdSchin {
1416da2e3ebdSchin 	register Pathcomp_t *pp, *oldpp;
1417da2e3ebdSchin 	int len, offset=staktell();
1418da2e3ebdSchin 	if(!(flag&PATH_BFPATH))
1419da2e3ebdSchin 	{
1420da2e3ebdSchin 		register const char *cp = name;
1421da2e3ebdSchin 		while(*cp && *cp!=':')
1422da2e3ebdSchin 			stakputc(*cp++);
1423da2e3ebdSchin 		len = staktell()-offset;
1424da2e3ebdSchin 		stakputc(0);
1425da2e3ebdSchin 		stakseek(offset);
1426da2e3ebdSchin 		name = (const char*)stakptr(offset);
1427da2e3ebdSchin 	}
1428da2e3ebdSchin 	else
1429da2e3ebdSchin 		len = strlen(name);
1430da2e3ebdSchin 	for(pp=first; pp; pp=pp->next)
1431da2e3ebdSchin 	{
1432da2e3ebdSchin 		if(memcmp(name,pp->name,len)==0 && (pp->name[len]==':' || pp->name[len]==0))
1433da2e3ebdSchin 		{
1434da2e3ebdSchin 			pp->flags |= flag;
1435da2e3ebdSchin 			return(first);
1436da2e3ebdSchin 		}
1437da2e3ebdSchin 	}
1438da2e3ebdSchin 	for(pp=first, oldpp=0; pp; oldpp=pp, pp=pp->next);
1439da2e3ebdSchin 	pp = newof((Pathcomp_t*)0,Pathcomp_t,1,len+1);
144034f9b3eeSRoland Mainz 	pp->refcount = 1;
1441da2e3ebdSchin 	memcpy((char*)(pp+1),name,len+1);
1442da2e3ebdSchin 	pp->name = (char*)(pp+1);
1443da2e3ebdSchin 	pp->len = len;
1444da2e3ebdSchin 	if(oldpp)
1445da2e3ebdSchin 		oldpp->next = pp;
1446da2e3ebdSchin 	else
1447da2e3ebdSchin 		first = pp;
1448da2e3ebdSchin 	pp->flags = flag;
1449da2e3ebdSchin 	if(strcmp(name,SH_CMDLIB_DIR)==0)
1450da2e3ebdSchin 	{
145134f9b3eeSRoland Mainz 		pp->dev = 1;
1452da2e3ebdSchin 		pp->flags |= PATH_BUILTIN_LIB;
145334f9b3eeSRoland Mainz 		pp->blib = malloc(4);
1454da2e3ebdSchin 		strcpy(pp->blib,LIBCMD);
1455da2e3ebdSchin 		return(first);
1456da2e3ebdSchin 	}
1457da2e3ebdSchin 	if(old && ((flag&(PATH_PATH|PATH_SKIP))==PATH_PATH))
1458da2e3ebdSchin 		path_chkpaths(first,old,pp,offset);
145934f9b3eeSRoland Mainz 	return(first);
1460da2e3ebdSchin }
1461da2e3ebdSchin 
1462da2e3ebdSchin /*
1463da2e3ebdSchin  * This function checks for the .paths file in directory in <pp>
1464da2e3ebdSchin  * it assumes that the directory is on the stack at <offset>
1465da2e3ebdSchin  */
path_chkpaths(Pathcomp_t * first,Pathcomp_t * old,Pathcomp_t * pp,int offset)1466da2e3ebdSchin static int path_chkpaths(Pathcomp_t *first, Pathcomp_t* old,Pathcomp_t *pp, int offset)
1467da2e3ebdSchin {
1468da2e3ebdSchin 	struct stat statb;
1469da2e3ebdSchin 	int k,m,n,fd;
1470da2e3ebdSchin 	char *sp,*cp,*ep;
1471da2e3ebdSchin 	stakseek(offset+pp->len);
1472da2e3ebdSchin 	if(pp->len==1 && *stakptr(offset)=='/')
1473da2e3ebdSchin 		stakseek(offset);
1474da2e3ebdSchin 	stakputs("/.paths");
1475da2e3ebdSchin 	if((fd=open(stakptr(offset),O_RDONLY))>=0)
1476da2e3ebdSchin 	{
1477da2e3ebdSchin 		fstat(fd,&statb);
1478da2e3ebdSchin 		n = statb.st_size;
1479da2e3ebdSchin 		stakseek(offset+pp->len+n+2);
1480da2e3ebdSchin 		sp = stakptr(offset+pp->len);
1481da2e3ebdSchin 		*sp++ = '/';
1482da2e3ebdSchin 		n=read(fd,cp=sp,n);
1483da2e3ebdSchin 		sp[n] = 0;
1484da2e3ebdSchin 		close(fd);
1485da2e3ebdSchin 		for(ep=0; n--; cp++)
1486da2e3ebdSchin 		{
1487da2e3ebdSchin 			if(*cp=='=')
1488da2e3ebdSchin 			{
1489da2e3ebdSchin 				ep = cp+1;
1490da2e3ebdSchin 				continue;
1491da2e3ebdSchin 			}
1492da2e3ebdSchin 			else if(*cp!='\r' &&  *cp!='\n')
1493da2e3ebdSchin 				continue;
1494da2e3ebdSchin 			if(*sp=='#' || sp==cp)
1495da2e3ebdSchin 			{
1496da2e3ebdSchin 				sp = cp+1;
1497da2e3ebdSchin 				continue;
1498da2e3ebdSchin 			}
1499da2e3ebdSchin 			*cp = 0;
1500da2e3ebdSchin 			m = ep ? (ep-sp) : 0;
1501da2e3ebdSchin 			if(m==0 || m==6 && memcmp((void*)sp,(void*)"FPATH=",6)==0)
1502da2e3ebdSchin 			{
15033e14f97fSRoger A. Faulkner 				if(first)
1504da2e3ebdSchin 				{
1505da2e3ebdSchin 					char *ptr = stakptr(offset+pp->len+1);
1506da2e3ebdSchin 					if(ep)
1507da2e3ebdSchin 						strcpy(ptr,ep);
1508da2e3ebdSchin 					path_addcomp(first,old,stakptr(offset),PATH_FPATH|PATH_BFPATH);
1509da2e3ebdSchin 				}
1510da2e3ebdSchin 			}
1511da2e3ebdSchin 			else if(m==12 && memcmp((void*)sp,(void*)"BUILTIN_LIB=",12)==0)
1512da2e3ebdSchin 			{
1513da2e3ebdSchin 				if(!(pp->flags & PATH_BUILTIN_LIB) || strchr(ep,'-'))
1514da2e3ebdSchin 				{
15153e14f97fSRoger A. Faulkner 					if ((pp->flags & (PATH_BUILTIN_LIB|PATH_STD_DIR)) == PATH_BUILTIN_LIB)
1516da2e3ebdSchin 					{
15173e14f97fSRoger A. Faulkner 						free(pp->blib);
15183e14f97fSRoger A. Faulkner 						pp->blib = 0;
15193e14f97fSRoger A. Faulkner 					}
15203e14f97fSRoger A. Faulkner 					pp->flags |= PATH_BUILTIN_LIB;
15213e14f97fSRoger A. Faulkner 					if (*ep == '.' && !*(ep + 1))
1522da2e3ebdSchin 						pp->flags |= PATH_STD_DIR;
1523da2e3ebdSchin 					else
1524da2e3ebdSchin 					{
1525da2e3ebdSchin 						k = strlen(ep)+1;
1526da2e3ebdSchin 						if (*ep != '/')
1527da2e3ebdSchin 							k +=  pp->len+1;
1528da2e3ebdSchin 						pp->blib = sp = malloc(k);
1529da2e3ebdSchin 						if (*ep != '/')
1530da2e3ebdSchin 						{
1531da2e3ebdSchin 							strcpy(pp->blib,pp->name);
1532da2e3ebdSchin 							sp += pp->len;
1533da2e3ebdSchin 							*sp++ = '/';
1534da2e3ebdSchin 						}
1535da2e3ebdSchin 						strcpy(sp,ep);
1536da2e3ebdSchin 					}
1537da2e3ebdSchin 				}
1538da2e3ebdSchin 			}
1539da2e3ebdSchin 			else if(m)
1540da2e3ebdSchin 			{
1541da2e3ebdSchin 				pp->lib = (char*)malloc(cp-sp+pp->len+2);
1542da2e3ebdSchin 				memcpy((void*)pp->lib,(void*)sp,m);
1543da2e3ebdSchin 				memcpy((void*)&pp->lib[m],stakptr(offset),pp->len);
1544da2e3ebdSchin 				pp->lib[k=m+pp->len] = '/';
1545da2e3ebdSchin 				strcpy((void*)&pp->lib[k+1],ep);
1546da2e3ebdSchin 				pathcanon(&pp->lib[m],0);
1547da2e3ebdSchin 				if(!first)
1548da2e3ebdSchin 				{
1549da2e3ebdSchin 					stakseek(0);
1550da2e3ebdSchin 					stakputs(pp->lib);
1551da2e3ebdSchin 					free((void*)pp->lib);
1552da2e3ebdSchin 					return(1);
1553da2e3ebdSchin 				}
1554da2e3ebdSchin 			}
1555da2e3ebdSchin 			sp = cp+1;
1556da2e3ebdSchin 			ep = 0;
1557da2e3ebdSchin 		}
1558da2e3ebdSchin 	}
1559da2e3ebdSchin 	return(0);
1560da2e3ebdSchin }
1561da2e3ebdSchin 
1562da2e3ebdSchin 
path_addpath(Pathcomp_t * first,register const char * path,int type)1563da2e3ebdSchin Pathcomp_t *path_addpath(Pathcomp_t *first, register const char *path,int type)
1564da2e3ebdSchin {
1565da2e3ebdSchin 	register const char *cp;
1566da2e3ebdSchin 	Pathcomp_t *old=0;
1567da2e3ebdSchin 	int offset = staktell();
1568da2e3ebdSchin 	char *savptr;
1569da2e3ebdSchin 
1570da2e3ebdSchin 	if(!path && type!=PATH_PATH)
1571da2e3ebdSchin 		return(first);
1572da2e3ebdSchin 	if(type!=PATH_FPATH)
1573da2e3ebdSchin 	{
1574da2e3ebdSchin 		old = first;
1575da2e3ebdSchin 		first = 0;
1576da2e3ebdSchin 	}
1577da2e3ebdSchin 	if(offset)
1578da2e3ebdSchin 		savptr = stakfreeze(0);
1579da2e3ebdSchin 	if(path) while(*(cp=path))
1580da2e3ebdSchin 	{
1581da2e3ebdSchin 		if(*cp==':')
1582da2e3ebdSchin 		{
1583da2e3ebdSchin 			if(type!=PATH_FPATH)
1584da2e3ebdSchin 				first = path_addcomp(first,old,".",type);
1585da2e3ebdSchin 			while(*++path == ':');
1586da2e3ebdSchin 		}
1587da2e3ebdSchin 		else
1588da2e3ebdSchin 		{
1589da2e3ebdSchin 			int c;
1590da2e3ebdSchin 			while(*path && *path!=':')
1591da2e3ebdSchin 				path++;
1592da2e3ebdSchin 			c = *path++;
1593da2e3ebdSchin 			first = path_addcomp(first,old,cp,type);
1594da2e3ebdSchin 			if(c==0)
1595da2e3ebdSchin 				break;
1596da2e3ebdSchin 			if(*path==0)
1597da2e3ebdSchin 				path--;
1598da2e3ebdSchin 		}
1599da2e3ebdSchin 	}
1600da2e3ebdSchin 	if(old)
1601da2e3ebdSchin 	{
1602da2e3ebdSchin 		if(!first && !path)
1603da2e3ebdSchin 		{
1604da2e3ebdSchin 			Pathcomp_t *pp = (Pathcomp_t*)old->shp->defpathlist;
1605da2e3ebdSchin 			if(!pp)
1606da2e3ebdSchin 				pp = defpath_init(old->shp);
1607da2e3ebdSchin 			first = path_dup(pp);
1608da2e3ebdSchin 		}
1609da2e3ebdSchin 		if(cp=(FPATHNOD)->nvalue.cp)
1610da2e3ebdSchin 			first = (void*)path_addpath((Pathcomp_t*)first,cp,PATH_FPATH);
1611da2e3ebdSchin 		path_delete(old);
1612da2e3ebdSchin 	}
1613da2e3ebdSchin 	if(offset)
1614da2e3ebdSchin 		stakset(savptr,offset);
1615da2e3ebdSchin 	else
1616da2e3ebdSchin 		stakseek(0);
1617da2e3ebdSchin 	return(first);
1618da2e3ebdSchin }
1619da2e3ebdSchin 
1620da2e3ebdSchin /*
1621da2e3ebdSchin  * duplicate the path give by <first> by incremented reference counts
1622da2e3ebdSchin  */
path_dup(Pathcomp_t * first)1623da2e3ebdSchin Pathcomp_t *path_dup(Pathcomp_t *first)
1624da2e3ebdSchin {
1625da2e3ebdSchin 	register Pathcomp_t *pp=first;
1626da2e3ebdSchin 	while(pp)
1627da2e3ebdSchin 	{
1628da2e3ebdSchin 		pp->refcount++;
1629da2e3ebdSchin 		pp = pp->next;
1630da2e3ebdSchin 	}
1631da2e3ebdSchin 	return(first);
1632da2e3ebdSchin }
1633da2e3ebdSchin 
1634da2e3ebdSchin /*
1635da2e3ebdSchin  * called whenever the directory is changed
1636da2e3ebdSchin  */
path_newdir(Pathcomp_t * first)1637da2e3ebdSchin void path_newdir(Pathcomp_t *first)
1638da2e3ebdSchin {
1639da2e3ebdSchin 	register Pathcomp_t *pp=first, *next, *pq;
1640da2e3ebdSchin 	struct stat statb;
1641da2e3ebdSchin 	for(pp=first; pp; pp=pp->next)
1642da2e3ebdSchin 	{
1643da2e3ebdSchin 		pp->flags &= ~PATH_SKIP;
1644da2e3ebdSchin 		if(*pp->name=='/')
1645da2e3ebdSchin 			continue;
1646da2e3ebdSchin 		/* delete .paths component */
1647da2e3ebdSchin 		if((next=pp->next) && (next->flags&PATH_BFPATH))
1648da2e3ebdSchin 		{
1649da2e3ebdSchin 			pp->next = next->next;
1650da2e3ebdSchin 			if(--next->refcount<=0)
1651da2e3ebdSchin 				free((void*)next);
1652da2e3ebdSchin 		}
1653da2e3ebdSchin 		if(stat(pp->name,&statb)<0 || !S_ISDIR(statb.st_mode))
1654da2e3ebdSchin 		{
1655da2e3ebdSchin 			pp->dev = 0;
1656da2e3ebdSchin 			pp->ino = 0;
1657da2e3ebdSchin 			continue;
1658da2e3ebdSchin 		}
1659da2e3ebdSchin 		pp->dev = statb.st_dev;
1660da2e3ebdSchin 		pp->ino = statb.st_ino;
1661da2e3ebdSchin 		pp->mtime = statb.st_mtime;
1662da2e3ebdSchin 		for(pq=first;pq!=pp;pq=pq->next)
16637c2fbfb3SApril Chin 		{
1664da2e3ebdSchin 			if(pp->ino==pq->ino && pp->dev==pq->dev)
1665da2e3ebdSchin 				pp->flags |= PATH_SKIP;
1666da2e3ebdSchin 		}
1667da2e3ebdSchin 		for(pq=pp;pq=pq->next;)
1668da2e3ebdSchin 		{
1669da2e3ebdSchin 			if(pp->ino==pq->ino && pp->dev==pq->dev)
1670da2e3ebdSchin 				pq->flags |= PATH_SKIP;
1671da2e3ebdSchin 		}
1672da2e3ebdSchin 		if((pp->flags&(PATH_PATH|PATH_SKIP))==PATH_PATH)
1673da2e3ebdSchin 		{
1674da2e3ebdSchin 			/* try to insert .paths component */
1675da2e3ebdSchin 			int offset = staktell();
1676da2e3ebdSchin 			stakputs(pp->name);
1677da2e3ebdSchin 			stakseek(offset);
1678da2e3ebdSchin 			next = pp->next;
1679da2e3ebdSchin 			pp->next = 0;
1680da2e3ebdSchin 			path_chkpaths(first,(Pathcomp_t*)0,pp,offset);
1681da2e3ebdSchin 			if(pp->next)
1682da2e3ebdSchin 				pp = pp->next;
1683da2e3ebdSchin 			pp->next = next;
1684da2e3ebdSchin 		}
1685da2e3ebdSchin 	}
1686da2e3ebdSchin #if 0
1687da2e3ebdSchin 	path_dump(first);
1688da2e3ebdSchin #endif
1689da2e3ebdSchin }
1690da2e3ebdSchin 
path_unsetfpath(Pathcomp_t * first)1691da2e3ebdSchin Pathcomp_t *path_unsetfpath(Pathcomp_t *first)
1692da2e3ebdSchin {
1693da2e3ebdSchin 	register Pathcomp_t *pp=first, *old=0;
1694da2e3ebdSchin 	Shell_t	*shp = &sh;
1695da2e3ebdSchin 	if(shp->fpathdict)
16967c2fbfb3SApril Chin 	{
16977c2fbfb3SApril Chin 		struct Ufunction  *rp, *rpnext;
16987c2fbfb3SApril Chin 		for(rp=(struct Ufunction*)dtfirst(shp->fpathdict);rp;rp=rpnext)
16997c2fbfb3SApril Chin 		{
17007c2fbfb3SApril Chin 			rpnext = (struct Ufunction*)dtnext(shp->fpathdict,rp);
17017c2fbfb3SApril Chin 			if(rp->fdict)
17027c2fbfb3SApril Chin 				nv_delete(rp->np,rp->fdict,NV_NOFREE);
17037c2fbfb3SApril Chin 			rp->fdict = 0;
17047c2fbfb3SApril Chin 		}
17057c2fbfb3SApril Chin 	}
17067c2fbfb3SApril Chin 	while(pp)
17077c2fbfb3SApril Chin 	{
1708da2e3ebdSchin 		if((pp->flags&PATH_FPATH) && !(pp->flags&PATH_BFPATH))
1709da2e3ebdSchin 		{
1710da2e3ebdSchin 			if(pp->flags&PATH_PATH)
1711da2e3ebdSchin 				pp->flags &= ~PATH_FPATH;
1712da2e3ebdSchin 			else
1713da2e3ebdSchin 			{
1714da2e3ebdSchin 				Pathcomp_t *ppsave=pp;
1715da2e3ebdSchin 				if(old)
1716da2e3ebdSchin 					old->next = pp->next;
1717da2e3ebdSchin 				else
1718da2e3ebdSchin 					first = pp->next;
1719da2e3ebdSchin 				pp = pp->next;
1720da2e3ebdSchin 				if(--ppsave->refcount<=0)
1721da2e3ebdSchin 				{
1722da2e3ebdSchin 					if(ppsave->lib)
1723da2e3ebdSchin 						free((void*)ppsave->lib);
1724da2e3ebdSchin 					free((void*)ppsave);
1725da2e3ebdSchin 				}
1726da2e3ebdSchin 				continue;
1727da2e3ebdSchin 			}
1728da2e3ebdSchin 
1729da2e3ebdSchin 		}
1730da2e3ebdSchin 		old = pp;
1731da2e3ebdSchin 		pp = pp->next;
1732da2e3ebdSchin 	}
1733da2e3ebdSchin 	return(first);
1734da2e3ebdSchin }
1735da2e3ebdSchin 
path_dirfind(Pathcomp_t * first,const char * name,int c)1736da2e3ebdSchin Pathcomp_t *path_dirfind(Pathcomp_t *first,const char *name,int c)
1737da2e3ebdSchin {
1738da2e3ebdSchin 	register Pathcomp_t *pp=first;
1739da2e3ebdSchin 	while(pp)
1740da2e3ebdSchin 	{
1741da2e3ebdSchin 		if(memcmp(name,pp->name,pp->len)==0 && name[pp->len]==c)
1742da2e3ebdSchin 			return(pp);
1743da2e3ebdSchin 		pp = pp->next;
1744da2e3ebdSchin 	}
1745da2e3ebdSchin 	return(0);
1746da2e3ebdSchin }
1747da2e3ebdSchin 
1748da2e3ebdSchin /*
1749da2e3ebdSchin  * get discipline for tracked alias
1750da2e3ebdSchin  */
talias_get(Namval_t * np,Namfun_t * nvp)1751da2e3ebdSchin static char *talias_get(Namval_t *np, Namfun_t *nvp)
1752da2e3ebdSchin {
1753da2e3ebdSchin 	Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp;
1754da2e3ebdSchin 	char *ptr;
1755da2e3ebdSchin 	if(!pp)
1756da2e3ebdSchin 		return(NULL);
1757da2e3ebdSchin 	path_nextcomp(pp,nv_name(np),pp);
1758da2e3ebdSchin 	ptr = stakfreeze(0);
1759da2e3ebdSchin 	return(ptr+PATH_OFFSET);
1760da2e3ebdSchin }
1761da2e3ebdSchin 
talias_put(register Namval_t * np,const char * val,int flags,Namfun_t * fp)1762da2e3ebdSchin static void talias_put(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
1763da2e3ebdSchin {
1764da2e3ebdSchin 	if(!val && np->nvalue.cp)
1765da2e3ebdSchin 	{
1766da2e3ebdSchin 		Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp;
1767da2e3ebdSchin 		if(--pp->refcount<=0)
1768da2e3ebdSchin 			free((void*)pp);
1769da2e3ebdSchin 	}
1770da2e3ebdSchin 	nv_putv(np,val,flags,fp);
1771da2e3ebdSchin }
1772da2e3ebdSchin 
1773da2e3ebdSchin static const Namdisc_t talias_disc   = { 0, talias_put, talias_get   };
1774da2e3ebdSchin static Namfun_t  talias_init = { &talias_disc, 1 };
1775da2e3ebdSchin 
1776da2e3ebdSchin /*
1777da2e3ebdSchin  *  set tracked alias node <np> to value <pp>
1778da2e3ebdSchin  */
path_alias(register Namval_t * np,register Pathcomp_t * pp)1779da2e3ebdSchin void path_alias(register Namval_t *np,register Pathcomp_t *pp)
1780da2e3ebdSchin {
1781da2e3ebdSchin 	if(pp)
1782da2e3ebdSchin 	{
1783da2e3ebdSchin 		struct stat statb;
1784da2e3ebdSchin 		char *sp;
1785da2e3ebdSchin 		nv_offattr(np,NV_NOPRINT);
1786da2e3ebdSchin 		nv_stack(np,&talias_init);
1787da2e3ebdSchin 		np->nvalue.cp = (char*)pp;
1788da2e3ebdSchin 		pp->refcount++;
1789da2e3ebdSchin 		nv_setattr(np,NV_TAGGED|NV_NOFREE);
1790da2e3ebdSchin 		path_nextcomp(pp,nv_name(np),pp);
1791da2e3ebdSchin 		sp = stakptr(PATH_OFFSET);
1792da2e3ebdSchin 		if(sp && lstat(sp,&statb)>=0 && S_ISLNK(statb.st_mode))
1793da2e3ebdSchin 			nv_setsize(np,statb.st_size+1);
1794da2e3ebdSchin 		else
1795da2e3ebdSchin 			nv_setsize(np,0);
1796da2e3ebdSchin 	}
1797da2e3ebdSchin 	else
1798da2e3ebdSchin 		nv_unset(np);
1799da2e3ebdSchin }
1800da2e3ebdSchin 
1801da2e3ebdSchin