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