Blame src/cmd/ksh93/sh/path.c

Packit 992a25
/***********************************************************************
Packit 992a25
*                                                                      *
Packit 992a25
*               This software is part of the ast package               *
Packit 992a25
*          Copyright (c) 1982-2012 AT&T Intellectual Property          *
Packit 992a25
*                      and is licensed under the                       *
Packit 992a25
*                 Eclipse Public License, Version 1.0                  *
Packit 992a25
*                    by AT&T Intellectual Property                     *
Packit 992a25
*                                                                      *
Packit 992a25
*                A copy of the License is available at                 *
Packit 992a25
*          http://www.eclipse.org/org/documents/epl-v10.html           *
Packit 992a25
*         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
Packit 992a25
*                                                                      *
Packit 992a25
*              Information and Software Systems Research               *
Packit 992a25
*                            AT&T Research                             *
Packit 992a25
*                           Florham Park NJ                            *
Packit 992a25
*                                                                      *
Packit 992a25
*                  David Korn <dgk@research.att.com>                   *
Packit 992a25
*                                                                      *
Packit 992a25
***********************************************************************/
Packit 992a25
#pragma prototyped
Packit 992a25
/*
Packit 992a25
 * David Korn
Packit 992a25
 * AT&T Labs
Packit 992a25
 *
Packit 992a25
 */
Packit 992a25
Packit 992a25
#include	"defs.h"
Packit 992a25
#include	<fcin.h>
Packit 992a25
#include	<ls.h>
Packit 992a25
#include	<nval.h>
Packit 992a25
#include	"variables.h"
Packit 992a25
#include	"path.h"
Packit 992a25
#include	"io.h"
Packit 992a25
#include	"jobs.h"
Packit 992a25
#include	"history.h"
Packit 992a25
#include	"test.h"
Packit 992a25
#include	"FEATURE/dynamic"
Packit 992a25
#include	"FEATURE/externs"
Packit 992a25
#if SHOPT_PFSH 
Packit 992a25
#   ifdef _hdr_exec_attr
Packit 992a25
#	include	<exec_attr.h>
Packit 992a25
#   endif
Packit 992a25
#   if     _lib_vfork
Packit 992a25
#	include     <ast_vfork.h>
Packit 992a25
#   else
Packit 992a25
#	define vfork()      fork()
Packit 992a25
#   endif
Packit 992a25
#endif
Packit 992a25
Packit 992a25
#define RW_ALL	(S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH)
Packit 992a25
#define LIBCMD	"cmd"
Packit 992a25
Packit 992a25
Packit 992a25
static int		canexecute(Shell_t*,char*,int);
Packit 992a25
static void		funload(Shell_t*,int,const char*);
Packit 992a25
static void		exscript(Shell_t*,char*, char*[], char**);
Packit 992a25
static int		path_chkpaths(Shell_t*,Pathcomp_t*,Pathcomp_t*,Pathcomp_t*,int);
Packit 992a25
static void		path_checkdup(Shell_t *shp,register Pathcomp_t*);
Packit 992a25
Packit 992a25
static const char	*std_path;
Packit 992a25
Packit 992a25
static int onstdpath(const char *name)
Packit 992a25
{
Packit 992a25
	register const char *cp = std_path, *sp;
Packit 992a25
	if(cp)
Packit 992a25
		while(*cp)
Packit 992a25
		{
Packit 992a25
			for(sp=name; *sp && (*cp == *sp); sp++,cp++);
Packit 992a25
			if(*sp==0 && (*cp==0 || *cp==':'))
Packit 992a25
				return(1);
Packit 992a25
			while(*cp && *cp++!=':');
Packit 992a25
		}
Packit 992a25
	return(0);
Packit 992a25
}
Packit 992a25
Packit 992a25
#if SHOPT_PFSH 
Packit 992a25
int path_xattr(Shell_t *shp, const char *path, char *rpath)
Packit 992a25
{
Packit 992a25
	char  resolvedpath[PATH_MAX + 1];
Packit 992a25
	if (shp->gd->user && *shp->gd->user)
Packit 992a25
	{
Packit 992a25
		execattr_t *pf;
Packit 992a25
		if(!rpath)
Packit 992a25
			rpath = resolvedpath;
Packit 992a25
		if (!realpath(path, resolvedpath))
Packit 992a25
			return -1;
Packit 992a25
		if(pf=getexecuser(shp->gd->user, KV_COMMAND, resolvedpath, GET_ONE))
Packit 992a25
		{
Packit 992a25
			if (!pf->attr || pf->attr->length == 0)
Packit 992a25
			{
Packit 992a25
				free_execattr(pf);
Packit 992a25
				return(0);
Packit 992a25
			}
Packit 992a25
			free_execattr(pf);
Packit 992a25
			return(1);
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
	errno = ENOENT;
Packit 992a25
	return(-1);
Packit 992a25
}
Packit 992a25
#endif /* SHOPT_PFSH */
Packit 992a25
Packit 992a25
static pid_t path_pfexecve(Shell_t *shp,const char *path, char *argv[],char *const envp[],int spawn)
Packit 992a25
{
Packit 992a25
#if SHOPT_PFSH 
Packit 992a25
	char  resolvedpath[PATH_MAX + 1];
Packit 992a25
	pid_t	pid;
Packit 992a25
	if(spawn)
Packit 992a25
	{
Packit 992a25
		while((pid = vfork()) < 0)
Packit 992a25
			_sh_fork(shp,pid, 0, (int*)0);
Packit 992a25
		if(pid)
Packit 992a25
			return(pid);
Packit 992a25
	}
Packit 992a25
	if(!sh_isoption(SH_PFSH))
Packit 992a25
		return(execve(path, argv, envp));
Packit 992a25
	/* Solaris implements realpath(3C) using the resolvepath(2) */
Packit 992a25
	/* system call so we can save us to call access(2) first */
Packit 992a25
Packit 992a25
	/* we can exec the command directly instead of via pfexec(1) if */
Packit 992a25
	/* there is a matching entry without attributes in exec_attr(4) */
Packit 992a25
	if(!path_xattr(shp,path,resolvedpath))
Packit 992a25
		return(execve(path, argv, envp));
Packit 992a25
	--argv;
Packit 992a25
	argv[0] = argv[1];
Packit 992a25
	argv[1] = resolvedpath;
Packit 992a25
	return(execve("/usr/bin/pfexec", argv, envp));
Packit 992a25
#else
Packit 992a25
	return(execve(path, argv, envp));
Packit 992a25
#endif
Packit 992a25
}
Packit 992a25
Packit 992a25
Packit 992a25
static pid_t _spawnveg(Shell_t *shp,const char *path, char* const argv[], char* const envp[], pid_t pgid)
Packit 992a25
{
Packit 992a25
	pid_t pid;
Packit 992a25
	while(1)
Packit 992a25
	{
Packit 992a25
		sh_stats(STAT_SPAWN);
Packit 992a25
		pid = spawnveg(path,argv,envp,pgid);
Packit 992a25
		if(pid>=0 || errno!=EAGAIN)
Packit 992a25
			break;
Packit 992a25
	}
Packit 992a25
	return(pid);
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * used with command -x to run the command in multiple passes
Packit 992a25
 * spawn is non-zero when invoked via spawn
Packit 992a25
 * the exitval is set to the maximum for each execution
Packit 992a25
 */
Packit 992a25
static pid_t path_xargs(Shell_t *shp,const char *path, char *argv[],char *const envp[], int spawn)
Packit 992a25
{
Packit 992a25
	register char *cp, **av, **xv;
Packit 992a25
	char **avlast= &argv[shp->xargmax], **saveargs=0;
Packit 992a25
	char *const *ev;
Packit 992a25
	long size, left;
Packit 992a25
	int nlast=1,n,exitval=0;
Packit 992a25
	pid_t pid;
Packit 992a25
	if(shp->xargmin < 0)
Packit 992a25
		return((pid_t)-1);
Packit 992a25
	size = shp->gd->lim.arg_max-1024;
Packit 992a25
	for(ev=envp; cp= *ev; ev++)
Packit 992a25
		size -= strlen(cp)-1;
Packit 992a25
	for(av=argv; (cp= *av) && av< &argv[shp->xargmin]; av++)  
Packit 992a25
		size -= strlen(cp)-1;
Packit 992a25
	for(av=avlast; cp= *av; av++,nlast++)  
Packit 992a25
		size -= strlen(cp)-1;
Packit 992a25
	av =  &argv[shp->xargmin];
Packit 992a25
	if(!spawn)
Packit 992a25
		job_clear();
Packit 992a25
	shp->exitval = 0;
Packit 992a25
	while(av
Packit 992a25
	{
Packit 992a25
		for(xv=av,left=size; left>0 && av
Packit 992a25
			left -= strlen(*av++)+1;
Packit 992a25
		/* leave at least two for last */
Packit 992a25
		if(left<0 && (avlast-av)<2)
Packit 992a25
			av--;
Packit 992a25
		if(xv==&argv[shp->xargmin])
Packit 992a25
		{
Packit 992a25
			n = nlast*sizeof(char*);
Packit 992a25
			saveargs = (char**)malloc(n);
Packit 992a25
			memcpy((void*)saveargs, (void*)av, n);
Packit 992a25
			memcpy((void*)av,(void*)avlast,n);
Packit 992a25
		}
Packit 992a25
		else
Packit 992a25
		{
Packit 992a25
			for(n=shp->xargmin; xv < av; xv++)
Packit 992a25
				argv[n++] = *xv;
Packit 992a25
			for(xv=avlast; cp=  *xv; xv++)
Packit 992a25
				argv[n++] = cp;
Packit 992a25
			argv[n] = 0;
Packit 992a25
		}
Packit 992a25
		if(saveargs || av
Packit 992a25
		{
Packit 992a25
			if((pid=_spawnveg(shp,path,argv,envp,0)) < 0)
Packit 992a25
				return(-1);
Packit 992a25
			job_post(shp,pid,0);
Packit 992a25
			job_wait(pid);
Packit 992a25
			if(shp->exitval>exitval)
Packit 992a25
				exitval = shp->exitval;
Packit 992a25
			if(saveargs)
Packit 992a25
			{
Packit 992a25
				memcpy((void*)av,saveargs,n);
Packit 992a25
				free((void*)saveargs);
Packit 992a25
				saveargs = 0;
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
		else if(spawn && !sh_isoption(SH_PFSH))
Packit 992a25
		{
Packit 992a25
			shp->xargexit = exitval;
Packit 992a25
			if(saveargs)
Packit 992a25
				free((void*)saveargs);
Packit 992a25
			return(_spawnveg(shp,path,argv,envp,spawn>>1));
Packit 992a25
		}
Packit 992a25
		else
Packit 992a25
		{
Packit 992a25
			if(saveargs)
Packit 992a25
				free((void*)saveargs);
Packit 992a25
			return(path_pfexecve(shp,path,argv,envp,spawn));
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
	if(!spawn)
Packit 992a25
		exit(exitval);
Packit 992a25
	return((pid_t)-1);
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * make sure PWD is set up correctly
Packit 992a25
 * Return the present working directory
Packit 992a25
 * Invokes getcwd() if necessary
Packit 992a25
 * Sets the PWD variable to this value
Packit 992a25
 */
Packit 992a25
char *path_pwd(Shell_t *shp,int flag)
Packit 992a25
{
Packit 992a25
	register char *cp;
Packit 992a25
	register int count = 0;
Packit 992a25
	if(shp->pwd)
Packit 992a25
		return((char*)shp->pwd);
Packit 992a25
	while(1) 
Packit 992a25
	{
Packit 992a25
		/* try from lowest to highest */
Packit 992a25
		switch(count++)
Packit 992a25
		{
Packit 992a25
			case 0:
Packit 992a25
				cp = nv_getval(PWDNOD);
Packit 992a25
				break;
Packit 992a25
			case 1:
Packit 992a25
				cp = nv_getval(HOME);
Packit 992a25
				break;
Packit 992a25
			case 2:
Packit 992a25
				cp = "/";
Packit 992a25
				break;
Packit 992a25
			case 3:
Packit 992a25
			{
Packit 992a25
				if(cp=getcwd(NIL(char*),0))
Packit 992a25
				{  
Packit 992a25
					nv_offattr(PWDNOD,NV_NOFREE);
Packit 992a25
					_nv_unset(PWDNOD,0);
Packit 992a25
					PWDNOD->nvalue.cp = cp;
Packit 992a25
					goto skip;
Packit 992a25
				}
Packit 992a25
				break;
Packit 992a25
			}
Packit 992a25
			case 4:
Packit 992a25
				return((char*)e_dot);
Packit 992a25
		}
Packit 992a25
		if(cp && *cp=='/' && test_inode(cp,e_dot))
Packit 992a25
			break;
Packit 992a25
	}
Packit 992a25
	if(count>1)
Packit 992a25
	{
Packit 992a25
		nv_offattr(PWDNOD,NV_NOFREE);
Packit 992a25
		nv_putval(PWDNOD,cp,NV_RDONLY);
Packit 992a25
	}
Packit 992a25
skip:
Packit 992a25
	nv_onattr(PWDNOD,NV_NOFREE|NV_EXPORT);
Packit 992a25
	shp->pwd = (char*)(PWDNOD->nvalue.cp);
Packit 992a25
	return(cp);
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * delete current Pathcomp_t structure
Packit 992a25
 */
Packit 992a25
void  path_delete(Pathcomp_t *first)
Packit 992a25
{
Packit 992a25
	register Pathcomp_t *pp=first, *old=0, *ppnext;
Packit 992a25
	while(pp)
Packit 992a25
	{
Packit 992a25
		ppnext = pp->next;
Packit 992a25
		if(--pp->refcount<=0)
Packit 992a25
		{
Packit 992a25
			if(pp->lib)
Packit 992a25
				free((void*)pp->lib);
Packit 992a25
			if(pp->bbuf)
Packit 992a25
				free((void*)pp->bbuf);
Packit 992a25
			free((void*)pp);
Packit 992a25
			if(old)
Packit 992a25
				old->next = ppnext;
Packit 992a25
		}
Packit 992a25
		else
Packit 992a25
			old = pp;
Packit 992a25
		pp = ppnext; 
Packit 992a25
	}
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * returns library variable from .paths
Packit 992a25
 * The value might be returned on the stack overwriting path
Packit 992a25
 */
Packit 992a25
static char *path_lib(Shell_t *shp,Pathcomp_t *pp, char *path)
Packit 992a25
{
Packit 992a25
	register char *last = strrchr(path,'/');
Packit 992a25
	register int r;
Packit 992a25
	struct stat statb;
Packit 992a25
	if(last)
Packit 992a25
		*last = 0;
Packit 992a25
	else
Packit 992a25
		path = ".";
Packit 992a25
	r = stat(path,&statb);
Packit 992a25
	if(last)
Packit 992a25
		*last = '/';
Packit 992a25
	if(r>=0)
Packit 992a25
	{
Packit 992a25
		Pathcomp_t pcomp;
Packit 992a25
		char save[8];
Packit 992a25
		for( ;pp; pp=pp->next)
Packit 992a25
		{
Packit 992a25
			path_checkdup(shp,pp);
Packit 992a25
			if(pp->ino==statb.st_ino && pp->dev==statb.st_dev && pp->mtime==statb.st_mtime)
Packit 992a25
				return(pp->lib);
Packit 992a25
		}
Packit 992a25
		pcomp.len = 0;
Packit 992a25
		if(last)
Packit 992a25
			pcomp.len = last-path;
Packit 992a25
		memcpy((void*)save, (void*)stakptr(PATH_OFFSET+pcomp.len),sizeof(save));
Packit 992a25
		if(path_chkpaths(shp,(Pathcomp_t*)0,(Pathcomp_t*)0,&pcomp,PATH_OFFSET))
Packit 992a25
			return(stakfreeze(1));
Packit 992a25
		memcpy((void*)stakptr(PATH_OFFSET+pcomp.len),(void*)save,sizeof(save));
Packit 992a25
	}
Packit 992a25
	return(0);
Packit 992a25
}
Packit 992a25
Packit 992a25
#if 0
Packit 992a25
void path_dump(register Pathcomp_t *pp)
Packit 992a25
{
Packit 992a25
	sfprintf(sfstderr,"dump\n");
Packit 992a25
	while(pp)
Packit 992a25
	{
Packit 992a25
		sfprintf(sfstderr,"pp=%x dev=%d ino=%d len=%d flags=%o name=%.*s\n",
Packit 992a25
			pp,pp->dev,pp->ino,pp->len,pp->flags,pp->len,pp->name);
Packit 992a25
		pp = pp->next;
Packit 992a25
	}
Packit 992a25
}
Packit 992a25
#endif
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * check for duplicate directories on PATH
Packit 992a25
 */
Packit 992a25
static void path_checkdup(Shell_t *shp,register Pathcomp_t *pp)
Packit 992a25
{
Packit 992a25
	register char		*name = pp->name;
Packit 992a25
	register Pathcomp_t	*oldpp,*first;
Packit 992a25
	register int		flag=0;
Packit 992a25
	struct stat 		statb;
Packit 992a25
	if(stat(name,&statb)<0 || !S_ISDIR(statb.st_mode))
Packit 992a25
	{
Packit 992a25
		pp->flags |= PATH_SKIP;
Packit 992a25
		pp->dev = *name=='/';
Packit 992a25
		return;
Packit 992a25
	}
Packit 992a25
	pp->mtime = statb.st_mtime;
Packit 992a25
	pp->ino = statb.st_ino;
Packit 992a25
	pp->dev = statb.st_dev;
Packit 992a25
	if(*name=='/' && onstdpath(name))
Packit 992a25
		flag = PATH_STD_DIR;
Packit 992a25
	first = (pp->flags&PATH_CDPATH)?(Pathcomp_t*)shp->cdpathlist:path_get(shp,"");
Packit 992a25
	for(oldpp=first; oldpp && oldpp!=pp; oldpp=oldpp->next)
Packit 992a25
	{
Packit 992a25
		if(pp->ino==oldpp->ino && pp->dev==oldpp->dev && pp->mtime==oldpp->mtime)
Packit 992a25
		{
Packit 992a25
			flag |= PATH_SKIP;
Packit 992a25
			break;
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
	pp->flags |= flag;
Packit 992a25
	if(((pp->flags&(PATH_PATH|PATH_SKIP))==PATH_PATH))
Packit 992a25
	{
Packit 992a25
		int offset = staktell();
Packit 992a25
		stakputs(name);
Packit 992a25
		path_chkpaths(shp,first,0,pp,offset);
Packit 992a25
		stakseek(offset);
Packit 992a25
	}
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * write the next path to search on the current stack
Packit 992a25
 * if last is given, all paths that come before <last> are skipped
Packit 992a25
 * the next pathcomp is returned.
Packit 992a25
 */
Packit 992a25
Pathcomp_t *path_nextcomp(Shell_t *shp,register Pathcomp_t *pp, const char *name, Pathcomp_t *last)
Packit 992a25
{
Packit 992a25
	Pathcomp_t	*ppnext;
Packit 992a25
	stakseek(PATH_OFFSET);
Packit 992a25
	if(*name=='/')
Packit 992a25
		pp = 0;
Packit 992a25
	else
Packit 992a25
	{
Packit 992a25
		for(;pp && pp!=last;pp=ppnext)
Packit 992a25
		{
Packit 992a25
			ppnext = pp->next;
Packit 992a25
			if(!pp->dev && !pp->ino)
Packit 992a25
				path_checkdup(shp,pp);
Packit 992a25
			if(pp->flags&PATH_SKIP)
Packit 992a25
				return(ppnext);
Packit 992a25
			if(!last || *pp->name!='/')
Packit 992a25
				break;
Packit 992a25
		}
Packit 992a25
		if(!pp)		/* this should not happen */
Packit 992a25
			pp = last;
Packit 992a25
	}
Packit 992a25
	if(pp && (pp->name[0]!='.' || pp->name[1]))
Packit 992a25
	{
Packit 992a25
		if(*pp->name!='/')
Packit 992a25
		{
Packit 992a25
			stakputs(path_pwd(shp,1));
Packit 992a25
			if(*stakptr(staktell()-1)!='/')
Packit 992a25
				stakputc('/');
Packit 992a25
		}
Packit 992a25
		stakwrite(pp->name,pp->len);
Packit 992a25
		if(pp->name[pp->len-1]!='/')
Packit 992a25
			stakputc('/');
Packit 992a25
	}
Packit 992a25
	stakputs(name);
Packit 992a25
	stakputc(0);
Packit 992a25
	while(pp && pp!=last && (pp=pp->next))
Packit 992a25
	{
Packit 992a25
		if(!(pp->flags&PATH_SKIP))
Packit 992a25
			return(pp);
Packit 992a25
	}
Packit 992a25
	return((Pathcomp_t*)0);
Packit 992a25
}
Packit 992a25
Packit 992a25
static Pathcomp_t* defpath_init(Shell_t *shp)
Packit 992a25
{
Packit 992a25
	Pathcomp_t *pp = (void*)path_addpath(shp,(Pathcomp_t*)0,(std_path),PATH_PATH);
Packit 992a25
	return(pp);
Packit 992a25
}
Packit 992a25
Packit 992a25
static void path_init(Shell_t *shp)
Packit 992a25
{
Packit 992a25
	const char *val;
Packit 992a25
	Pathcomp_t *pp;
Packit 992a25
	if(!std_path && !(std_path=astconf("PATH",NIL(char*),NIL(char*))))
Packit 992a25
		std_path = e_defpath;
Packit 992a25
	if(val=sh_scoped(shp,(PATHNOD))->nvalue.cp)
Packit 992a25
	{
Packit 992a25
		shp->pathlist = pp = (void*)path_addpath(shp,(Pathcomp_t*)shp->pathlist,val,PATH_PATH);
Packit 992a25
	}
Packit 992a25
	else
Packit 992a25
	{
Packit 992a25
		if(!(pp=(Pathcomp_t*)shp->defpathlist))
Packit 992a25
			pp = defpath_init(shp);
Packit 992a25
		shp->pathlist = (void*)path_dup(pp);
Packit 992a25
	}
Packit 992a25
	if(val=sh_scoped(shp,(FPATHNOD))->nvalue.cp)
Packit 992a25
	{
Packit 992a25
		pp = (void*)path_addpath(shp,(Pathcomp_t*)shp->pathlist,val,PATH_FPATH);
Packit 992a25
	}
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * returns that pathlist to search
Packit 992a25
 */
Packit 992a25
Pathcomp_t *path_get(register Shell_t *shp,register const char *name)
Packit 992a25
{
Packit 992a25
	register Pathcomp_t *pp=0;
Packit 992a25
	if(*name && strchr(name,'/'))
Packit 992a25
		return(0);
Packit 992a25
	if(!sh_isstate(SH_DEFPATH))
Packit 992a25
	{
Packit 992a25
		if(!shp->pathlist)
Packit 992a25
			path_init(shp);
Packit 992a25
		pp = (Pathcomp_t*)shp->pathlist;
Packit 992a25
	}
Packit 992a25
	if(!pp && (!(sh_scoped(shp,PATHNOD)->nvalue.cp)) || sh_isstate(SH_DEFPATH))
Packit 992a25
	{
Packit 992a25
		if(!(pp=(Pathcomp_t*)shp->defpathlist))
Packit 992a25
			pp = defpath_init(shp);
Packit 992a25
	}
Packit 992a25
	return(pp);
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * open file corresponding to name using path give by <pp>
Packit 992a25
 */
Packit 992a25
static int	path_opentype(Shell_t *shp,const char *name, register Pathcomp_t *pp, int fun)
Packit 992a25
{
Packit 992a25
	register int fd= -1;
Packit 992a25
	struct stat statb;
Packit 992a25
	Pathcomp_t *oldpp;
Packit 992a25
	if(!pp && !shp->pathlist)
Packit 992a25
		path_init(shp);
Packit 992a25
	if(!fun && strchr(name,'/'))
Packit 992a25
	{
Packit 992a25
		if(sh_isoption(SH_RESTRICTED))
Packit 992a25
			errormsg(SH_DICT,ERROR_exit(1),e_restricted,name);
Packit 992a25
	}
Packit 992a25
	do
Packit 992a25
	{
Packit 992a25
		pp = path_nextcomp(shp,oldpp=pp,name,0);
Packit 992a25
		while(oldpp && (oldpp->flags&PATH_SKIP))
Packit 992a25
			oldpp = oldpp->next;
Packit 992a25
		if(fun && (!oldpp || !(oldpp->flags&PATH_FPATH)))
Packit 992a25
			continue;
Packit 992a25
		if((fd = sh_open(path_relative(shp,stakptr(PATH_OFFSET)),O_RDONLY,0)) >= 0)
Packit 992a25
		{
Packit 992a25
			if(fstat(fd,&statb)<0 || S_ISDIR(statb.st_mode))
Packit 992a25
			{
Packit 992a25
				errno = EISDIR;
Packit 992a25
				sh_close(fd);
Packit 992a25
				fd = -1;
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
	while( fd<0 && pp);
Packit 992a25
	if(fd>=0 && (fd = sh_iomovefd(fd)) > 0)
Packit 992a25
	{
Packit 992a25
		fcntl(fd,F_SETFD,FD_CLOEXEC);
Packit 992a25
		shp->fdstatus[fd] |= IOCLEX;
Packit 992a25
	}
Packit 992a25
	return(fd);
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * open file corresponding to name using path give by <pp>
Packit 992a25
 */
Packit 992a25
int	path_open(Shell_t *shp,const char *name, register Pathcomp_t *pp)
Packit 992a25
{
Packit 992a25
	return(path_opentype(shp,name,pp,0));
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * given a pathname return the base name
Packit 992a25
 */
Packit 992a25
Packit 992a25
char	*path_basename(register const char *name)
Packit 992a25
{
Packit 992a25
	register const char *start = name;
Packit 992a25
	while (*name)
Packit 992a25
		if ((*name++ == '/') && *name)	/* don't trim trailing / */
Packit 992a25
			start = name;
Packit 992a25
	return ((char*)start);
Packit 992a25
}
Packit 992a25
Packit 992a25
char *path_fullname(Shell_t *shp,const char *name)
Packit 992a25
{
Packit 992a25
	int len=strlen(name)+1,dirlen=0;
Packit 992a25
	char *path,*pwd;
Packit 992a25
	if(*name!='/')
Packit 992a25
	{
Packit 992a25
		pwd = path_pwd(shp,1);
Packit 992a25
		dirlen = strlen(pwd)+1;
Packit 992a25
	}
Packit 992a25
	path = (char*)malloc(len+dirlen);
Packit 992a25
	if(dirlen)
Packit 992a25
	{
Packit 992a25
		memcpy((void*)path,(void*)pwd,dirlen);
Packit 992a25
		path[dirlen-1] = '/';
Packit 992a25
	}
Packit 992a25
	memcpy((void*)&path[dirlen],(void*)name,len);
Packit 992a25
	pathcanon(path,0);
Packit 992a25
	return(path);
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * load functions from file <fno>
Packit 992a25
 */
Packit 992a25
static void funload(Shell_t *shp,int fno, const char *name)
Packit 992a25
{
Packit 992a25
	char		*pname,*oldname=shp->st.filename, buff[IOBSIZE+1];
Packit 992a25
	Namval_t	*np;
Packit 992a25
	struct Ufunction *rp,*rpfirst;
Packit 992a25
	int		 savestates = sh_getstate(), oldload=shp->funload;
Packit 992a25
	pname = path_fullname(shp,stakptr(PATH_OFFSET));
Packit 992a25
	if(shp->fpathdict && (rp = dtmatch(shp->fpathdict,(void*)pname)))
Packit 992a25
	{
Packit 992a25
		Dt_t	*funtree = sh_subfuntree(1);
Packit 992a25
		while(1)
Packit 992a25
		{
Packit 992a25
			rpfirst = dtprev(shp->fpathdict,rp);
Packit 992a25
			if(!rpfirst || strcmp(pname,rpfirst->fname))
Packit 992a25
				break;
Packit 992a25
			rp = rpfirst;
Packit 992a25
		}
Packit 992a25
		do
Packit 992a25
		{
Packit 992a25
			if((np = dtsearch(funtree,rp->np)) && is_afunction(np))
Packit 992a25
			{
Packit 992a25
				if(np->nvalue.rp)
Packit 992a25
					np->nvalue.rp->fdict = 0;
Packit 992a25
				nv_delete(np,funtree,NV_NOFREE);
Packit 992a25
			}
Packit 992a25
			dtinsert(funtree,rp->np);
Packit 992a25
			rp->fdict = funtree;
Packit 992a25
		}
Packit 992a25
		while((rp=dtnext(shp->fpathdict,rp)) && strcmp(pname,rp->fname)==0);
Packit 992a25
		sh_close(fno);
Packit 992a25
		free((void*)pname);
Packit 992a25
		return;
Packit 992a25
	}
Packit 992a25
	sh_onstate(SH_NOLOG);
Packit 992a25
	sh_onstate(SH_NOALIAS);
Packit 992a25
	shp->readscript = (char*)name;
Packit 992a25
	shp->st.filename = pname;
Packit 992a25
	shp->funload = 1;
Packit 992a25
	error_info.line = 0;
Packit 992a25
	sh_eval(sfnew(NIL(Sfio_t*),buff,IOBSIZE,fno,SF_READ),SH_FUNEVAL);
Packit 992a25
	sh_close(fno);
Packit 992a25
	shp->readscript = 0;
Packit 992a25
#if SHOPT_NAMESPACE
Packit 992a25
	if(shp->namespace)
Packit 992a25
		np = sh_fsearch(shp,name,0);
Packit 992a25
	else
Packit 992a25
#endif /* SHOPT_NAMESPACE */
Packit 992a25
		np = nv_search(name,shp->fun_tree,0);
Packit 992a25
	if(!np || !np->nvalue.ip)
Packit 992a25
		pname = stakcopy(shp->st.filename);
Packit 992a25
	else
Packit 992a25
		pname = 0;
Packit 992a25
	free((void*)shp->st.filename);
Packit 992a25
	shp->funload = oldload;
Packit 992a25
	shp->st.filename = oldname;
Packit 992a25
	sh_setstate(savestates);
Packit 992a25
	if(pname)
Packit 992a25
		errormsg(SH_DICT,ERROR_exit(ERROR_NOEXEC),e_funload,name,pname);
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * do a path search and track alias if requested
Packit 992a25
 * if flag is 0, or if name not found, then try autoloading function
Packit 992a25
 * if flag==2 or 3, returns 1 if name found on FPATH
Packit 992a25
 * if flag==3 no tracked alias will be set
Packit 992a25
 * returns 1, if function was autoloaded.
Packit 992a25
 * If oldpp is not NULL, it will contain a pointer to the path component
Packit 992a25
 *    where it was found.
Packit 992a25
 */
Packit 992a25
Packit 992a25
int	path_search(Shell_t *shp,register const char *name,Pathcomp_t **oldpp, int flag)
Packit 992a25
{
Packit 992a25
	register Namval_t *np;
Packit 992a25
	register int fno;
Packit 992a25
	Pathcomp_t *pp=0;
Packit 992a25
	if(name && strchr(name,'/'))
Packit 992a25
	{
Packit 992a25
		stakseek(PATH_OFFSET);
Packit 992a25
		stakputs(name);
Packit 992a25
		if(canexecute(shp,stakptr(PATH_OFFSET),0)<0)
Packit 992a25
		{
Packit 992a25
			*stakptr(PATH_OFFSET) = 0;
Packit 992a25
			return(0);
Packit 992a25
		}
Packit 992a25
		if(*name=='/')
Packit 992a25
			return(1);
Packit 992a25
		stakseek(PATH_OFFSET);
Packit 992a25
		stakputs(path_pwd(shp,1));
Packit 992a25
		stakputc('/');
Packit 992a25
		stakputs(name);
Packit 992a25
		stakputc(0);
Packit 992a25
		return(0);
Packit 992a25
	}
Packit 992a25
	if(sh_isstate(SH_DEFPATH))
Packit 992a25
	{
Packit 992a25
		if(!shp->defpathlist)
Packit 992a25
			defpath_init(shp);
Packit 992a25
	}
Packit 992a25
	else if(!shp->pathlist)
Packit 992a25
		path_init(shp);
Packit 992a25
	if(flag)
Packit 992a25
	{
Packit 992a25
		if(!(flag&1) && (np=nv_search(name,shp->track_tree,0)) && !nv_isattr(np,NV_NOALIAS) && (pp=(Pathcomp_t*)np->nvalue.cp))
Packit 992a25
		{
Packit 992a25
			stakseek(PATH_OFFSET);
Packit 992a25
			path_nextcomp(shp,pp,name,pp);
Packit 992a25
			if(oldpp)
Packit 992a25
				*oldpp = pp;
Packit 992a25
			stakputc(0);
Packit 992a25
			return(0);
Packit 992a25
		}
Packit 992a25
		pp = path_absolute(shp,name,oldpp?*oldpp:NIL(Pathcomp_t*));
Packit 992a25
		if(oldpp)
Packit 992a25
			*oldpp = pp;
Packit 992a25
		if(!pp && (np=nv_search(name,shp->fun_tree,0))&&np->nvalue.ip)
Packit 992a25
			return(1);
Packit 992a25
		if(!pp)
Packit 992a25
			*stakptr(PATH_OFFSET) = 0;
Packit 992a25
	}
Packit 992a25
	if(flag==0 || !pp || (pp->flags&PATH_FPATH))
Packit 992a25
	{
Packit 992a25
		if(!pp)
Packit 992a25
			pp=sh_isstate(SH_DEFPATH)?shp->defpathlist:shp->pathlist;
Packit 992a25
		if(pp && strmatch(name,e_alphanum)  && (fno=path_opentype(shp,name,pp,1))>=0)
Packit 992a25
		{
Packit 992a25
			if(flag==2)
Packit 992a25
			{
Packit 992a25
				sh_close(fno);
Packit 992a25
				return(1);
Packit 992a25
			}
Packit 992a25
			funload(shp,fno,name);
Packit 992a25
			return(1);
Packit 992a25
		}
Packit 992a25
		*stakptr(PATH_OFFSET) = 0;
Packit 992a25
		return(0);
Packit 992a25
	}
Packit 992a25
	else if(pp && !sh_isstate(SH_DEFPATH) && *name!='/' && flag<3)
Packit 992a25
	{
Packit 992a25
		if(np=nv_search(name,shp->track_tree,NV_ADD))
Packit 992a25
			path_alias(np,pp);
Packit 992a25
	}
Packit 992a25
	return(0);
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * do a path search and find the full pathname of file name
Packit 992a25
 */
Packit 992a25
Pathcomp_t *path_absolute(Shell_t *shp,register const char *name, Pathcomp_t *pp)
Packit 992a25
{
Packit 992a25
	register int	f,isfun;
Packit 992a25
	int		noexec=0;
Packit 992a25
	Pathcomp_t	*oldpp;
Packit 992a25
	Namval_t	*np;
Packit 992a25
	char		*cp;
Packit 992a25
	char		*bp;
Packit 992a25
	shp->path_err = ENOENT;
Packit 992a25
	if(!pp && !(pp=path_get(shp,"")))
Packit 992a25
		return(0);
Packit 992a25
	shp->path_err = 0;
Packit 992a25
	while(1)
Packit 992a25
	{
Packit 992a25
		sh_sigcheck(shp);
Packit 992a25
		shp->bltin_dir = 0;
Packit 992a25
		while(oldpp=pp)
Packit 992a25
		{
Packit 992a25
			pp = path_nextcomp(shp,pp,name,0);
Packit 992a25
			if(!(oldpp->flags&PATH_SKIP))
Packit 992a25
				break;
Packit 992a25
		}
Packit 992a25
		if(!oldpp)
Packit 992a25
		{
Packit 992a25
			shp->path_err = ENOENT;
Packit 992a25
			return(0);
Packit 992a25
		}
Packit 992a25
		isfun = (oldpp->flags&PATH_FPATH);
Packit 992a25
		if(!isfun && !sh_isoption(SH_RESTRICTED))
Packit 992a25
		{
Packit 992a25
#if SHOPT_DYNAMIC
Packit 992a25
			Shbltin_f addr;
Packit 992a25
			int n;
Packit 992a25
#endif
Packit 992a25
			if(*stakptr(PATH_OFFSET)=='/' && nv_search(stakptr(PATH_OFFSET),shp->bltin_tree,0))
Packit 992a25
				return(oldpp);
Packit 992a25
#if SHOPT_DYNAMIC
Packit 992a25
			n = staktell();
Packit 992a25
			stakputs("b_");
Packit 992a25
			stakputs(name);
Packit 992a25
			stakputc(0);
Packit 992a25
			if((addr = sh_getlib(shp, stakptr(n), oldpp)) &&
Packit 992a25
			   (np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL)) &&
Packit 992a25
			   nv_isattr(np,NV_BLTINOPT))
Packit 992a25
			{
Packit 992a25
				shp->bltin_dir = 0;
Packit 992a25
				return(oldpp);
Packit 992a25
			}
Packit 992a25
			stakseek(n);
Packit 992a25
			while(bp = oldpp->blib)
Packit 992a25
			{
Packit 992a25
				char *fp;
Packit 992a25
				void *dll;
Packit 992a25
				int m;
Packit 992a25
				if(fp = strchr(bp, ':'))
Packit 992a25
				{
Packit 992a25
					*fp++ = 0;
Packit 992a25
					oldpp->blib = fp;
Packit 992a25
					fp = 0;
Packit 992a25
				}
Packit 992a25
				else
Packit 992a25
				{
Packit 992a25
					fp = oldpp->bbuf;
Packit 992a25
					oldpp->blib = oldpp->bbuf = 0;
Packit 992a25
				}
Packit 992a25
				n = staktell();
Packit 992a25
				stakputs("b_");
Packit 992a25
				stakputs(name);
Packit 992a25
				stakputc(0);
Packit 992a25
				m = staktell();
Packit 992a25
				shp->bltin_dir = oldpp->name;
Packit 992a25
				if(*bp!='/')
Packit 992a25
				{
Packit 992a25
					stakputs(oldpp->name);
Packit 992a25
					stakputc('/');
Packit 992a25
				}
Packit 992a25
				stakputs(bp);
Packit 992a25
				stakputc(0);
Packit 992a25
				if(cp = strrchr(stakptr(m),'/'))
Packit 992a25
					cp++;
Packit 992a25
				else
Packit 992a25
					cp = stakptr(m);
Packit 992a25
				if(!strcmp(cp,LIBCMD) &&
Packit 992a25
				   (addr=(Shbltin_f)dlllook((void*)0,stakptr(n))) &&
Packit 992a25
				   (np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL)) &&
Packit 992a25
				   nv_isattr(np,NV_BLTINOPT))
Packit 992a25
				{
Packit 992a25
				found:
Packit 992a25
					if(fp)
Packit 992a25
						free(fp);
Packit 992a25
					shp->bltin_dir = 0;
Packit 992a25
					return(oldpp);
Packit 992a25
				}
Packit 992a25
#ifdef SH_PLUGIN_VERSION
Packit 992a25
				if (dll = dllplugin(SH_ID, stakptr(m), NiL, SH_PLUGIN_VERSION, NiL, RTLD_LAZY, NiL, 0))
Packit 992a25
					sh_addlib(shp,dll,stakptr(m),oldpp);
Packit 992a25
#else
Packit 992a25
#if (_AST_VERSION>=20040404)
Packit 992a25
				if (dll = dllplug(SH_ID, stakptr(m), NiL, RTLD_LAZY, NiL, 0))
Packit 992a25
#else
Packit 992a25
				if (dll = dllfind(stakptr(m), NiL, RTLD_LAZY, NiL, 0))
Packit 992a25
#endif
Packit 992a25
				{
Packit 992a25
					/*
Packit 992a25
					 * this detects the 2007-05-11 builtin context change and also
Packit 992a25
					 * the 2008-03-30 opt_info.num change that hit libcmd::b_head
Packit 992a25
					 */
Packit 992a25
Packit 992a25
					if (libcmd && !dlllook(dll, "b_pids"))
Packit 992a25
					{
Packit 992a25
						dlclose(dll);
Packit 992a25
						dll = 0;
Packit 992a25
					}
Packit 992a25
					else
Packit 992a25
						sh_addlib(shp,dll,stakptr(m),oldpp);
Packit 992a25
				}
Packit 992a25
#endif
Packit 992a25
				if(dll &&
Packit 992a25
				   (addr=(Shbltin_f)dlllook(dll,stakptr(n))) &&
Packit 992a25
				   (!(np = sh_addbuiltin(stakptr(PATH_OFFSET),NiL,NiL)) || np->nvalue.bfp!=(Nambfp_f)addr) &&
Packit 992a25
				   (np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL)))
Packit 992a25
				{
Packit 992a25
					np->nvenv = dll;
Packit 992a25
					goto found;
Packit 992a25
				}
Packit 992a25
				if(*stakptr(PATH_OFFSET)=='/' && nv_search(stakptr(PATH_OFFSET),shp->bltin_tree,0))
Packit 992a25
					goto found;
Packit 992a25
				if(fp)
Packit 992a25
					free(fp);
Packit 992a25
				stakseek(n);
Packit 992a25
			}
Packit 992a25
#endif /* SHOPT_DYNAMIC */
Packit 992a25
		}
Packit 992a25
		shp->bltin_dir = 0;
Packit 992a25
		sh_stats(STAT_PATHS);
Packit 992a25
		f = canexecute(shp,stakptr(PATH_OFFSET),isfun);
Packit 992a25
		if(isfun && f>=0 && (cp = strrchr(name,'.')))
Packit 992a25
		{
Packit 992a25
			*cp = 0;
Packit 992a25
			if(nv_open(name,sh_subfuntree(1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE))
Packit 992a25
				f = -1;
Packit 992a25
			*cp = '.';
Packit 992a25
		}
Packit 992a25
		if(isfun && f>=0)
Packit 992a25
		{
Packit 992a25
			nv_onattr(nv_open(name,sh_subfuntree(1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE),NV_LTOU|NV_FUNCTION);
Packit 992a25
			funload(shp,f,name);
Packit 992a25
			close(f);
Packit 992a25
			f = -1;
Packit 992a25
			return(0);
Packit 992a25
		}
Packit 992a25
		else if(f>=0 && (oldpp->flags & PATH_STD_DIR))
Packit 992a25
		{
Packit 992a25
			int n = staktell();
Packit 992a25
			stakputs("/bin/");
Packit 992a25
			stakputs(name);
Packit 992a25
			stakputc(0);
Packit 992a25
			np = nv_search(stakptr(n),shp->bltin_tree,0);
Packit 992a25
			stakseek(n);
Packit 992a25
			if(np)
Packit 992a25
			{
Packit 992a25
				n = np->nvflag;
Packit 992a25
				np = sh_addbuiltin(stakptr(PATH_OFFSET),(Shbltin_f)np->nvalue.bfp,nv_context(np));
Packit 992a25
				np->nvflag = n;
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
		if(!pp || f>=0)
Packit 992a25
			break;
Packit 992a25
		if(errno!=ENOENT)
Packit 992a25
			noexec = errno;
Packit 992a25
	}
Packit 992a25
	if(f<0)
Packit 992a25
	{
Packit 992a25
		shp->path_err = (noexec?noexec:ENOENT);
Packit 992a25
		return(0);
Packit 992a25
	}
Packit 992a25
	stakputc(0);
Packit 992a25
	return(oldpp);
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * returns 0 if path can execute
Packit 992a25
 * sets exec_err if file is found but can't be executable
Packit 992a25
 */
Packit 992a25
#undef S_IXALL
Packit 992a25
#ifdef S_IXUSR
Packit 992a25
#   define S_IXALL	(S_IXUSR|S_IXGRP|S_IXOTH)
Packit 992a25
#else
Packit 992a25
#   ifdef S_IEXEC
Packit 992a25
#	define S_IXALL	(S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6))
Packit 992a25
#   else
Packit 992a25
#	define S_IXALL	0111
Packit 992a25
#   endif /*S_EXEC */
Packit 992a25
#endif /* S_IXUSR */
Packit 992a25
Packit 992a25
static int canexecute(Shell_t *shp,register char *path, int isfun)
Packit 992a25
{
Packit 992a25
	struct stat statb;
Packit 992a25
	register int fd=0;
Packit 992a25
	path = path_relative(shp,path);
Packit 992a25
	if(isfun)
Packit 992a25
	{
Packit 992a25
		if((fd=open(path,O_RDONLY,0))<0 || fstat(fd,&statb)<0)
Packit 992a25
			goto err;
Packit 992a25
	}
Packit 992a25
	else if(stat(path,&statb) < 0)
Packit 992a25
	{
Packit 992a25
#if _WINIX
Packit 992a25
		/* check for .exe or .bat suffix */
Packit 992a25
		char *cp;
Packit 992a25
		if(errno==ENOENT && (!(cp=strrchr(path,'.')) || strlen(cp)>4 || strchr(cp,'/')))
Packit 992a25
		{
Packit 992a25
			int offset = staktell()-1;
Packit 992a25
			stakseek(offset);
Packit 992a25
			stakputs(".bat");
Packit 992a25
			path = stakptr(PATH_OFFSET);
Packit 992a25
			if(stat(path,&statb) < 0)
Packit 992a25
			{
Packit 992a25
				if(errno!=ENOENT)
Packit 992a25
					goto err;
Packit 992a25
				memcpy(stakptr(offset),".sh",4);
Packit 992a25
				if(stat(path,&statb) < 0)
Packit 992a25
					goto err;
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
		else
Packit 992a25
#endif /* _WINIX */
Packit 992a25
		goto err;
Packit 992a25
	}
Packit 992a25
	errno = EPERM;
Packit 992a25
	if(S_ISDIR(statb.st_mode))
Packit 992a25
		errno = EISDIR;
Packit 992a25
	else if((statb.st_mode&S_IXALL)==S_IXALL || sh_access(path,X_OK)>=0)
Packit 992a25
		return(fd);
Packit 992a25
	if(isfun && fd>=0)
Packit 992a25
		sh_close(fd);
Packit 992a25
err:
Packit 992a25
	return(-1);
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * Return path relative to present working directory
Packit 992a25
 */
Packit 992a25
Packit 992a25
char *path_relative(Shell_t *shp,register const char* file)
Packit 992a25
{
Packit 992a25
	register const char *pwd;
Packit 992a25
	register const char *fp = file;
Packit 992a25
	/* can't relpath when shp->pwd not set */
Packit 992a25
	if(!(pwd=shp->pwd))
Packit 992a25
		return((char*)fp);
Packit 992a25
	while(*pwd==*fp)
Packit 992a25
	{
Packit 992a25
		if(*pwd++==0)
Packit 992a25
			return((char*)e_dot);
Packit 992a25
		fp++;
Packit 992a25
	}
Packit 992a25
	if(*pwd==0 && *fp == '/')
Packit 992a25
	{
Packit 992a25
		while(*++fp=='/');
Packit 992a25
		if(*fp)
Packit 992a25
			return((char*)fp);
Packit 992a25
		return((char*)e_dot);
Packit 992a25
	}
Packit 992a25
	return((char*)file);
Packit 992a25
}
Packit 992a25
Packit 992a25
void	path_exec(Shell_t *shp,register const char *arg0,register char *argv[],struct argnod *local)
Packit 992a25
{
Packit 992a25
	char **envp;
Packit 992a25
	const char *opath;
Packit 992a25
	Pathcomp_t *libpath, *pp=0;
Packit 992a25
	int slash=0;
Packit 992a25
	nv_setlist(local,NV_EXPORT|NV_IDENT|NV_ASSIGN,0);
Packit 992a25
	envp = sh_envgen();
Packit 992a25
	if(strchr(arg0,'/'))
Packit 992a25
	{
Packit 992a25
		slash=1;
Packit 992a25
		/* name containing / not allowed for restricted shell */
Packit 992a25
		if(sh_isoption(SH_RESTRICTED))
Packit 992a25
			errormsg(SH_DICT,ERROR_exit(1),e_restricted,arg0);
Packit 992a25
	}
Packit 992a25
	else
Packit 992a25
		pp=path_get(shp,arg0);
Packit 992a25
	shp->path_err= ENOENT;
Packit 992a25
	sfsync(NIL(Sfio_t*));
Packit 992a25
	timerdel(NIL(void*));
Packit 992a25
	/* find first path that has a library component */
Packit 992a25
	while(pp && (pp->flags&PATH_SKIP))
Packit 992a25
		pp = pp->next;
Packit 992a25
	if(pp || slash) do
Packit 992a25
	{
Packit 992a25
		sh_sigcheck(shp);
Packit 992a25
		if(libpath=pp)
Packit 992a25
		{
Packit 992a25
			pp = path_nextcomp(shp,pp,arg0,0);
Packit 992a25
			opath = stakfreeze(1)+PATH_OFFSET;
Packit 992a25
		}
Packit 992a25
		else
Packit 992a25
			opath = arg0;
Packit 992a25
		path_spawn(shp,opath,argv,envp,libpath,0);
Packit 992a25
		while(pp && (pp->flags&PATH_FPATH))
Packit 992a25
			pp = path_nextcomp(shp,pp,arg0,0);
Packit 992a25
	}
Packit 992a25
	while(pp);
Packit 992a25
	/* force an exit */
Packit 992a25
	((struct checkpt*)shp->jmplist)->mode = SH_JMPEXIT;
Packit 992a25
	if((errno=shp->path_err)==ENOENT)
Packit 992a25
		errormsg(SH_DICT,ERROR_exit(ERROR_NOENT),e_found,arg0);
Packit 992a25
	else
Packit 992a25
		errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,arg0);
Packit 992a25
}
Packit 992a25
Packit 992a25
pid_t path_spawn(Shell_t *shp,const char *opath,register char **argv, char **envp, Pathcomp_t *libpath, int spawn)
Packit 992a25
{
Packit 992a25
	register char *path;
Packit 992a25
	char **xp=0, *xval, *libenv = (libpath?libpath->lib:0); 
Packit 992a25
	Namval_t*	np;
Packit 992a25
	char		*s, *v;
Packit 992a25
	int		r, n, pidsize;
Packit 992a25
	pid_t		pid= -1;
Packit 992a25
	/* leave room for inserting _= pathname in environment */
Packit 992a25
	envp--;
Packit 992a25
#if _lib_readlink
Packit 992a25
	/* save original pathname */
Packit 992a25
	stakseek(PATH_OFFSET);
Packit 992a25
	pidsize = sfprintf(stkstd,"*%d*",spawn?getpid():getppid());
Packit 992a25
	stakputs(opath);
Packit 992a25
	opath = stakfreeze(1)+PATH_OFFSET+pidsize;
Packit 992a25
	np=nv_search(argv[0],shp->track_tree,0);
Packit 992a25
	while(libpath && !libpath->lib)
Packit 992a25
		libpath=libpath->next;
Packit 992a25
	if(libpath && (!np || nv_size(np)>0))
Packit 992a25
	{
Packit 992a25
		/* check for symlink and use symlink name */
Packit 992a25
		char buff[PATH_MAX+1];
Packit 992a25
		char save[PATH_MAX+1];
Packit 992a25
		stakseek(PATH_OFFSET);
Packit 992a25
		stakputs(opath);
Packit 992a25
		path = stakptr(PATH_OFFSET);
Packit 992a25
		while((n=readlink(path,buff,PATH_MAX))>0)
Packit 992a25
		{
Packit 992a25
			buff[n] = 0;
Packit 992a25
			n = PATH_OFFSET;
Packit 992a25
			r = 0;
Packit 992a25
			if((v=strrchr(path,'/')) && *buff!='/')
Packit 992a25
			{
Packit 992a25
				if(buff[0]=='.' && buff[1]=='.' && (r = strlen(path) + 1) <= PATH_MAX)
Packit 992a25
					memcpy(save, path, r);
Packit 992a25
				else
Packit 992a25
					r = 0;
Packit 992a25
				n += (v+1-path);
Packit 992a25
			}
Packit 992a25
			stakseek(n);
Packit 992a25
			stakputs(buff);
Packit 992a25
			stakputc(0);
Packit 992a25
			path = stakptr(PATH_OFFSET);
Packit 992a25
			if(v && buff[0]=='.' && buff[1]=='.')
Packit 992a25
			{
Packit 992a25
				pathcanon(path, 0);
Packit 992a25
				if(r && access(path,X_OK))
Packit 992a25
				{
Packit 992a25
					memcpy(path, save, r);
Packit 992a25
					break;
Packit 992a25
				}
Packit 992a25
			}
Packit 992a25
			if(libenv = path_lib(shp,libpath,path))
Packit 992a25
				break;
Packit 992a25
		}
Packit 992a25
		stakseek(0);
Packit 992a25
	}
Packit 992a25
#endif
Packit 992a25
	if(libenv && (v = strchr(libenv,'=')))
Packit 992a25
	{
Packit 992a25
		n = v - libenv;
Packit 992a25
		*v = 0;
Packit 992a25
		np = nv_open(libenv,shp->var_tree,0);
Packit 992a25
		*v = '=';
Packit 992a25
		s = nv_getval(np);
Packit 992a25
		stakputs(libenv);
Packit 992a25
		if(s)
Packit 992a25
		{
Packit 992a25
			stakputc(':');
Packit 992a25
			stakputs(s);
Packit 992a25
		}
Packit 992a25
		v = stakfreeze(1);
Packit 992a25
		r = 1;
Packit 992a25
		xp = envp + 1;
Packit 992a25
		while (s = *xp++)
Packit 992a25
		{
Packit 992a25
			if (strneq(s, v, n) && s[n] == '=')
Packit 992a25
			{
Packit 992a25
				xval = *--xp;
Packit 992a25
				*xp = v;
Packit 992a25
				r = 0;
Packit 992a25
				break;
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
		if (r)
Packit 992a25
		{
Packit 992a25
			*envp-- = v;
Packit 992a25
			xp = 0;
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
	if(!opath)
Packit 992a25
		opath = stakptr(PATH_OFFSET);
Packit 992a25
	envp[0] =  (char*)opath-(PATH_OFFSET+pidsize);
Packit 992a25
	envp[0][0] =  '_';
Packit 992a25
	envp[0][1] =  '=';
Packit 992a25
	sfsync(sfstderr);
Packit 992a25
	sh_sigcheck(shp);
Packit 992a25
	path = path_relative(shp,opath);
Packit 992a25
#ifdef SHELLMAGIC
Packit 992a25
	if(*path!='/' && path!=opath)
Packit 992a25
	{
Packit 992a25
		/*
Packit 992a25
		 * The following code because execv(foo,) and execv(./foo,)
Packit 992a25
		 * may not yield the same results
Packit 992a25
		 */
Packit 992a25
		char *sp = (char*)malloc(strlen(path)+3);
Packit 992a25
		sp[0] = '.';
Packit 992a25
		sp[1] = '/';
Packit 992a25
		strcpy(sp+2,path);
Packit 992a25
		path = sp;
Packit 992a25
	}
Packit 992a25
#endif /* SHELLMAGIC */
Packit 992a25
	if(spawn && !sh_isoption(SH_PFSH))
Packit 992a25
		pid = _spawnveg(shp,opath, &argv[0],envp, spawn>>1);
Packit 992a25
	else
Packit 992a25
		pid = path_pfexecve(shp,opath, &argv[0] ,envp,spawn);
Packit 992a25
	if(xp)
Packit 992a25
		*xp = xval;
Packit 992a25
#ifdef SHELLMAGIC
Packit 992a25
	if(*path=='.' && path!=opath)
Packit 992a25
	{
Packit 992a25
		free(path);
Packit 992a25
		path = path_relative(shp,opath);
Packit 992a25
	}
Packit 992a25
#endif /* SHELLMAGIC */
Packit 992a25
	if(pid>0)
Packit 992a25
		return(pid);
Packit 992a25
retry:
Packit 992a25
	switch(shp->path_err = errno)
Packit 992a25
	{
Packit 992a25
#ifdef apollo
Packit 992a25
	    /* 
Packit 992a25
  	     * On apollo's execve will fail with eacces when
Packit 992a25
	     * file has execute but not read permissions. So,
Packit 992a25
	     * for now we will pretend that EACCES and ENOEXEC
Packit 992a25
 	     * mean the same thing.
Packit 992a25
 	     */
Packit 992a25
	    case EACCES:
Packit 992a25
#endif /* apollo */
Packit 992a25
	    case ENOEXEC:
Packit 992a25
#if SHOPT_SUID_EXEC
Packit 992a25
	    case EPERM:
Packit 992a25
		/* some systems return EPERM if setuid bit is on */
Packit 992a25
#endif
Packit 992a25
		errno = ENOEXEC;
Packit 992a25
		if(spawn)
Packit 992a25
		{
Packit 992a25
#ifdef _lib_fork
Packit 992a25
			if(shp->subshell)
Packit 992a25
				return(-1);
Packit 992a25
			do
Packit 992a25
			{
Packit 992a25
				if((pid=fork())>0)
Packit 992a25
					return(pid);
Packit 992a25
			}
Packit 992a25
			while(_sh_fork(shp,pid,0,(int*)0) < 0);
Packit 992a25
			((struct checkpt*)shp->jmplist)->mode = SH_JMPEXIT;
Packit 992a25
#else
Packit 992a25
			return(-1);
Packit 992a25
#endif
Packit 992a25
		}
Packit 992a25
		exscript(shp,path,argv,envp);
Packit 992a25
#ifndef apollo
Packit 992a25
	    case EACCES:
Packit 992a25
	    {
Packit 992a25
		struct stat statb;
Packit 992a25
		if(stat(path,&statb)>=0)
Packit 992a25
		{
Packit 992a25
			if(S_ISDIR(statb.st_mode))
Packit 992a25
				errno = EISDIR;
Packit 992a25
#ifdef S_ISSOCK
Packit 992a25
			if(S_ISSOCK(statb.st_mode))
Packit 992a25
				exscript(shp,path,argv,envp);
Packit 992a25
#endif
Packit 992a25
		}
Packit 992a25
	    }
Packit 992a25
		/* FALL THROUGH */
Packit 992a25
#endif /* !apollo */
Packit 992a25
#ifdef ENAMETOOLONG
Packit 992a25
	    case ENAMETOOLONG:
Packit 992a25
#endif /* ENAMETOOLONG */
Packit 992a25
#if !SHOPT_SUID_EXEC
Packit 992a25
	    case EPERM:
Packit 992a25
#endif
Packit 992a25
		shp->path_err = errno;
Packit 992a25
		return(-1);
Packit 992a25
	    case ENOTDIR:
Packit 992a25
	    case ENOENT:
Packit 992a25
	    case EINTR:
Packit 992a25
#ifdef EMLINK
Packit 992a25
	    case EMLINK:
Packit 992a25
#endif /* EMLINK */
Packit 992a25
		return(-1);
Packit 992a25
	    case E2BIG:
Packit 992a25
		if(shp->xargmin)
Packit 992a25
		{
Packit 992a25
			pid = path_xargs(shp,opath, &argv[0] ,envp,spawn);
Packit 992a25
			if(pid<0)
Packit 992a25
				goto retry;
Packit 992a25
			return(pid);
Packit 992a25
		}
Packit 992a25
	    default:
Packit 992a25
		errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path);
Packit 992a25
	}
Packit 992a25
	return 0;
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * File is executable but not machine code.
Packit 992a25
 * Assume file is a Shell script and execute it.
Packit 992a25
 */
Packit 992a25
Packit 992a25
static void exscript(Shell_t *shp,register char *path,register char *argv[],char **envp)
Packit 992a25
{
Packit 992a25
	register Sfio_t *sp;
Packit 992a25
	path = path_relative(shp,path);
Packit 992a25
	shp->comdiv=0;
Packit 992a25
	shp->bckpid = 0;
Packit 992a25
	shp->coshell = 0;
Packit 992a25
	shp->st.ioset=0;
Packit 992a25
	/* clean up any cooperating processes */
Packit 992a25
	if(shp->cpipe[0]>0)
Packit 992a25
		sh_pclose(shp->cpipe);
Packit 992a25
	if(shp->cpid && shp->outpipe)
Packit 992a25
		sh_close(*shp->outpipe);
Packit 992a25
	shp->cpid = 0;
Packit 992a25
	if(sp=fcfile())
Packit 992a25
		while(sfstack(sp,SF_POPSTACK));
Packit 992a25
	job_clear();
Packit 992a25
	if(shp->infd>0 && (shp->fdstatus[shp->infd]&IOCLEX))
Packit 992a25
		sh_close(shp->infd);
Packit 992a25
	sh_setstate(sh_state(SH_FORKED));
Packit 992a25
	sfsync(sfstderr);
Packit 992a25
#if SHOPT_SUID_EXEC && !SHOPT_PFSH
Packit 992a25
	/* check if file cannot open for read or script is setuid/setgid  */
Packit 992a25
	{
Packit 992a25
		static char name[] = "/tmp/euidXXXXXXXXXX";
Packit 992a25
		register int n;
Packit 992a25
		register uid_t euserid;
Packit 992a25
		char *savet=0;
Packit 992a25
		struct stat statb;
Packit 992a25
		if((n=sh_open(path,O_RDONLY,0)) >= 0)
Packit 992a25
		{
Packit 992a25
			/* move <n> if n=0,1,2 */
Packit 992a25
			n = sh_iomovefd(n);
Packit 992a25
			if(fstat(n,&statb)>=0 && !(statb.st_mode&(S_ISUID|S_ISGID)))
Packit 992a25
				goto openok;
Packit 992a25
			sh_close(n);
Packit 992a25
		}
Packit 992a25
		if((euserid=geteuid()) != shp->gd->userid)
Packit 992a25
		{
Packit 992a25
			strncpy(name+9,fmtbase((long)getpid(),10,0),sizeof(name)-10);
Packit 992a25
			/* create a suid open file with owner equal effective uid */
Packit 992a25
			if((n=open(name,O_CREAT|O_TRUNC|O_WRONLY,S_ISUID|S_IXUSR)) < 0)
Packit 992a25
				goto fail;
Packit 992a25
			unlink(name);
Packit 992a25
			/* make sure that file has right owner */
Packit 992a25
			if(fstat(n,&statb)<0 || statb.st_uid != euserid)
Packit 992a25
				goto fail;
Packit 992a25
			if(n!=10)
Packit 992a25
			{
Packit 992a25
				sh_close(10);
Packit 992a25
				fcntl(n, F_DUPFD, 10);
Packit 992a25
				sh_close(n);
Packit 992a25
				n=10;
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
		savet = *--argv;
Packit 992a25
		*argv = path;
Packit 992a25
		path_pfexecve(shp,e_suidexec,argv,envp,0);
Packit 992a25
	fail:
Packit 992a25
		/*
Packit 992a25
		 *  The following code is just for compatibility
Packit 992a25
		 */
Packit 992a25
		if((n=open(path,O_RDONLY,0)) < 0)
Packit 992a25
			errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path);
Packit 992a25
		if(savet)
Packit 992a25
			*argv++ = savet;
Packit 992a25
	openok:
Packit 992a25
		shp->infd = n;
Packit 992a25
	}
Packit 992a25
#else
Packit 992a25
	if((shp->infd = sh_open(path,O_RDONLY,0)) < 0)
Packit 992a25
		errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path);
Packit 992a25
#endif
Packit 992a25
	shp->infd = sh_iomovefd(shp->infd);
Packit 992a25
#if SHOPT_ACCT
Packit 992a25
	sh_accbegin(path) ;  /* reset accounting */
Packit 992a25
#endif	/* SHOPT_ACCT */
Packit 992a25
	shp->arglist = sh_argcreate(argv);
Packit 992a25
	shp->lastarg = strdup(path);
Packit 992a25
	/* save name of calling command */
Packit 992a25
	shp->readscript = error_info.id;
Packit 992a25
	/* close history file if name has changed */
Packit 992a25
	if(shp->gd->hist_ptr && (path=nv_getval(HISTFILE)) && strcmp(path,shp->gd->hist_ptr->histname))
Packit 992a25
	{
Packit 992a25
		hist_close(shp->gd->hist_ptr);
Packit 992a25
		(HISTCUR)->nvalue.lp = 0;
Packit 992a25
	}
Packit 992a25
	sh_offstate(SH_FORKED);
Packit 992a25
	if(shp->sigflag[SIGCHLD]==SH_SIGOFF)
Packit 992a25
		shp->sigflag[SIGCHLD] = SH_SIGFAULT;
Packit 992a25
	siglongjmp(*shp->jmplist,SH_JMPSCRIPT);
Packit 992a25
}
Packit 992a25
Packit 992a25
#if SHOPT_ACCT
Packit 992a25
#   include <sys/acct.h>
Packit 992a25
#   include "FEATURE/time"
Packit 992a25
Packit 992a25
    static struct acct sabuf;
Packit 992a25
    static struct tms buffer;
Packit 992a25
    static clock_t	before;
Packit 992a25
    static char *SHACCT; /* set to value of SHACCT environment variable */
Packit 992a25
    static shaccton;	/* non-zero causes accounting record to be written */
Packit 992a25
    static int compress(time_t);
Packit 992a25
    /*
Packit 992a25
     *	initialize accounting, i.e., see if SHACCT variable set
Packit 992a25
     */
Packit 992a25
    void sh_accinit(void)
Packit 992a25
    {
Packit 992a25
	SHACCT = getenv("SHACCT");
Packit 992a25
    }
Packit 992a25
    /*
Packit 992a25
    * suspend accounting until turned on by sh_accbegin()
Packit 992a25
    */
Packit 992a25
    void sh_accsusp(void)
Packit 992a25
    {
Packit 992a25
	shaccton=0;
Packit 992a25
#ifdef AEXPAND
Packit 992a25
	sabuf.ac_flag |= AEXPND;
Packit 992a25
#endif /* AEXPAND */
Packit 992a25
    }
Packit 992a25
Packit 992a25
    /*
Packit 992a25
     * begin an accounting record by recording start time
Packit 992a25
     */
Packit 992a25
    void sh_accbegin(const char *cmdname)
Packit 992a25
    {
Packit 992a25
	if(SHACCT)
Packit 992a25
	{
Packit 992a25
		sabuf.ac_btime = time(NIL(time_t *));
Packit 992a25
		before = times(&buffer);
Packit 992a25
		sabuf.ac_uid = getuid();
Packit 992a25
		sabuf.ac_gid = getgid();
Packit 992a25
		strncpy(sabuf.ac_comm, (char*)path_basename(cmdname),
Packit 992a25
			sizeof(sabuf.ac_comm));
Packit 992a25
		shaccton = 1;
Packit 992a25
	}
Packit 992a25
    }
Packit 992a25
    /*
Packit 992a25
     * terminate an accounting record and append to accounting file
Packit 992a25
     */
Packit 992a25
    void	sh_accend(void)
Packit 992a25
    {
Packit 992a25
	int	fd;
Packit 992a25
	clock_t	after;
Packit 992a25
Packit 992a25
	if(shaccton)
Packit 992a25
	{
Packit 992a25
		after = times(&buffer);
Packit 992a25
		sabuf.ac_utime = compress(buffer.tms_utime + buffer.tms_cutime);
Packit 992a25
		sabuf.ac_stime = compress(buffer.tms_stime + buffer.tms_cstime);
Packit 992a25
		sabuf.ac_etime = compress( (time_t)(after-before));
Packit 992a25
		fd = open( SHACCT , O_WRONLY | O_APPEND | O_CREAT,RW_ALL);
Packit 992a25
		write(fd, (const char*)&sabuf, sizeof( sabuf ));
Packit 992a25
		close( fd);
Packit 992a25
	}
Packit 992a25
    }
Packit 992a25
 
Packit 992a25
    /*
Packit 992a25
     * Produce a pseudo-floating point representation
Packit 992a25
     * with 3 bits base-8 exponent, 13 bits fraction.
Packit 992a25
     */
Packit 992a25
    static int compress(register time_t t)
Packit 992a25
    {
Packit 992a25
	register int exp = 0, rund = 0;
Packit 992a25
Packit 992a25
	while (t >= 8192)
Packit 992a25
	{
Packit 992a25
		exp++;
Packit 992a25
		rund = t&0;;
Packit 992a25
		t >>= 3;
Packit 992a25
	}
Packit 992a25
	if (rund)
Packit 992a25
	{
Packit 992a25
		t++;
Packit 992a25
		if (t >= 8192)
Packit 992a25
		{
Packit 992a25
			t >>= 3;
Packit 992a25
			exp++;
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
	return((exp<<13) + t);
Packit 992a25
    }
Packit 992a25
#endif	/* SHOPT_ACCT */
Packit 992a25
Packit 992a25
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * add a pathcomponent to the path search list and eliminate duplicates
Packit 992a25
 * and non-existing absolute paths.
Packit 992a25
 */
Packit 992a25
static Pathcomp_t *path_addcomp(Shell_t *shp,Pathcomp_t *first, Pathcomp_t *old,const char *name, int flag)
Packit 992a25
{
Packit 992a25
	register Pathcomp_t *pp, *oldpp;
Packit 992a25
	int len, offset=staktell();
Packit 992a25
	if(!(flag&PATH_BFPATH))
Packit 992a25
	{
Packit 992a25
		register const char *cp = name;
Packit 992a25
		while(*cp && *cp!=':')
Packit 992a25
			stakputc(*cp++);
Packit 992a25
		len = staktell()-offset;
Packit 992a25
		stakputc(0);
Packit 992a25
		stakseek(offset);
Packit 992a25
		name = (const char*)stakptr(offset);
Packit 992a25
	}
Packit 992a25
	else
Packit 992a25
		len = strlen(name);
Packit 992a25
	for(pp=first; pp; pp=pp->next)
Packit 992a25
	{
Packit 992a25
		if(len == pp->len && memcmp(name,pp->name,len)==0)
Packit 992a25
		{
Packit 992a25
			pp->flags |= flag;
Packit 992a25
			return(first);
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
	for(pp=first, oldpp=0; pp; oldpp=pp, pp=pp->next);
Packit 992a25
	pp = newof((Pathcomp_t*)0,Pathcomp_t,1,len+1);
Packit 992a25
	pp->shp = shp;
Packit 992a25
	pp->refcount = 1;
Packit 992a25
	memcpy((char*)(pp+1),name,len+1);
Packit 992a25
	pp->name = (char*)(pp+1);
Packit 992a25
	pp->len = len;
Packit 992a25
	if(oldpp)
Packit 992a25
		oldpp->next = pp;
Packit 992a25
	else
Packit 992a25
		first = pp;
Packit 992a25
	pp->flags = flag;
Packit 992a25
	if(strcmp(name,SH_CMDLIB_DIR)==0)
Packit 992a25
	{
Packit 992a25
		pp->dev = 1;
Packit 992a25
		pp->flags |= PATH_BUILTIN_LIB;
Packit 992a25
		pp->blib = pp->bbuf = malloc(sizeof(LIBCMD));
Packit 992a25
		strcpy(pp->blib,LIBCMD);
Packit 992a25
		return(first);
Packit 992a25
	}
Packit 992a25
	if((old||shp->pathinit) &&  ((flag&(PATH_PATH|PATH_SKIP))==PATH_PATH))
Packit 992a25
		path_chkpaths(shp,first,old,pp,offset);
Packit 992a25
	return(first);
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * This function checks for the .paths file in directory in <pp>
Packit 992a25
 * it assumes that the directory is on the stack at <offset> 
Packit 992a25
 */
Packit 992a25
static int path_chkpaths(Shell_t *shp,Pathcomp_t *first, Pathcomp_t* old,Pathcomp_t *pp, int offset)
Packit 992a25
{
Packit 992a25
	struct stat statb;
Packit 992a25
	int k,m,n,fd;
Packit 992a25
	char *sp,*cp,*ep;
Packit 992a25
	stakseek(offset+pp->len);
Packit 992a25
	if(pp->len==1 && *stakptr(offset)=='/')
Packit 992a25
		stakseek(offset);
Packit 992a25
	stakputs("/.paths");
Packit 992a25
	if((fd=open(stakptr(offset),O_RDONLY))>=0)
Packit 992a25
	{
Packit 992a25
		fstat(fd,&statb);
Packit 992a25
		n = statb.st_size;
Packit 992a25
		stakseek(offset+pp->len+n+2);
Packit 992a25
		sp = stakptr(offset+pp->len);
Packit 992a25
		*sp++ = '/';
Packit 992a25
		n=read(fd,cp=sp,n);
Packit 992a25
		sp[n] = 0;
Packit 992a25
		close(fd);
Packit 992a25
		for(ep=0; n--; cp++)
Packit 992a25
		{
Packit 992a25
			if(*cp=='=')
Packit 992a25
			{
Packit 992a25
				ep = cp+1;
Packit 992a25
				continue;
Packit 992a25
			}
Packit 992a25
			else if(*cp!='\r' &&  *cp!='\n')
Packit 992a25
				continue;
Packit 992a25
			if(*sp=='#' || sp==cp)
Packit 992a25
			{
Packit 992a25
				sp = cp+1;
Packit 992a25
				continue;
Packit 992a25
			}
Packit 992a25
			*cp = 0;
Packit 992a25
			m = ep ? (ep-sp) : 0;
Packit 992a25
			if(m==0 || m==6 && memcmp((void*)sp,(void*)"FPATH=",m)==0)
Packit 992a25
			{
Packit 992a25
				if(first)
Packit 992a25
				{
Packit 992a25
					char *ptr = stakptr(offset+pp->len+1);
Packit 992a25
					if(ep)
Packit 992a25
						strcpy(ptr,ep);
Packit 992a25
					path_addcomp(shp,first,old,stakptr(offset),PATH_FPATH|PATH_BFPATH);
Packit 992a25
				}
Packit 992a25
			}
Packit 992a25
			else if(m==11 && memcmp((void*)sp,(void*)"PLUGIN_LIB=",m)==0)
Packit 992a25
			{
Packit 992a25
				if(pp->bbuf)
Packit 992a25
					free(pp->bbuf);
Packit 992a25
				pp->blib = pp->bbuf = strdup(ep);
Packit 992a25
			}
Packit 992a25
			else if(m)
Packit 992a25
			{
Packit 992a25
				pp->lib = (char*)malloc(cp-sp+pp->len+2);
Packit 992a25
				memcpy((void*)pp->lib,(void*)sp,m);
Packit 992a25
				memcpy((void*)&pp->lib[m],stakptr(offset),pp->len);
Packit 992a25
				pp->lib[k=m+pp->len] = '/';
Packit 992a25
				strcpy((void*)&pp->lib[k+1],ep);
Packit 992a25
				pathcanon(&pp->lib[m],0);
Packit 992a25
				if(!first)
Packit 992a25
				{
Packit 992a25
					stakseek(0);
Packit 992a25
					stakputs(pp->lib);
Packit 992a25
					free((void*)pp->lib);
Packit 992a25
					return(1);
Packit 992a25
				}
Packit 992a25
			}
Packit 992a25
			sp = cp+1;
Packit 992a25
			ep = 0;
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
	return(0);
Packit 992a25
}
Packit 992a25
Packit 992a25
Packit 992a25
Pathcomp_t *path_addpath(Shell_t *shp,Pathcomp_t *first, register const char *path,int type)
Packit 992a25
{
Packit 992a25
	register const char *cp;
Packit 992a25
	Pathcomp_t *old=0;
Packit 992a25
	int offset = staktell();
Packit 992a25
	char *savptr;
Packit 992a25
	
Packit 992a25
	if(!path && type!=PATH_PATH)
Packit 992a25
		return(first);
Packit 992a25
	if(type!=PATH_FPATH)
Packit 992a25
	{
Packit 992a25
		old = first;
Packit 992a25
		first = 0;
Packit 992a25
	}
Packit 992a25
	if(offset)
Packit 992a25
		savptr = stakfreeze(0);
Packit 992a25
	if(path) while(*(cp=path))
Packit 992a25
	{
Packit 992a25
		if(*cp==':')
Packit 992a25
		{
Packit 992a25
			if(type!=PATH_FPATH)
Packit 992a25
				first = path_addcomp(shp,first,old,".",type);
Packit 992a25
			while(*++path == ':');
Packit 992a25
		}
Packit 992a25
		else
Packit 992a25
		{
Packit 992a25
			int c;
Packit 992a25
			while(*path && *path!=':')
Packit 992a25
				path++;
Packit 992a25
			c = *path++;
Packit 992a25
			first = path_addcomp(shp,first,old,cp,type);
Packit 992a25
			if(c==0)
Packit 992a25
				break;
Packit 992a25
			if(*path==0)
Packit 992a25
				path--;
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
	if(old)
Packit 992a25
	{
Packit 992a25
		if(!first && !path)
Packit 992a25
		{
Packit 992a25
			Pathcomp_t *pp = (Pathcomp_t*)shp->defpathlist;
Packit 992a25
			if(!pp)
Packit 992a25
				pp = defpath_init(shp);
Packit 992a25
			first = path_dup(pp);
Packit 992a25
		}
Packit 992a25
		if(cp=(sh_scoped(shp,FPATHNOD))->nvalue.cp)
Packit 992a25
			first = (void*)path_addpath(shp,(Pathcomp_t*)first,cp,PATH_FPATH);
Packit 992a25
		path_delete(old);
Packit 992a25
	}
Packit 992a25
	if(offset)
Packit 992a25
		stakset(savptr,offset);
Packit 992a25
	else
Packit 992a25
		stakseek(0);
Packit 992a25
	return(first);
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * duplicate the path give by <first> by incremented reference counts
Packit 992a25
 */
Packit 992a25
Pathcomp_t *path_dup(Pathcomp_t *first)
Packit 992a25
{
Packit 992a25
	register Pathcomp_t *pp=first;
Packit 992a25
	while(pp)
Packit 992a25
	{
Packit 992a25
		pp->refcount++;
Packit 992a25
		pp = pp->next;
Packit 992a25
	}
Packit 992a25
	return(first);
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * called whenever the directory is changed
Packit 992a25
 */
Packit 992a25
void path_newdir(Shell_t *shp,Pathcomp_t *first)
Packit 992a25
{
Packit 992a25
	register Pathcomp_t *pp=first, *next, *pq;
Packit 992a25
	struct stat statb;
Packit 992a25
	for(pp=first; pp; pp=pp->next)
Packit 992a25
	{
Packit 992a25
		pp->flags &= ~PATH_SKIP;
Packit 992a25
		if(*pp->name=='/')
Packit 992a25
			continue;
Packit 992a25
		/* delete .paths component */
Packit 992a25
		if((next=pp->next) && (next->flags&PATH_BFPATH))
Packit 992a25
		{
Packit 992a25
			pp->next = next->next;
Packit 992a25
			if(--next->refcount<=0)
Packit 992a25
				free((void*)next);
Packit 992a25
		}
Packit 992a25
		if(stat(pp->name,&statb)<0 || !S_ISDIR(statb.st_mode))
Packit 992a25
		{
Packit 992a25
			pp->dev = 0;
Packit 992a25
			pp->ino = 0;
Packit 992a25
			continue;
Packit 992a25
		}
Packit 992a25
		pp->dev = statb.st_dev;
Packit 992a25
		pp->ino = statb.st_ino;
Packit 992a25
		pp->mtime = statb.st_mtime;
Packit 992a25
		for(pq=first;pq!=pp;pq=pq->next)
Packit 992a25
		{
Packit 992a25
			if(pp->ino==pq->ino && pp->dev==pq->dev)
Packit 992a25
				pp->flags |= PATH_SKIP;
Packit 992a25
		}
Packit 992a25
		for(pq=pp;pq=pq->next;)
Packit 992a25
		{
Packit 992a25
			if(pp->ino==pq->ino && pp->dev==pq->dev)
Packit 992a25
				pq->flags |= PATH_SKIP;
Packit 992a25
		}
Packit 992a25
		if((pp->flags&(PATH_PATH|PATH_SKIP))==PATH_PATH)
Packit 992a25
		{
Packit 992a25
			/* try to insert .paths component */
Packit 992a25
			int offset = staktell();
Packit 992a25
			stakputs(pp->name);
Packit 992a25
			stakseek(offset);
Packit 992a25
			next = pp->next;
Packit 992a25
			pp->next = 0;
Packit 992a25
			path_chkpaths(shp,first,(Pathcomp_t*)0,pp,offset);
Packit 992a25
			if(pp->next)
Packit 992a25
				pp = pp->next;
Packit 992a25
			pp->next = next;
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
#if 0
Packit 992a25
	path_dump(first);
Packit 992a25
#endif
Packit 992a25
}
Packit 992a25
Packit 992a25
Pathcomp_t *path_unsetfpath(Shell_t *shp)
Packit 992a25
{
Packit 992a25
	Pathcomp_t	*first = (Pathcomp_t*)shp->pathlist;
Packit 992a25
	register Pathcomp_t *pp=first, *old=0;
Packit 992a25
	if(shp->fpathdict)
Packit 992a25
	{
Packit 992a25
		struct Ufunction  *rp, *rpnext;
Packit 992a25
		for(rp=(struct Ufunction*)dtfirst(shp->fpathdict);rp;rp=rpnext)
Packit 992a25
		{
Packit 992a25
			rpnext = (struct Ufunction*)dtnext(shp->fpathdict,rp);
Packit 992a25
			if(rp->fdict)
Packit 992a25
				nv_delete(rp->np,rp->fdict,NV_NOFREE);
Packit 992a25
			rp->fdict = 0;
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
	while(pp)
Packit 992a25
	{
Packit 992a25
		if((pp->flags&PATH_FPATH) && !(pp->flags&PATH_BFPATH))
Packit 992a25
		{
Packit 992a25
			if(pp->flags&PATH_PATH)
Packit 992a25
				pp->flags &= ~PATH_FPATH;
Packit 992a25
			else
Packit 992a25
			{
Packit 992a25
				Pathcomp_t *ppsave=pp;
Packit 992a25
				if(old)
Packit 992a25
					old->next = pp->next;
Packit 992a25
				else
Packit 992a25
					first = pp->next;
Packit 992a25
				pp = pp->next;
Packit 992a25
				if(--ppsave->refcount<=0)
Packit 992a25
				{
Packit 992a25
					if(ppsave->lib)
Packit 992a25
						free((void*)ppsave->lib);
Packit 992a25
					free((void*)ppsave);
Packit 992a25
				}
Packit 992a25
				continue;
Packit 992a25
			}
Packit 992a25
			
Packit 992a25
		}
Packit 992a25
		old = pp;
Packit 992a25
		pp = pp->next;
Packit 992a25
	}
Packit 992a25
	return(first);
Packit 992a25
}
Packit 992a25
Packit 992a25
Pathcomp_t *path_dirfind(Pathcomp_t *first,const char *name,int c)
Packit 992a25
{
Packit 992a25
	register Pathcomp_t *pp=first;
Packit 992a25
	while(pp)
Packit 992a25
	{
Packit 992a25
		if(memcmp(name,pp->name,pp->len)==0 && name[pp->len]==c) 
Packit 992a25
			return(pp);
Packit 992a25
		pp = pp->next;
Packit 992a25
	}
Packit 992a25
	return(0);
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * get discipline for tracked alias
Packit 992a25
 */
Packit 992a25
static char *talias_get(Namval_t *np, Namfun_t *nvp)
Packit 992a25
{
Packit 992a25
	Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp;
Packit 992a25
	char *ptr;
Packit 992a25
	if(!pp)
Packit 992a25
		return(NULL);
Packit 992a25
	pp->shp->last_table = 0;
Packit 992a25
	path_nextcomp(pp->shp,pp,nv_name(np),pp);
Packit 992a25
	ptr = stakfreeze(0);
Packit 992a25
	return(ptr+PATH_OFFSET);
Packit 992a25
}
Packit 992a25
Packit 992a25
static void talias_put(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
Packit 992a25
{
Packit 992a25
	if(!val && np->nvalue.cp)
Packit 992a25
	{
Packit 992a25
		Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp;
Packit 992a25
		if(--pp->refcount<=0)
Packit 992a25
			free((void*)pp);
Packit 992a25
	}
Packit 992a25
	nv_putv(np,val,flags,fp);
Packit 992a25
}
Packit 992a25
Packit 992a25
static const Namdisc_t talias_disc   = { 0, talias_put, talias_get   };
Packit 992a25
static Namfun_t  talias_init = { &talias_disc, 1 };
Packit 992a25
Packit 992a25
/*
Packit 992a25
 *  set tracked alias node <np> to value <pp>
Packit 992a25
 */
Packit 992a25
void path_alias(register Namval_t *np,register Pathcomp_t *pp)
Packit 992a25
{
Packit 992a25
	if(pp)
Packit 992a25
	{
Packit 992a25
		struct stat statb;
Packit 992a25
		char *sp;
Packit 992a25
		Pathcomp_t *old = 0;
Packit 992a25
		nv_offattr(np,NV_NOPRINT);
Packit 992a25
		nv_stack(np,&talias_init);
Packit 992a25
		old = (Pathcomp_t*)np->nvalue.cp;
Packit 992a25
		if (old && (--old->refcount <= 0))
Packit 992a25
			free((void*)old);
Packit 992a25
		np->nvalue.cp = (char*)pp;
Packit 992a25
		pp->refcount++;
Packit 992a25
		nv_setattr(np,NV_TAGGED|NV_NOFREE);
Packit 992a25
		path_nextcomp(pp->shp,pp,nv_name(np),pp);
Packit 992a25
		sp = stakptr(PATH_OFFSET);
Packit 992a25
		if(sp && lstat(sp,&statb)>=0 && S_ISLNK(statb.st_mode))
Packit 992a25
			nv_setsize(np,statb.st_size+1);
Packit 992a25
		else
Packit 992a25
			nv_setsize(np,0);
Packit 992a25
	}
Packit 992a25
	else
Packit 992a25
		_nv_unset(np,0);
Packit 992a25
}
Packit 992a25