14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1982-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * David Korn <dgk@research.att.com> *
184887Schin * *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin * David Korn
234887Schin * AT&T Labs
244887Schin *
254887Schin */
264887Schin
274887Schin #include "defs.h"
284887Schin #include <fcin.h>
294887Schin #include <ls.h>
304887Schin #include <nval.h>
314887Schin #include "variables.h"
324887Schin #include "path.h"
334887Schin #include "io.h"
344887Schin #include "jobs.h"
354887Schin #include "history.h"
364887Schin #include "test.h"
378462SApril.Chin@Sun.COM #include "FEATURE/dynamic"
384887Schin #include "FEATURE/externs"
394887Schin #if SHOPT_PFSH
404887Schin # ifdef _hdr_exec_attr
414887Schin # include <exec_attr.h>
424887Schin # endif
438462SApril.Chin@Sun.COM # if _lib_vfork
448462SApril.Chin@Sun.COM # include <ast_vfork.h>
458462SApril.Chin@Sun.COM # else
468462SApril.Chin@Sun.COM # define vfork() fork()
478462SApril.Chin@Sun.COM # endif
484887Schin #endif
494887Schin
504887Schin #define RW_ALL (S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH)
514887Schin #define LIBCMD "cmd"
524887Schin
534887Schin
544887Schin static int canexecute(char*,int);
554887Schin static void funload(Shell_t*,int,const char*);
564887Schin static void exscript(Shell_t*,char*, char*[], char**);
574887Schin static int path_chkpaths(Pathcomp_t*,Pathcomp_t*,Pathcomp_t*,int);
5810898Sroland.mainz@nrubsig.org static void path_checkdup(register Pathcomp_t*);
594887Schin
604887Schin static const char *std_path;
614887Schin
onstdpath(const char * name)624887Schin static int onstdpath(const char *name)
634887Schin {
644887Schin register const char *cp = std_path, *sp;
654887Schin if(cp)
664887Schin while(*cp)
674887Schin {
684887Schin for(sp=name; *sp && (*cp == *sp); sp++,cp++);
694887Schin if(*sp==0 && (*cp==0 || *cp==':'))
704887Schin return(1);
714887Schin while(*cp && *cp++!=':');
724887Schin }
734887Schin return(0);
744887Schin }
754887Schin
path_pfexecve(const char * path,char * argv[],char * const envp[],int spawn)768462SApril.Chin@Sun.COM static pid_t path_pfexecve(const char *path, char *argv[],char *const envp[],int spawn)
774887Schin {
784887Schin #if SHOPT_PFSH
798462SApril.Chin@Sun.COM pid_t pid;
804887Schin char resolvedpath[PATH_MAX + 1];
818462SApril.Chin@Sun.COM if(spawn)
828462SApril.Chin@Sun.COM {
838462SApril.Chin@Sun.COM while((pid = vfork()) < 0)
848462SApril.Chin@Sun.COM _sh_fork(pid, 0, (int*)0);
858462SApril.Chin@Sun.COM if(pid)
868462SApril.Chin@Sun.COM return(pid);
878462SApril.Chin@Sun.COM }
884887Schin if(!sh_isoption(SH_PFSH))
894887Schin return(execve(path, argv, envp));
904887Schin /* Solaris implements realpath(3C) using the resolvepath(2) */
914887Schin /* system call so we can save us to call access(2) first */
924887Schin if (!realpath(path, resolvedpath))
934887Schin return -1;
944887Schin
954887Schin /* we can exec the command directly instead of via pfexec(1) if */
964887Schin /* there is a matching entry without attributes in exec_attr(4) */
974887Schin if (sh.user && *sh.user)
984887Schin {
994887Schin execattr_t *pf;
1004887Schin if(pf=getexecuser(sh.user, KV_COMMAND, resolvedpath, GET_ONE))
1014887Schin {
1024887Schin if (!pf->attr || pf->attr->length == 0)
1034887Schin {
1044887Schin int r = execve(path, argv, envp);
1054887Schin free_execattr(pf);
1064887Schin return r;
1074887Schin }
1084887Schin free_execattr(pf);
1094887Schin }
1104887Schin else
1114887Schin {
1124887Schin errno = ENOENT;
1134887Schin return -1;
1144887Schin }
1154887Schin }
1164887Schin --argv;
1174887Schin argv[0] = argv[1];
1184887Schin argv[1] = resolvedpath;
1194887Schin return(execve("/usr/bin/pfexec", argv, envp));
1204887Schin #else
1214887Schin return(execve(path, argv, envp));
1224887Schin #endif
1234887Schin }
1244887Schin
1254887Schin
_spawnveg(const char * path,char * const argv[],char * const envp[],pid_t pgid)1268462SApril.Chin@Sun.COM static pid_t _spawnveg(const char *path, char* const argv[], char* const envp[], pid_t pgid)
1274887Schin {
1284887Schin int waitsafe = job.waitsafe;
1298462SApril.Chin@Sun.COM pid_t pid;
1304887Schin job_lock();
1318462SApril.Chin@Sun.COM while(1)
1328462SApril.Chin@Sun.COM {
1338462SApril.Chin@Sun.COM sh_stats(STAT_SPAWN);
1348462SApril.Chin@Sun.COM pid = spawnveg(path,argv,envp,pgid);
1358462SApril.Chin@Sun.COM if(pid>=0 || errno!=EAGAIN)
1368462SApril.Chin@Sun.COM break;
1378462SApril.Chin@Sun.COM _sh_fork(pid, 0, (int*)0);
1388462SApril.Chin@Sun.COM }
1394887Schin job.waitsafe = waitsafe;
140*12068SRoger.Faulkner@Oracle.COM if(pid>0)
141*12068SRoger.Faulkner@Oracle.COM job_fork(pid);
142*12068SRoger.Faulkner@Oracle.COM else
143*12068SRoger.Faulkner@Oracle.COM job_unlock();
1444887Schin return(pid);
1454887Schin }
1464887Schin /*
1474887Schin * used with command -x to run the command in multiple passes
1484887Schin * spawn is non-zero when invoked via spawn
1494887Schin * the exitval is set to the maximum for each execution
1504887Schin */
path_xargs(const char * path,char * argv[],char * const envp[],int spawn)1514887Schin static pid_t path_xargs(const char *path, char *argv[],char *const envp[], int spawn)
1524887Schin {
1534887Schin register char *cp, **av, **xv;
1544887Schin char **avlast= &argv[sh.xargmax], **saveargs=0;
1554887Schin char *const *ev;
1564887Schin long size, left;
1574887Schin int nlast=1,n,exitval=0;
1584887Schin pid_t pid;
1594887Schin if(sh.xargmin < 0)
1604887Schin return((pid_t)-1);
1614887Schin size = sh.lim.arg_max-1024;
1624887Schin for(ev=envp; cp= *ev; ev++)
1634887Schin size -= strlen(cp)-1;
1644887Schin for(av=argv; (cp= *av) && av< &argv[sh.xargmin]; av++)
1654887Schin size -= strlen(cp)-1;
1664887Schin for(av=avlast; cp= *av; av++,nlast++)
1674887Schin size -= strlen(cp)-1;
1684887Schin av = &argv[sh.xargmin];
1694887Schin if(!spawn)
1704887Schin job_clear();
1714887Schin sh.exitval = 0;
1724887Schin while(av<avlast)
1734887Schin {
1744887Schin for(xv=av,left=size; left>0 && av<avlast;)
1754887Schin left -= strlen(*av++)+1;
1764887Schin /* leave at least two for last */
1774887Schin if(left<0 && (avlast-av)<2)
1784887Schin av--;
1794887Schin if(xv==&argv[sh.xargmin])
1804887Schin {
1814887Schin n = nlast*sizeof(char*);
1824887Schin saveargs = (char**)malloc(n);
1834887Schin memcpy((void*)saveargs, (void*)av, n);
1844887Schin memcpy((void*)av,(void*)avlast,n);
1854887Schin }
1864887Schin else
1874887Schin {
1884887Schin for(n=sh.xargmin; xv < av; xv++)
1894887Schin argv[n++] = *xv;
1904887Schin for(xv=avlast; cp= *xv; xv++)
1914887Schin argv[n++] = cp;
1924887Schin argv[n] = 0;
1934887Schin }
1944887Schin if(saveargs || av<avlast || (exitval && !spawn))
1954887Schin {
1964887Schin if((pid=_spawnveg(path,argv,envp,0)) < 0)
1974887Schin return(-1);
1984887Schin job_post(pid,0);
1994887Schin job_wait(pid);
2004887Schin if(sh.exitval>exitval)
2014887Schin exitval = sh.exitval;
2024887Schin if(saveargs)
2034887Schin {
2044887Schin memcpy((void*)av,saveargs,n);
2054887Schin free((void*)saveargs);
2064887Schin saveargs = 0;
2074887Schin }
2084887Schin }
2094887Schin else if(spawn && !sh_isoption(SH_PFSH))
2104887Schin {
2114887Schin sh.xargexit = exitval;
2124887Schin return(_spawnveg(path,argv,envp,spawn>>1));
2134887Schin }
2144887Schin else
2158462SApril.Chin@Sun.COM return(path_pfexecve(path,argv,envp,spawn));
2164887Schin }
2174887Schin if(!spawn)
2184887Schin exit(exitval);
2194887Schin return((pid_t)-1);
2204887Schin }
2214887Schin
2224887Schin /*
2234887Schin * make sure PWD is set up correctly
2244887Schin * Return the present working directory
2254887Schin * Invokes getcwd() if flag==0 and if necessary
2264887Schin * Sets the PWD variable to this value
2274887Schin */
path_pwd(int flag)2284887Schin char *path_pwd(int flag)
2294887Schin {
2304887Schin register char *cp;
2314887Schin register char *dfault = (char*)e_dot;
2324887Schin register int count = 0;
2334887Schin Shell_t *shp = &sh;
2344887Schin if(shp->pwd)
2354887Schin return((char*)shp->pwd);
2364887Schin while(1)
2374887Schin {
2384887Schin /* try from lowest to highest */
2394887Schin switch(count++)
2404887Schin {
2414887Schin case 0:
2424887Schin cp = nv_getval(PWDNOD);
2434887Schin break;
2444887Schin case 1:
2454887Schin cp = nv_getval(HOME);
2464887Schin break;
2474887Schin case 2:
2484887Schin cp = "/";
2494887Schin break;
2504887Schin case 3:
2514887Schin cp = (char*)e_crondir;
2524887Schin if(flag) /* skip next case when non-zero flag */
2534887Schin ++count;
2544887Schin break;
2554887Schin case 4:
2564887Schin {
2574887Schin if(cp=getcwd(NIL(char*),0))
2584887Schin {
2594887Schin nv_offattr(PWDNOD,NV_NOFREE);
2604887Schin nv_unset(PWDNOD);
2614887Schin PWDNOD->nvalue.cp = cp;
2624887Schin goto skip;
2634887Schin }
2644887Schin break;
2654887Schin }
2664887Schin case 5:
2674887Schin return(dfault);
2684887Schin }
2694887Schin if(cp && *cp=='/' && test_inode(cp,e_dot))
2704887Schin break;
2714887Schin }
2724887Schin if(count>1)
2734887Schin {
2744887Schin nv_offattr(PWDNOD,NV_NOFREE);
2754887Schin nv_putval(PWDNOD,cp,NV_RDONLY);
2764887Schin }
2774887Schin skip:
2784887Schin nv_onattr(PWDNOD,NV_NOFREE|NV_EXPORT);
2794887Schin shp->pwd = (char*)(PWDNOD->nvalue.cp);
2804887Schin return(cp);
2814887Schin }
2824887Schin
free_bltin(Namval_t * np,void * data)2834887Schin static void free_bltin(Namval_t *np,void *data)
2844887Schin {
2854887Schin register Pathcomp_t *pp= (Pathcomp_t*)data;
2864887Schin if(pp->flags&PATH_STD_DIR)
2874887Schin {
2884887Schin int offset=staktell();;
2894887Schin if(strcmp(pp->name,"/bin")==0 || memcmp(pp->name,np->nvname,pp->len) || np->nvname[pp->len]!='/')
2904887Schin return;
2914887Schin stakputs("/bin");
2924887Schin stakputs(np->nvname+pp->len+1);
2934887Schin stakputc(0);
2944887Schin sh_addbuiltin(stakptr(offset),np->nvalue.bfp,NiL);
2954887Schin stakseek(offset);
2964887Schin return;
2974887Schin }
2984887Schin if((void*)np->nvenv==pp->bltin_lib)
2998462SApril.Chin@Sun.COM nv_delete(np,sh_bltin_tree(),NV_NOFREE);
3004887Schin }
3014887Schin
3024887Schin /*
3034887Schin * delete current Pathcomp_t structure
3044887Schin */
path_delete(Pathcomp_t * first)3054887Schin void path_delete(Pathcomp_t *first)
3064887Schin {
3074887Schin register Pathcomp_t *pp=first, *old=0, *ppnext;
3084887Schin while(pp)
3094887Schin {
3104887Schin ppnext = pp->next;
3114887Schin if(--pp->refcount<=0)
3124887Schin {
3134887Schin if(pp->lib)
3144887Schin free((void*)pp->lib);
3154887Schin if(pp->blib)
3164887Schin free((void*)pp->blib);
3174887Schin if(pp->bltin_lib || (pp->flags&PATH_STD_DIR))
3184887Schin {
3194887Schin nv_scan(sh_bltin_tree(),free_bltin,pp,0,0);
3208462SApril.Chin@Sun.COM #if SHOPT_DYNAMIC
3214887Schin if(pp->bltin_lib)
3224887Schin dlclose(pp->bltin_lib);
3238462SApril.Chin@Sun.COM #endif /* SHOPT_DYNAMIC */
3244887Schin }
3254887Schin free((void*)pp);
3264887Schin if(old)
3274887Schin old->next = ppnext;
3284887Schin }
3294887Schin else
3304887Schin old = pp;
3314887Schin pp = ppnext;
3324887Schin }
3334887Schin }
3344887Schin
3354887Schin /*
3364887Schin * returns library variable from .paths
3374887Schin * The value might be returned on the stack overwriting path
3384887Schin */
path_lib(Pathcomp_t * pp,char * path)3394887Schin static char *path_lib(Pathcomp_t *pp, char *path)
3404887Schin {
3414887Schin register char *last = strrchr(path,'/');
3424887Schin register int r;
3434887Schin struct stat statb;
3444887Schin if(last)
3454887Schin *last = 0;
3464887Schin else
3474887Schin path = ".";
3484887Schin r = stat(path,&statb);
3494887Schin if(last)
3504887Schin *last = '/';
3514887Schin if(r>=0)
3524887Schin {
3534887Schin Pathcomp_t pcomp;
3544887Schin char save[8];
3554887Schin for( ;pp; pp=pp->next)
3564887Schin {
35710898Sroland.mainz@nrubsig.org path_checkdup(pp);
3588462SApril.Chin@Sun.COM if(pp->ino==statb.st_ino && pp->dev==statb.st_dev && pp->mtime==statb.st_mtime)
3594887Schin return(pp->lib);
3604887Schin }
3614887Schin pcomp.len = 0;
3624887Schin if(last)
3634887Schin pcomp.len = last-path;
3644887Schin memcpy((void*)save, (void*)stakptr(PATH_OFFSET+pcomp.len),sizeof(save));
3654887Schin if(path_chkpaths((Pathcomp_t*)0,(Pathcomp_t*)0,&pcomp,PATH_OFFSET))
3664887Schin return(stakfreeze(1));
3674887Schin memcpy((void*)stakptr(PATH_OFFSET+pcomp.len),(void*)save,sizeof(save));
3684887Schin }
3694887Schin return(0);
3704887Schin }
3714887Schin
3724887Schin #if 0
3734887Schin void path_dump(register Pathcomp_t *pp)
3744887Schin {
3754887Schin sfprintf(sfstderr,"dump\n");
3764887Schin while(pp)
3774887Schin {
3784887Schin sfprintf(sfstderr,"pp=%x dev=%d ino=%d len=%d flags=%o name=%.*s\n",
3794887Schin pp,pp->dev,pp->ino,pp->len,pp->flags,pp->len,pp->name);
3804887Schin pp = pp->next;
3814887Schin }
3824887Schin }
3834887Schin #endif
3844887Schin
3854887Schin /*
38610898Sroland.mainz@nrubsig.org * check for duplicate directories on PATH
38710898Sroland.mainz@nrubsig.org */
path_checkdup(register Pathcomp_t * pp)38810898Sroland.mainz@nrubsig.org static void path_checkdup(register Pathcomp_t *pp)
38910898Sroland.mainz@nrubsig.org {
39010898Sroland.mainz@nrubsig.org register char *name = pp->name;
39110898Sroland.mainz@nrubsig.org register Pathcomp_t *oldpp,*first;
39210898Sroland.mainz@nrubsig.org register int flag=0;
39310898Sroland.mainz@nrubsig.org struct stat statb;
39410898Sroland.mainz@nrubsig.org if(stat(name,&statb)<0 || !S_ISDIR(statb.st_mode))
39510898Sroland.mainz@nrubsig.org {
39610898Sroland.mainz@nrubsig.org pp->flags |= PATH_SKIP;
39710898Sroland.mainz@nrubsig.org pp->dev = *name=='/';
39810898Sroland.mainz@nrubsig.org return;
39910898Sroland.mainz@nrubsig.org }
40010898Sroland.mainz@nrubsig.org pp->mtime = statb.st_mtime;
40110898Sroland.mainz@nrubsig.org pp->ino = statb.st_ino;
40210898Sroland.mainz@nrubsig.org pp->dev = statb.st_dev;
40310898Sroland.mainz@nrubsig.org if(*name=='/' && onstdpath(name))
40410898Sroland.mainz@nrubsig.org flag = PATH_STD_DIR;
40510898Sroland.mainz@nrubsig.org first = (pp->flags&PATH_CDPATH)?pp->shp->cdpathlist:path_get("");
40610898Sroland.mainz@nrubsig.org for(oldpp=first; oldpp && oldpp!=pp; oldpp=oldpp->next)
40710898Sroland.mainz@nrubsig.org {
40810898Sroland.mainz@nrubsig.org if(pp->ino==oldpp->ino && pp->dev==oldpp->dev && pp->mtime==oldpp->mtime)
40910898Sroland.mainz@nrubsig.org {
41010898Sroland.mainz@nrubsig.org flag |= PATH_SKIP;
41110898Sroland.mainz@nrubsig.org break;
41210898Sroland.mainz@nrubsig.org }
41310898Sroland.mainz@nrubsig.org }
41410898Sroland.mainz@nrubsig.org pp->flags |= flag;
41510898Sroland.mainz@nrubsig.org if(((pp->flags&(PATH_PATH|PATH_SKIP))==PATH_PATH))
41610898Sroland.mainz@nrubsig.org {
41710898Sroland.mainz@nrubsig.org int offset = staktell();
41810898Sroland.mainz@nrubsig.org stakputs(name);
41910898Sroland.mainz@nrubsig.org path_chkpaths(first,0,pp,offset);
42010898Sroland.mainz@nrubsig.org stakseek(offset);
42110898Sroland.mainz@nrubsig.org }
42210898Sroland.mainz@nrubsig.org }
42310898Sroland.mainz@nrubsig.org
42410898Sroland.mainz@nrubsig.org /*
4254887Schin * write the next path to search on the current stack
4264887Schin * if last is given, all paths that come before <last> are skipped
4274887Schin * the next pathcomp is returned.
4284887Schin */
path_nextcomp(register Pathcomp_t * pp,const char * name,Pathcomp_t * last)4294887Schin Pathcomp_t *path_nextcomp(register Pathcomp_t *pp, const char *name, Pathcomp_t *last)
4304887Schin {
43110898Sroland.mainz@nrubsig.org Pathcomp_t *ppnext;
4324887Schin stakseek(PATH_OFFSET);
4334887Schin if(*name=='/')
4344887Schin pp = 0;
4354887Schin else
4364887Schin {
43710898Sroland.mainz@nrubsig.org for(;pp && pp!=last;pp=ppnext)
4384887Schin {
43910898Sroland.mainz@nrubsig.org if(ppnext=pp->next)
44010898Sroland.mainz@nrubsig.org ppnext->shp = pp->shp;
44110898Sroland.mainz@nrubsig.org if(!pp->dev && !pp->ino)
44210898Sroland.mainz@nrubsig.org path_checkdup(pp);
4434887Schin if(pp->flags&PATH_SKIP)
4444887Schin continue;
4454887Schin if(!last || *pp->name!='/')
4464887Schin break;
4474887Schin }
4484887Schin if(!pp) /* this should not happen */
4494887Schin pp = last;
4504887Schin }
4514887Schin if(pp && (pp->name[0]!='.' || pp->name[1]))
4524887Schin {
4534887Schin if(*pp->name!='/')
4544887Schin {
4554887Schin stakputs(path_pwd(1));
4564887Schin if(*stakptr(staktell()-1)!='/')
4574887Schin stakputc('/');
4584887Schin }
4594887Schin stakwrite(pp->name,pp->len);
4604887Schin if(pp->name[pp->len-1]!='/')
4614887Schin stakputc('/');
4624887Schin }
4634887Schin stakputs(name);
4644887Schin stakputc(0);
4654887Schin while(pp && pp!=last && (pp=pp->next))
4664887Schin {
4674887Schin if(!(pp->flags&PATH_SKIP))
4684887Schin return(pp);
4694887Schin }
4704887Schin return((Pathcomp_t*)0);
4714887Schin }
4724887Schin
defpath_init(Shell_t * shp)4734887Schin static Pathcomp_t* defpath_init(Shell_t *shp)
4744887Schin {
4754887Schin Pathcomp_t *pp = (void*)path_addpath((Pathcomp_t*)0,(std_path),PATH_PATH);
4764887Schin if(shp->defpathlist = (void*)pp)
4774887Schin pp->shp = shp;
4784887Schin return(pp);
4794887Schin }
4804887Schin
path_init(Shell_t * shp)4814887Schin static void path_init(Shell_t *shp)
4824887Schin {
4834887Schin const char *val;
4844887Schin Pathcomp_t *pp;
4854887Schin if(!std_path && !(std_path=astconf("PATH",NIL(char*),NIL(char*))))
4864887Schin std_path = e_defpath;
4878462SApril.Chin@Sun.COM if(val=sh_scoped(shp,(PATHNOD))->nvalue.cp)
4884887Schin {
4894887Schin pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_PATH);
4904887Schin if(shp->pathlist = (void*)pp)
4914887Schin pp->shp = shp;
4924887Schin }
4934887Schin else
4944887Schin {
4954887Schin if(!(pp=(Pathcomp_t*)shp->defpathlist))
4964887Schin pp = defpath_init(shp);
4974887Schin shp->pathlist = (void*)path_dup(pp);
4984887Schin }
4998462SApril.Chin@Sun.COM if(val=sh_scoped(shp,(FPATHNOD))->nvalue.cp)
5004887Schin {
5014887Schin pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_FPATH);
5024887Schin if(shp->pathlist = (void*)pp)
5034887Schin pp->shp = shp;
5044887Schin }
5054887Schin }
5064887Schin
5074887Schin /*
5084887Schin * returns that pathlist to search
5094887Schin */
path_get(register const char * name)5104887Schin Pathcomp_t *path_get(register const char *name)
5114887Schin {
5124887Schin register Shell_t *shp = &sh;
5134887Schin register Pathcomp_t *pp=0;
5144887Schin if(*name && strchr(name,'/'))
5154887Schin return(0);
5164887Schin if(!sh_isstate(SH_DEFPATH))
5174887Schin {
5184887Schin if(!shp->pathlist)
5194887Schin path_init(shp);
5204887Schin pp = (Pathcomp_t*)shp->pathlist;
5214887Schin }
5224887Schin if(!pp && (!(PATHNOD)->nvalue.cp) || sh_isstate(SH_DEFPATH))
5234887Schin {
5244887Schin if(!(pp=(Pathcomp_t*)shp->defpathlist))
5254887Schin pp = defpath_init(shp);
5264887Schin }
5274887Schin return(pp);
5284887Schin }
5294887Schin
5304887Schin /*
5314887Schin * open file corresponding to name using path give by <pp>
5324887Schin */
path_opentype(const char * name,register Pathcomp_t * pp,int fun)5334887Schin static int path_opentype(const char *name, register Pathcomp_t *pp, int fun)
5344887Schin {
5354887Schin register int fd= -1;
5364887Schin struct stat statb;
5374887Schin Pathcomp_t *oldpp;
5384887Schin Shell_t *shp;
5394887Schin if(pp)
5404887Schin shp = pp->shp;
5414887Schin else
5424887Schin {
5434887Schin shp = sh_getinterp();
5444887Schin if(!shp->pathlist)
5454887Schin path_init(shp);
5464887Schin }
5474887Schin if(!fun && strchr(name,'/'))
5484887Schin {
5494887Schin if(sh_isoption(SH_RESTRICTED))
5504887Schin errormsg(SH_DICT,ERROR_exit(1),e_restricted,name);
5514887Schin }
5524887Schin do
5534887Schin {
5544887Schin pp = path_nextcomp(oldpp=pp,name,0);
5554887Schin while(oldpp && (oldpp->flags&PATH_SKIP))
5564887Schin oldpp = oldpp->next;
5574887Schin if(fun && (!oldpp || !(oldpp->flags&PATH_FPATH)))
5584887Schin continue;
5594887Schin if((fd = sh_open(path_relative(stakptr(PATH_OFFSET)),O_RDONLY,0)) >= 0)
5604887Schin {
5614887Schin if(fstat(fd,&statb)<0 || S_ISDIR(statb.st_mode))
5624887Schin {
5634887Schin errno = EISDIR;
5644887Schin sh_close(fd);
5654887Schin fd = -1;
5664887Schin }
5674887Schin }
5684887Schin }
5694887Schin while( fd<0 && pp);
5704887Schin if(fd>=0 && (fd = sh_iomovefd(fd)) > 0)
5714887Schin {
5724887Schin fcntl(fd,F_SETFD,FD_CLOEXEC);
57310898Sroland.mainz@nrubsig.org if(!shp)
57410898Sroland.mainz@nrubsig.org {
57510898Sroland.mainz@nrubsig.org shp = sh_getinterp();
57610898Sroland.mainz@nrubsig.org #if _UWIN
57710898Sroland.mainz@nrubsig.org close(0x10001); /* this results in a /var/log/uwin message with "0x10001" for debugging */
57810898Sroland.mainz@nrubsig.org #endif
57910898Sroland.mainz@nrubsig.org }
5804887Schin shp->fdstatus[fd] |= IOCLEX;
5814887Schin }
5824887Schin return(fd);
5834887Schin }
5844887Schin
5854887Schin /*
5864887Schin * open file corresponding to name using path give by <pp>
5874887Schin */
path_open(const char * name,register Pathcomp_t * pp)5884887Schin int path_open(const char *name, register Pathcomp_t *pp)
5894887Schin {
5904887Schin return(path_opentype(name,pp,0));
5914887Schin }
5924887Schin
5934887Schin /*
5944887Schin * given a pathname return the base name
5954887Schin */
5964887Schin
path_basename(register const char * name)5974887Schin char *path_basename(register const char *name)
5984887Schin {
5994887Schin register const char *start = name;
6004887Schin while (*name)
6014887Schin if ((*name++ == '/') && *name) /* don't trim trailing / */
6024887Schin start = name;
6034887Schin return ((char*)start);
6044887Schin }
6054887Schin
path_fullname(const char * name)6064887Schin char *path_fullname(const char *name)
6074887Schin {
6084887Schin int len=strlen(name)+1,dirlen=0;
6094887Schin char *path,*pwd;
6104887Schin if(*name!='/')
6114887Schin {
6124887Schin pwd = path_pwd(1);
6134887Schin dirlen = strlen(pwd)+1;
6144887Schin }
6154887Schin path = (char*)malloc(len+dirlen);
6164887Schin if(dirlen)
6174887Schin {
6184887Schin memcpy((void*)path,(void*)pwd,dirlen);
6194887Schin path[dirlen-1] = '/';
6204887Schin }
6214887Schin memcpy((void*)&path[dirlen],(void*)name,len);
6224887Schin pathcanon(path,0);
6234887Schin return(path);
6244887Schin }
6254887Schin
6264887Schin /*
6274887Schin * load functions from file <fno>
6284887Schin */
funload(Shell_t * shp,int fno,const char * name)6294887Schin static void funload(Shell_t *shp,int fno, const char *name)
6304887Schin {
6318462SApril.Chin@Sun.COM char *pname,*oldname=shp->st.filename, buff[IOBSIZE+1];
6328462SApril.Chin@Sun.COM Namval_t *np;
6338462SApril.Chin@Sun.COM struct Ufunction *rp;
6348462SApril.Chin@Sun.COM int savestates = sh_getstate(), oldload=shp->funload;
6358462SApril.Chin@Sun.COM pname = path_fullname(stakptr(PATH_OFFSET));
6368462SApril.Chin@Sun.COM if(shp->fpathdict && (rp = dtmatch(shp->fpathdict,(void*)pname)))
6378462SApril.Chin@Sun.COM {
63810898Sroland.mainz@nrubsig.org Dt_t *funtree = sh_subfuntree(1);
6398462SApril.Chin@Sun.COM do
6408462SApril.Chin@Sun.COM {
64110898Sroland.mainz@nrubsig.org if((np = dtsearch(funtree,rp->np)) && is_afunction(np))
6428462SApril.Chin@Sun.COM {
6438462SApril.Chin@Sun.COM if(np->nvalue.rp)
6448462SApril.Chin@Sun.COM np->nvalue.rp->fdict = 0;
64510898Sroland.mainz@nrubsig.org nv_delete(np,funtree,NV_NOFREE);
6468462SApril.Chin@Sun.COM }
64710898Sroland.mainz@nrubsig.org dtinsert(funtree,rp->np);
64810898Sroland.mainz@nrubsig.org rp->fdict = funtree;
6498462SApril.Chin@Sun.COM }
6508462SApril.Chin@Sun.COM while((rp=dtnext(shp->fpathdict,rp)) && strcmp(pname,rp->fname)==0);
6518462SApril.Chin@Sun.COM return;
6528462SApril.Chin@Sun.COM }
6534887Schin sh_onstate(SH_NOLOG);
6544887Schin sh_onstate(SH_NOALIAS);
6554887Schin shp->readscript = (char*)name;
6568462SApril.Chin@Sun.COM shp->st.filename = pname;
6578462SApril.Chin@Sun.COM shp->funload = 1;
6584887Schin error_info.line = 0;
65910898Sroland.mainz@nrubsig.org sh_eval(sfnew(NIL(Sfio_t*),buff,IOBSIZE,fno,SF_READ),SH_FUNEVAL);
6604887Schin shp->readscript = 0;
6614887Schin free((void*)shp->st.filename);
6628462SApril.Chin@Sun.COM shp->funload = oldload;
6634887Schin shp->st.filename = oldname;
6644887Schin sh_setstate(savestates);
6654887Schin }
6664887Schin
6674887Schin /*
6684887Schin * do a path search and track alias if requested
6694887Schin * if flag is 0, or if name not found, then try autoloading function
6708462SApril.Chin@Sun.COM * if flag==2 or 3, returns 1 if name found on FPATH
6718462SApril.Chin@Sun.COM * if flag==3 no tracked alias will be set
6724887Schin * returns 1, if function was autoloaded.
6738462SApril.Chin@Sun.COM * If oldpp is not NULL, it will contain a pointer to the path component
6748462SApril.Chin@Sun.COM * where it was found.
6754887Schin */
6764887Schin
path_search(register const char * name,Pathcomp_t ** oldpp,int flag)6778462SApril.Chin@Sun.COM int path_search(register const char *name,Pathcomp_t **oldpp, int flag)
6784887Schin {
6794887Schin register Namval_t *np;
6804887Schin register int fno;
6814887Schin Pathcomp_t *pp=0;
6824887Schin Shell_t *shp = &sh;
6834887Schin if(name && strchr(name,'/'))
6844887Schin {
6854887Schin stakseek(PATH_OFFSET);
6864887Schin stakputs(name);
6874887Schin if(canexecute(stakptr(PATH_OFFSET),0)<0)
6884887Schin {
6894887Schin *stakptr(PATH_OFFSET) = 0;
6904887Schin return(0);
6914887Schin }
6924887Schin if(*name=='/')
6934887Schin return(1);
6944887Schin stakseek(PATH_OFFSET);
6954887Schin stakputs(path_pwd(1));
6964887Schin stakputc('/');
6974887Schin stakputs(name);
6984887Schin stakputc(0);
6994887Schin return(0);
7004887Schin }
7014887Schin if(sh_isstate(SH_DEFPATH))
7024887Schin {
7034887Schin if(!shp->defpathlist)
7044887Schin defpath_init(shp);
7054887Schin }
7064887Schin else if(!shp->pathlist)
7074887Schin path_init(shp);
7084887Schin if(flag)
7094887Schin {
71010898Sroland.mainz@nrubsig.org if((np=nv_search(name,shp->track_tree,0)) && !nv_isattr(np,NV_NOALIAS) && (pp=(Pathcomp_t*)np->nvalue.cp))
71110898Sroland.mainz@nrubsig.org {
71210898Sroland.mainz@nrubsig.org stakseek(PATH_OFFSET);
71310898Sroland.mainz@nrubsig.org path_nextcomp(pp,name,pp);
71410898Sroland.mainz@nrubsig.org stakputc(0);
71510898Sroland.mainz@nrubsig.org return(0);
71610898Sroland.mainz@nrubsig.org }
7178462SApril.Chin@Sun.COM pp = path_absolute(name,oldpp?*oldpp:NIL(Pathcomp_t*));
7188462SApril.Chin@Sun.COM if(oldpp)
7198462SApril.Chin@Sun.COM *oldpp = pp;
72010898Sroland.mainz@nrubsig.org if(!pp && (np=nv_search(name,shp->fun_tree,HASH_NOSCOPE))&&np->nvalue.ip)
7214887Schin return(1);
7224887Schin if(!pp)
7234887Schin *stakptr(PATH_OFFSET) = 0;
7244887Schin }
7254887Schin if(flag==0 || !pp || (pp->flags&PATH_FPATH))
7264887Schin {
7274887Schin if(!pp)
7284887Schin pp=sh_isstate(SH_DEFPATH)?shp->defpathlist:shp->pathlist;
7294887Schin if(pp && strmatch(name,e_alphanum) && (fno=path_opentype(name,pp,1))>=0)
7304887Schin {
7314887Schin if(flag==2)
7324887Schin {
7334887Schin sh_close(fno);
7344887Schin return(1);
7354887Schin }
7364887Schin funload(shp,fno,name);
7374887Schin return(1);
7384887Schin }
7394887Schin *stakptr(PATH_OFFSET) = 0;
7404887Schin return(0);
7414887Schin }
7428462SApril.Chin@Sun.COM else if(pp && !sh_isstate(SH_DEFPATH) && *name!='/' && flag<3)
7434887Schin {
7444887Schin if(np=nv_search(name,shp->track_tree,NV_ADD))
7454887Schin path_alias(np,pp);
7464887Schin }
7474887Schin return(0);
7484887Schin }
7494887Schin
7504887Schin /*
7514887Schin * do a path search and find the full pathname of file name
7524887Schin */
path_absolute(register const char * name,Pathcomp_t * pp)7538462SApril.Chin@Sun.COM Pathcomp_t *path_absolute(register const char *name, Pathcomp_t *pp)
7544887Schin {
7554887Schin register int f,isfun;
7564887Schin int noexec=0;
7578462SApril.Chin@Sun.COM Pathcomp_t *oldpp;
7584887Schin Shell_t *shp = &sh;
7594887Schin Namval_t *np;
7604887Schin shp->path_err = ENOENT;
7618462SApril.Chin@Sun.COM if(!pp && !(pp=path_get("")))
7624887Schin return(0);
7634887Schin shp->path_err = 0;
7644887Schin while(1)
7654887Schin {
7664887Schin sh_sigcheck();
7674887Schin isfun = (pp->flags&PATH_FPATH);
7684887Schin if(oldpp=pp)
76910898Sroland.mainz@nrubsig.org {
7704887Schin pp = path_nextcomp(pp,name,0);
77110898Sroland.mainz@nrubsig.org while(oldpp->flags&PATH_SKIP)
77210898Sroland.mainz@nrubsig.org {
77310898Sroland.mainz@nrubsig.org if(!(oldpp=oldpp->next))
77410898Sroland.mainz@nrubsig.org {
77510898Sroland.mainz@nrubsig.org shp->path_err = ENOENT;
77610898Sroland.mainz@nrubsig.org return(0);
77710898Sroland.mainz@nrubsig.org }
77810898Sroland.mainz@nrubsig.org }
77910898Sroland.mainz@nrubsig.org }
78010898Sroland.mainz@nrubsig.org
7814887Schin if(!isfun && !sh_isoption(SH_RESTRICTED))
7824887Schin {
7838462SApril.Chin@Sun.COM if(*stakptr(PATH_OFFSET)=='/' && nv_search(stakptr(PATH_OFFSET),sh.bltin_tree,0))
7844887Schin return(oldpp);
7858462SApril.Chin@Sun.COM #if SHOPT_DYNAMIC
7864887Schin if(oldpp->blib)
7874887Schin {
7884887Schin typedef int (*Fptr_t)(int, char*[], void*);
7894887Schin Fptr_t addr;
7904887Schin int n = staktell();
79110898Sroland.mainz@nrubsig.org int libcmd;
7924887Schin char *cp;
7934887Schin stakputs("b_");
7944887Schin stakputs(name);
7954887Schin stakputc(0);
7964887Schin if(!oldpp->bltin_lib)
7974887Schin {
7984887Schin if(cp = strrchr(oldpp->blib,'/'))
7994887Schin cp++;
8004887Schin else
8014887Schin cp = oldpp->blib;
80210898Sroland.mainz@nrubsig.org if((libcmd = !strcmp(cp,LIBCMD)) && (addr=(Fptr_t)dlllook((void*)0,stakptr(n))))
8034887Schin {
8048462SApril.Chin@Sun.COM if((np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL)) && nv_isattr(np,NV_BLTINOPT))
8058462SApril.Chin@Sun.COM return(oldpp);
8064887Schin }
8074887Schin #if (_AST_VERSION>=20040404)
8084887Schin if (oldpp->bltin_lib = dllplug(SH_ID, oldpp->blib, NiL, RTLD_LAZY, NiL, 0))
8094887Schin #else
8104887Schin if (oldpp->bltin_lib = dllfind(oldpp->blib, NiL, RTLD_LAZY, NiL, 0))
8114887Schin #endif
81210898Sroland.mainz@nrubsig.org {
81310898Sroland.mainz@nrubsig.org /*
81410898Sroland.mainz@nrubsig.org * this detects the 2007-05-11 builtin context change and also
81510898Sroland.mainz@nrubsig.org * the 2008-03-30 opt_info.num change that hit libcmd::b_head
81610898Sroland.mainz@nrubsig.org */
81710898Sroland.mainz@nrubsig.org
81810898Sroland.mainz@nrubsig.org if (libcmd && !dlllook(oldpp->bltin_lib, "b_pids"))
81910898Sroland.mainz@nrubsig.org {
82010898Sroland.mainz@nrubsig.org dlclose(oldpp->bltin_lib);
82110898Sroland.mainz@nrubsig.org oldpp->bltin_lib = 0;
82210898Sroland.mainz@nrubsig.org oldpp->blib = 0;
82310898Sroland.mainz@nrubsig.org }
82410898Sroland.mainz@nrubsig.org else
82510898Sroland.mainz@nrubsig.org sh_addlib(oldpp->bltin_lib);
82610898Sroland.mainz@nrubsig.org }
8274887Schin }
8284887Schin if((addr=(Fptr_t)dlllook(oldpp->bltin_lib,stakptr(n))) &&
8294887Schin (!(np = sh_addbuiltin(stakptr(PATH_OFFSET),NiL,NiL)) || np->nvalue.bfp!=addr) &&
8304887Schin (np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL)))
8314887Schin {
8324887Schin np->nvenv = oldpp->bltin_lib;
8334887Schin return(oldpp);
8344887Schin }
8354887Schin }
8368462SApril.Chin@Sun.COM #endif /* SHOPT_DYNAMIC */
8374887Schin }
8388462SApril.Chin@Sun.COM sh_stats(STAT_PATHS);
8394887Schin f = canexecute(stakptr(PATH_OFFSET),isfun);
8404887Schin if(isfun && f>=0)
8414887Schin {
84210898Sroland.mainz@nrubsig.org nv_onattr(nv_open(name,sh_subfuntree(1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE),NV_LTOU|NV_FUNCTION);
84310898Sroland.mainz@nrubsig.org funload(shp,f,name);
8444887Schin close(f);
8454887Schin f = -1;
8464887Schin return(0);
8474887Schin }
8484887Schin else if(f>=0 && (oldpp->flags & PATH_STD_DIR))
8494887Schin {
8508462SApril.Chin@Sun.COM int n = staktell();
8514887Schin stakputs("/bin/");
8524887Schin stakputs(name);
8534887Schin stakputc(0);
8548462SApril.Chin@Sun.COM np = nv_search(stakptr(n),sh.bltin_tree,0);
8558462SApril.Chin@Sun.COM stakseek(n);
8564887Schin if(np)
8574887Schin {
8588462SApril.Chin@Sun.COM n = np->nvflag;
8598462SApril.Chin@Sun.COM np = sh_addbuiltin(stakptr(PATH_OFFSET),np->nvalue.bfp,nv_context(np));
8608462SApril.Chin@Sun.COM np->nvflag = n;
8614887Schin }
8624887Schin }
8634887Schin if(!pp || f>=0)
8644887Schin break;
8654887Schin if(errno!=ENOENT)
8664887Schin noexec = errno;
8674887Schin }
8684887Schin if(f<0)
8694887Schin {
8708462SApril.Chin@Sun.COM shp->path_err = (noexec?noexec:ENOENT);
8714887Schin return(0);
8724887Schin }
8734887Schin stakputc(0);
8744887Schin return(oldpp);
8754887Schin }
8764887Schin
8774887Schin /*
8784887Schin * returns 0 if path can execute
8794887Schin * sets exec_err if file is found but can't be executable
8804887Schin */
8814887Schin #undef S_IXALL
8824887Schin #ifdef S_IXUSR
8834887Schin # define S_IXALL (S_IXUSR|S_IXGRP|S_IXOTH)
8844887Schin #else
8854887Schin # ifdef S_IEXEC
8864887Schin # define S_IXALL (S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6))
8874887Schin # else
8884887Schin # define S_IXALL 0111
8894887Schin # endif /*S_EXEC */
8904887Schin #endif /* S_IXUSR */
8914887Schin
canexecute(register char * path,int isfun)8924887Schin static int canexecute(register char *path, int isfun)
8934887Schin {
8944887Schin struct stat statb;
8954887Schin register int fd=0;
8964887Schin path = path_relative(path);
8974887Schin if(isfun)
8984887Schin {
8994887Schin if((fd=open(path,O_RDONLY,0))<0 || fstat(fd,&statb)<0)
9004887Schin goto err;
9014887Schin }
9024887Schin else if(stat(path,&statb) < 0)
9034887Schin {
9044887Schin #if _WINIX
9054887Schin /* check for .exe or .bat suffix */
9064887Schin char *cp;
9074887Schin if(errno==ENOENT && (!(cp=strrchr(path,'.')) || strlen(cp)>4 || strchr(cp,'/')))
9084887Schin {
9094887Schin int offset = staktell()-1;
9104887Schin stakseek(offset);
9114887Schin stakputs(".bat");
9124887Schin path = stakptr(PATH_OFFSET);
9134887Schin if(stat(path,&statb) < 0)
9144887Schin {
9154887Schin if(errno!=ENOENT)
9164887Schin goto err;
9174887Schin memcpy(stakptr(offset),".sh",4);
9184887Schin if(stat(path,&statb) < 0)
9194887Schin goto err;
9204887Schin }
9214887Schin }
9224887Schin else
9234887Schin #endif /* _WINIX */
9244887Schin goto err;
9254887Schin }
9264887Schin errno = EPERM;
9274887Schin if(S_ISDIR(statb.st_mode))
9284887Schin errno = EISDIR;
9294887Schin else if((statb.st_mode&S_IXALL)==S_IXALL || sh_access(path,X_OK)>=0)
9304887Schin return(fd);
9314887Schin if(isfun && fd>=0)
9324887Schin sh_close(fd);
9334887Schin err:
9344887Schin return(-1);
9354887Schin }
9364887Schin
9374887Schin /*
9384887Schin * Return path relative to present working directory
9394887Schin */
9404887Schin
path_relative(register const char * file)9414887Schin char *path_relative(register const char* file)
9424887Schin {
9434887Schin register const char *pwd;
9444887Schin register const char *fp = file;
9454887Schin /* can't relpath when sh.pwd not set */
9464887Schin if(!(pwd=sh.pwd))
9474887Schin return((char*)fp);
9484887Schin while(*pwd==*fp)
9494887Schin {
9504887Schin if(*pwd++==0)
9514887Schin return((char*)e_dot);
9524887Schin fp++;
9534887Schin }
9544887Schin if(*pwd==0 && *fp == '/')
9554887Schin {
9564887Schin while(*++fp=='/');
9574887Schin if(*fp)
9584887Schin return((char*)fp);
9594887Schin return((char*)e_dot);
9604887Schin }
9614887Schin return((char*)file);
9624887Schin }
9634887Schin
path_exec(register const char * arg0,register char * argv[],struct argnod * local)9644887Schin void path_exec(register const char *arg0,register char *argv[],struct argnod *local)
9654887Schin {
9664887Schin char **envp;
9674887Schin const char *opath;
9684887Schin Pathcomp_t *libpath, *pp=0;
9694887Schin Shell_t *shp = &sh;
9704887Schin int slash=0;
97110898Sroland.mainz@nrubsig.org nv_setlist(local,NV_EXPORT|NV_IDENT|NV_ASSIGN,0);
9724887Schin envp = sh_envgen();
9734887Schin if(strchr(arg0,'/'))
9744887Schin {
9754887Schin slash=1;
9764887Schin /* name containing / not allowed for restricted shell */
9774887Schin if(sh_isoption(SH_RESTRICTED))
9784887Schin errormsg(SH_DICT,ERROR_exit(1),e_restricted,arg0);
9794887Schin }
9804887Schin else
9814887Schin pp=path_get(arg0);
9824887Schin shp->path_err= ENOENT;
9834887Schin sfsync(NIL(Sfio_t*));
9844887Schin timerdel(NIL(void*));
9854887Schin /* find first path that has a library component */
98610898Sroland.mainz@nrubsig.org while(pp && (pp->flags&PATH_SKIP))
98710898Sroland.mainz@nrubsig.org pp = pp->next;
9884887Schin if(pp || slash) do
9894887Schin {
9904887Schin sh_sigcheck();
9914887Schin if(libpath=pp)
9924887Schin {
9934887Schin pp = path_nextcomp(pp,arg0,0);
9944887Schin opath = stakfreeze(1)+PATH_OFFSET;
9954887Schin }
9964887Schin else
9974887Schin opath = arg0;
9984887Schin path_spawn(opath,argv,envp,libpath,0);
9994887Schin while(pp && (pp->flags&PATH_FPATH))
10004887Schin pp = path_nextcomp(pp,arg0,0);
10014887Schin }
10024887Schin while(pp);
10034887Schin /* force an exit */
10044887Schin ((struct checkpt*)shp->jmplist)->mode = SH_JMPEXIT;
10054887Schin if((errno=shp->path_err)==ENOENT)
10064887Schin errormsg(SH_DICT,ERROR_exit(ERROR_NOENT),e_found,arg0);
10074887Schin else
10084887Schin errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,arg0);
10094887Schin }
10104887Schin
path_spawn(const char * opath,register char ** argv,char ** envp,Pathcomp_t * libpath,int spawn)10114887Schin pid_t path_spawn(const char *opath,register char **argv, char **envp, Pathcomp_t *libpath, int spawn)
10124887Schin {
10134887Schin Shell_t *shp = sh_getinterp();
10144887Schin register char *path;
10154887Schin char **xp=0, *xval, *libenv = (libpath?libpath->lib:0);
10164887Schin Namval_t* np;
10174887Schin char *s, *v;
101810898Sroland.mainz@nrubsig.org int r, n, pidsize;
10194887Schin pid_t pid= -1;
10204887Schin /* leave room for inserting _= pathname in environment */
10214887Schin envp--;
10224887Schin #if _lib_readlink
10234887Schin /* save original pathname */
10244887Schin stakseek(PATH_OFFSET);
102510898Sroland.mainz@nrubsig.org pidsize = sfprintf(stkstd,"*%d*",spawn?getpid():getppid());
10264887Schin stakputs(opath);
102710898Sroland.mainz@nrubsig.org opath = stakfreeze(1)+PATH_OFFSET+pidsize;
10284887Schin np=nv_search(argv[0],shp->track_tree,0);
10294887Schin while(libpath && !libpath->lib)
10304887Schin libpath=libpath->next;
10314887Schin if(libpath && (!np || nv_size(np)>0))
10324887Schin {
10334887Schin /* check for symlink and use symlink name */
10344887Schin char buff[PATH_MAX+1];
10354887Schin char save[PATH_MAX+1];
10364887Schin stakseek(PATH_OFFSET);
10374887Schin stakputs(opath);
10384887Schin path = stakptr(PATH_OFFSET);
10394887Schin while((n=readlink(path,buff,PATH_MAX))>0)
10404887Schin {
10414887Schin buff[n] = 0;
10424887Schin n = PATH_OFFSET;
10434887Schin r = 0;
10444887Schin if((v=strrchr(path,'/')) && *buff!='/')
10454887Schin {
10464887Schin if(buff[0]=='.' && buff[1]=='.' && (r = strlen(path) + 1) <= PATH_MAX)
10474887Schin memcpy(save, path, r);
10484887Schin else
10494887Schin r = 0;
10504887Schin n += (v+1-path);
10514887Schin }
10524887Schin stakseek(n);
10534887Schin stakputs(buff);
10544887Schin stakputc(0);
10554887Schin path = stakptr(PATH_OFFSET);
10564887Schin if(v && buff[0]=='.' && buff[1]=='.')
10574887Schin {
10584887Schin pathcanon(path, 0);
10594887Schin if(r && access(path,X_OK))
10604887Schin {
10614887Schin memcpy(path, save, r);
10624887Schin break;
10634887Schin }
10644887Schin }
10654887Schin if(libenv = path_lib(libpath,path))
10664887Schin break;
10674887Schin }
10684887Schin stakseek(0);
10694887Schin }
10704887Schin #endif
10714887Schin if(libenv && (v = strchr(libenv,'=')))
10724887Schin {
10734887Schin n = v - libenv;
10744887Schin *v = 0;
10754887Schin np = nv_open(libenv,shp->var_tree,0);
10764887Schin *v = '=';
10774887Schin s = nv_getval(np);
10784887Schin stakputs(libenv);
10794887Schin if(s)
10804887Schin {
10814887Schin stakputc(':');
10824887Schin stakputs(s);
10834887Schin }
10844887Schin v = stakfreeze(1);
10854887Schin r = 1;
10868462SApril.Chin@Sun.COM xp = envp + 1;
10874887Schin while (s = *xp++)
10884887Schin {
10894887Schin if (strneq(s, v, n) && s[n] == '=')
10904887Schin {
10914887Schin xval = *--xp;
10924887Schin *xp = v;
10934887Schin r = 0;
10944887Schin break;
10954887Schin }
10964887Schin }
10974887Schin if (r)
10984887Schin {
10994887Schin *envp-- = v;
11004887Schin xp = 0;
11014887Schin }
11024887Schin }
11034887Schin if(!opath)
11044887Schin opath = stakptr(PATH_OFFSET);
110510898Sroland.mainz@nrubsig.org envp[0] = (char*)opath-(PATH_OFFSET+pidsize);
11064887Schin envp[0][0] = '_';
11074887Schin envp[0][1] = '=';
11084887Schin sfsync(sfstderr);
11094887Schin sh_sigcheck();
11104887Schin path = path_relative(opath);
11114887Schin #ifdef SHELLMAGIC
11124887Schin if(*path!='/' && path!=opath)
11134887Schin {
11144887Schin /*
11154887Schin * The following code because execv(foo,) and execv(./foo,)
11164887Schin * may not yield the same results
11174887Schin */
11184887Schin char *sp = (char*)malloc(strlen(path)+3);
11194887Schin sp[0] = '.';
11204887Schin sp[1] = '/';
11214887Schin strcpy(sp+2,path);
11224887Schin path = sp;
11234887Schin }
11244887Schin #endif /* SHELLMAGIC */
11254887Schin if(spawn && !sh_isoption(SH_PFSH))
11264887Schin pid = _spawnveg(opath, &argv[0],envp, spawn>>1);
11274887Schin else
11288462SApril.Chin@Sun.COM pid = path_pfexecve(opath, &argv[0] ,envp,spawn);
11294887Schin if(xp)
11304887Schin *xp = xval;
11314887Schin #ifdef SHELLMAGIC
11324887Schin if(*path=='.' && path!=opath)
11334887Schin {
11344887Schin free(path);
11354887Schin path = path_relative(opath);
11364887Schin }
11374887Schin #endif /* SHELLMAGIC */
11384887Schin if(pid>0)
11394887Schin return(pid);
11404887Schin retry:
11414887Schin switch(sh.path_err = errno)
11424887Schin {
11434887Schin #ifdef apollo
11444887Schin /*
11454887Schin * On apollo's execve will fail with eacces when
11464887Schin * file has execute but not read permissions. So,
11474887Schin * for now we will pretend that EACCES and ENOEXEC
11484887Schin * mean the same thing.
11494887Schin */
11504887Schin case EACCES:
11514887Schin #endif /* apollo */
11524887Schin case ENOEXEC:
11534887Schin #if SHOPT_SUID_EXEC
11544887Schin case EPERM:
11554887Schin /* some systems return EPERM if setuid bit is on */
11564887Schin #endif
11574887Schin errno = ENOEXEC;
11584887Schin if(spawn)
11594887Schin {
11604887Schin #ifdef _lib_fork
11614887Schin if(sh.subshell)
11624887Schin return(-1);
11634887Schin do
11644887Schin {
11654887Schin if((pid=fork())>0)
11664887Schin return(pid);
11674887Schin }
11684887Schin while(_sh_fork(pid,0,(int*)0) < 0);
11698462SApril.Chin@Sun.COM ((struct checkpt*)shp->jmplist)->mode = SH_JMPEXIT;
11704887Schin #else
11714887Schin return(-1);
11724887Schin #endif
11734887Schin }
11744887Schin exscript(shp,path,argv,envp);
11754887Schin #ifndef apollo
11764887Schin case EACCES:
11774887Schin {
11784887Schin struct stat statb;
11794887Schin if(stat(path,&statb)>=0)
11804887Schin {
11814887Schin if(S_ISDIR(statb.st_mode))
11824887Schin errno = EISDIR;
11834887Schin #ifdef S_ISSOCK
11844887Schin if(S_ISSOCK(statb.st_mode))
11854887Schin exscript(shp,path,argv,envp);
11864887Schin #endif
11874887Schin }
11884887Schin }
11894887Schin /* FALL THROUGH */
11904887Schin #endif /* !apollo */
11914887Schin #ifdef ENAMETOOLONG
11924887Schin case ENAMETOOLONG:
11934887Schin #endif /* ENAMETOOLONG */
11944887Schin #if !SHOPT_SUID_EXEC
11954887Schin case EPERM:
11964887Schin #endif
11974887Schin shp->path_err = errno;
11984887Schin return(-1);
11994887Schin case ENOTDIR:
12004887Schin case ENOENT:
12014887Schin case EINTR:
12024887Schin #ifdef EMLINK
12034887Schin case EMLINK:
12044887Schin #endif /* EMLINK */
12054887Schin return(-1);
12064887Schin case E2BIG:
12074887Schin if(sh.xargmin)
12084887Schin {
12094887Schin pid = path_xargs(opath, &argv[0] ,envp,spawn);
12104887Schin if(pid<0)
12114887Schin goto retry;
12124887Schin return(pid);
12134887Schin }
12144887Schin default:
12154887Schin errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path);
12164887Schin }
12174887Schin return 0;
12184887Schin }
12194887Schin
12204887Schin /*
12214887Schin * File is executable but not machine code.
12224887Schin * Assume file is a Shell script and execute it.
12234887Schin */
12244887Schin
exscript(Shell_t * shp,register char * path,register char * argv[],char ** envp)12254887Schin static void exscript(Shell_t *shp,register char *path,register char *argv[],char **envp)
12264887Schin {
12274887Schin register Sfio_t *sp;
12284887Schin path = path_relative(path);
12294887Schin shp->comdiv=0;
12304887Schin shp->bckpid = 0;
12314887Schin shp->st.ioset=0;
12324887Schin /* clean up any cooperating processes */
12334887Schin if(shp->cpipe[0]>0)
12344887Schin sh_pclose(shp->cpipe);
12354887Schin if(shp->cpid && shp->outpipe)
12364887Schin sh_close(*shp->outpipe);
12374887Schin shp->cpid = 0;
12384887Schin if(sp=fcfile())
12394887Schin while(sfstack(sp,SF_POPSTACK));
12404887Schin job_clear();
12414887Schin if(shp->infd>0 && (shp->fdstatus[shp->infd]&IOCLEX))
12424887Schin sh_close(shp->infd);
12434887Schin sh_setstate(sh_state(SH_FORKED));
12444887Schin sfsync(sfstderr);
12454887Schin #if SHOPT_SUID_EXEC && !SHOPT_PFSH
12464887Schin /* check if file cannot open for read or script is setuid/setgid */
12474887Schin {
12484887Schin static char name[] = "/tmp/euidXXXXXXXXXX";
12494887Schin register int n;
12504887Schin register uid_t euserid;
12514887Schin char *savet=0;
12524887Schin struct stat statb;
12534887Schin if((n=sh_open(path,O_RDONLY,0)) >= 0)
12544887Schin {
12554887Schin /* move <n> if n=0,1,2 */
12564887Schin n = sh_iomovefd(n);
12574887Schin if(fstat(n,&statb)>=0 && !(statb.st_mode&(S_ISUID|S_ISGID)))
12584887Schin goto openok;
12594887Schin sh_close(n);
12604887Schin }
12614887Schin if((euserid=geteuid()) != shp->userid)
12624887Schin {
12634887Schin strncpy(name+9,fmtbase((long)getpid(),10,0),sizeof(name)-10);
12644887Schin /* create a suid open file with owner equal effective uid */
12654887Schin if((n=open(name,O_CREAT|O_TRUNC|O_WRONLY,S_ISUID|S_IXUSR)) < 0)
12664887Schin goto fail;
12674887Schin unlink(name);
12684887Schin /* make sure that file has right owner */
12694887Schin if(fstat(n,&statb)<0 || statb.st_uid != euserid)
12704887Schin goto fail;
12714887Schin if(n!=10)
12724887Schin {
12734887Schin sh_close(10);
12744887Schin fcntl(n, F_DUPFD, 10);
12754887Schin sh_close(n);
12764887Schin n=10;
12774887Schin }
12784887Schin }
12794887Schin savet = *--argv;
12804887Schin *argv = path;
12818462SApril.Chin@Sun.COM path_pfexecve(e_suidexec,argv,envp,0);
12824887Schin fail:
12834887Schin /*
12844887Schin * The following code is just for compatibility
12854887Schin */
12864887Schin if((n=open(path,O_RDONLY,0)) < 0)
12878462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path);
12884887Schin if(savet)
12894887Schin *argv++ = savet;
12904887Schin openok:
12914887Schin shp->infd = n;
12924887Schin }
12934887Schin #else
12948462SApril.Chin@Sun.COM if((shp->infd = sh_open(path,O_RDONLY,0)) < 0)
12958462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path);
12964887Schin #endif
12974887Schin shp->infd = sh_iomovefd(shp->infd);
12984887Schin #if SHOPT_ACCT
12994887Schin sh_accbegin(path) ; /* reset accounting */
13004887Schin #endif /* SHOPT_ACCT */
13014887Schin shp->arglist = sh_argcreate(argv);
13024887Schin shp->lastarg = strdup(path);
13034887Schin /* save name of calling command */
13044887Schin shp->readscript = error_info.id;
13054887Schin /* close history file if name has changed */
13064887Schin if(shp->hist_ptr && (path=nv_getval(HISTFILE)) && strcmp(path,shp->hist_ptr->histname))
13074887Schin {
13084887Schin hist_close(shp->hist_ptr);
13094887Schin (HISTCUR)->nvalue.lp = 0;
13104887Schin }
13114887Schin sh_offstate(SH_FORKED);
131210898Sroland.mainz@nrubsig.org if(shp->sigflag[SIGCHLD]==SH_SIGOFF)
131310898Sroland.mainz@nrubsig.org shp->sigflag[SIGCHLD] = SH_SIGFAULT;
13144887Schin siglongjmp(*shp->jmplist,SH_JMPSCRIPT);
13154887Schin }
13164887Schin
13174887Schin #if SHOPT_ACCT
13184887Schin # include <sys/acct.h>
13194887Schin # include "FEATURE/time"
13204887Schin
13214887Schin static struct acct sabuf;
13224887Schin static struct tms buffer;
13234887Schin static clock_t before;
13244887Schin static char *SHACCT; /* set to value of SHACCT environment variable */
13254887Schin static shaccton; /* non-zero causes accounting record to be written */
13264887Schin static int compress(time_t);
13274887Schin /*
13284887Schin * initialize accounting, i.e., see if SHACCT variable set
13294887Schin */
sh_accinit(void)13304887Schin void sh_accinit(void)
13314887Schin {
13324887Schin SHACCT = getenv("SHACCT");
13334887Schin }
13344887Schin /*
13358462SApril.Chin@Sun.COM * suspend accounting until turned on by sh_accbegin()
13364887Schin */
sh_accsusp(void)13374887Schin void sh_accsusp(void)
13384887Schin {
13394887Schin shaccton=0;
13404887Schin #ifdef AEXPAND
13414887Schin sabuf.ac_flag |= AEXPND;
13424887Schin #endif /* AEXPAND */
13434887Schin }
13444887Schin
13454887Schin /*
13464887Schin * begin an accounting record by recording start time
13474887Schin */
sh_accbegin(const char * cmdname)13484887Schin void sh_accbegin(const char *cmdname)
13494887Schin {
13504887Schin if(SHACCT)
13514887Schin {
13524887Schin sabuf.ac_btime = time(NIL(time_t *));
13534887Schin before = times(&buffer);
13544887Schin sabuf.ac_uid = getuid();
13554887Schin sabuf.ac_gid = getgid();
13564887Schin strncpy(sabuf.ac_comm, (char*)path_basename(cmdname),
13574887Schin sizeof(sabuf.ac_comm));
13584887Schin shaccton = 1;
13594887Schin }
13604887Schin }
13614887Schin /*
13624887Schin * terminate an accounting record and append to accounting file
13634887Schin */
sh_accend(void)13644887Schin void sh_accend(void)
13654887Schin {
13664887Schin int fd;
13674887Schin clock_t after;
13684887Schin
13694887Schin if(shaccton)
13704887Schin {
13714887Schin after = times(&buffer);
13724887Schin sabuf.ac_utime = compress(buffer.tms_utime + buffer.tms_cutime);
13734887Schin sabuf.ac_stime = compress(buffer.tms_stime + buffer.tms_cstime);
13744887Schin sabuf.ac_etime = compress( (time_t)(after-before));
13754887Schin fd = open( SHACCT , O_WRONLY | O_APPEND | O_CREAT,RW_ALL);
13764887Schin write(fd, (const char*)&sabuf, sizeof( sabuf ));
13774887Schin close( fd);
13784887Schin }
13794887Schin }
13804887Schin
13814887Schin /*
13824887Schin * Produce a pseudo-floating point representation
13834887Schin * with 3 bits base-8 exponent, 13 bits fraction.
13844887Schin */
compress(register time_t t)13854887Schin static int compress(register time_t t)
13864887Schin {
13874887Schin register int exp = 0, rund = 0;
13884887Schin
13894887Schin while (t >= 8192)
13904887Schin {
13914887Schin exp++;
13924887Schin rund = t&04;
13934887Schin t >>= 3;
13944887Schin }
13954887Schin if (rund)
13964887Schin {
13974887Schin t++;
13984887Schin if (t >= 8192)
13994887Schin {
14004887Schin t >>= 3;
14014887Schin exp++;
14024887Schin }
14034887Schin }
14044887Schin return((exp<<13) + t);
14054887Schin }
14064887Schin #endif /* SHOPT_ACCT */
14074887Schin
14084887Schin
14094887Schin
14104887Schin /*
14114887Schin * add a pathcomponent to the path search list and eliminate duplicates
14124887Schin * and non-existing absolute paths.
14134887Schin */
path_addcomp(Pathcomp_t * first,Pathcomp_t * old,const char * name,int flag)14144887Schin static Pathcomp_t *path_addcomp(Pathcomp_t *first, Pathcomp_t *old,const char *name, int flag)
14154887Schin {
14164887Schin register Pathcomp_t *pp, *oldpp;
14174887Schin int len, offset=staktell();
14184887Schin if(!(flag&PATH_BFPATH))
14194887Schin {
14204887Schin register const char *cp = name;
14214887Schin while(*cp && *cp!=':')
14224887Schin stakputc(*cp++);
14234887Schin len = staktell()-offset;
14244887Schin stakputc(0);
14254887Schin stakseek(offset);
14264887Schin name = (const char*)stakptr(offset);
14274887Schin }
14284887Schin else
14294887Schin len = strlen(name);
14304887Schin for(pp=first; pp; pp=pp->next)
14314887Schin {
14324887Schin if(memcmp(name,pp->name,len)==0 && (pp->name[len]==':' || pp->name[len]==0))
14334887Schin {
14344887Schin pp->flags |= flag;
14354887Schin return(first);
14364887Schin }
14374887Schin }
143810898Sroland.mainz@nrubsig.org for(pp=first, oldpp=0; pp; oldpp=pp, pp=pp->next);
14394887Schin pp = newof((Pathcomp_t*)0,Pathcomp_t,1,len+1);
14404887Schin pp->refcount = 1;
14414887Schin memcpy((char*)(pp+1),name,len+1);
14424887Schin pp->name = (char*)(pp+1);
14434887Schin pp->len = len;
14444887Schin if(oldpp)
14454887Schin oldpp->next = pp;
14464887Schin else
14474887Schin first = pp;
14484887Schin pp->flags = flag;
144910898Sroland.mainz@nrubsig.org if(strcmp(name,SH_CMDLIB_DIR)==0)
14504887Schin {
145110898Sroland.mainz@nrubsig.org pp->dev = 1;
14524887Schin pp->flags |= PATH_BUILTIN_LIB;
14534887Schin pp->blib = malloc(4);
14544887Schin strcpy(pp->blib,LIBCMD);
14554887Schin return(first);
14564887Schin }
145710898Sroland.mainz@nrubsig.org if(old && ((flag&(PATH_PATH|PATH_SKIP))==PATH_PATH))
14584887Schin path_chkpaths(first,old,pp,offset);
14594887Schin return(first);
14604887Schin }
14614887Schin
14624887Schin /*
14634887Schin * This function checks for the .paths file in directory in <pp>
14644887Schin * it assumes that the directory is on the stack at <offset>
14654887Schin */
path_chkpaths(Pathcomp_t * first,Pathcomp_t * old,Pathcomp_t * pp,int offset)14664887Schin static int path_chkpaths(Pathcomp_t *first, Pathcomp_t* old,Pathcomp_t *pp, int offset)
14674887Schin {
14684887Schin struct stat statb;
14694887Schin int k,m,n,fd;
14704887Schin char *sp,*cp,*ep;
14714887Schin stakseek(offset+pp->len);
14724887Schin if(pp->len==1 && *stakptr(offset)=='/')
14734887Schin stakseek(offset);
14744887Schin stakputs("/.paths");
14754887Schin if((fd=open(stakptr(offset),O_RDONLY))>=0)
14764887Schin {
14774887Schin fstat(fd,&statb);
14784887Schin n = statb.st_size;
14794887Schin stakseek(offset+pp->len+n+2);
14804887Schin sp = stakptr(offset+pp->len);
14814887Schin *sp++ = '/';
14824887Schin n=read(fd,cp=sp,n);
14834887Schin sp[n] = 0;
14844887Schin close(fd);
14854887Schin for(ep=0; n--; cp++)
14864887Schin {
14874887Schin if(*cp=='=')
14884887Schin {
14894887Schin ep = cp+1;
14904887Schin continue;
14914887Schin }
14924887Schin else if(*cp!='\r' && *cp!='\n')
14934887Schin continue;
14944887Schin if(*sp=='#' || sp==cp)
14954887Schin {
14964887Schin sp = cp+1;
14974887Schin continue;
14984887Schin }
14994887Schin *cp = 0;
15004887Schin m = ep ? (ep-sp) : 0;
1501*12068SRoger.Faulkner@Oracle.COM if(m==0 || m==6 && memcmp((void*)sp,(void*)"FPATH=",6)==0)
15024887Schin {
15034887Schin if(first)
15044887Schin {
15054887Schin char *ptr = stakptr(offset+pp->len+1);
15064887Schin if(ep)
15074887Schin strcpy(ptr,ep);
15084887Schin path_addcomp(first,old,stakptr(offset),PATH_FPATH|PATH_BFPATH);
15094887Schin }
15104887Schin }
15114887Schin else if(m==12 && memcmp((void*)sp,(void*)"BUILTIN_LIB=",12)==0)
15124887Schin {
1513*12068SRoger.Faulkner@Oracle.COM if(!(pp->flags & PATH_BUILTIN_LIB) || strchr(ep,'-'))
15144887Schin {
1515*12068SRoger.Faulkner@Oracle.COM if ((pp->flags & (PATH_BUILTIN_LIB|PATH_STD_DIR)) == PATH_BUILTIN_LIB)
1516*12068SRoger.Faulkner@Oracle.COM {
1517*12068SRoger.Faulkner@Oracle.COM free(pp->blib);
1518*12068SRoger.Faulkner@Oracle.COM pp->blib = 0;
1519*12068SRoger.Faulkner@Oracle.COM }
15204887Schin pp->flags |= PATH_BUILTIN_LIB;
15214887Schin if (*ep == '.' && !*(ep + 1))
15224887Schin pp->flags |= PATH_STD_DIR;
15234887Schin else
15244887Schin {
15254887Schin k = strlen(ep)+1;
15264887Schin if (*ep != '/')
15274887Schin k += pp->len+1;
15284887Schin pp->blib = sp = malloc(k);
15294887Schin if (*ep != '/')
15304887Schin {
15314887Schin strcpy(pp->blib,pp->name);
15324887Schin sp += pp->len;
15334887Schin *sp++ = '/';
15344887Schin }
15354887Schin strcpy(sp,ep);
15364887Schin }
15374887Schin }
15384887Schin }
15394887Schin else if(m)
15404887Schin {
15414887Schin pp->lib = (char*)malloc(cp-sp+pp->len+2);
15424887Schin memcpy((void*)pp->lib,(void*)sp,m);
15434887Schin memcpy((void*)&pp->lib[m],stakptr(offset),pp->len);
15444887Schin pp->lib[k=m+pp->len] = '/';
15454887Schin strcpy((void*)&pp->lib[k+1],ep);
15464887Schin pathcanon(&pp->lib[m],0);
15474887Schin if(!first)
15484887Schin {
15494887Schin stakseek(0);
15504887Schin stakputs(pp->lib);
15514887Schin free((void*)pp->lib);
15524887Schin return(1);
15534887Schin }
15544887Schin }
15554887Schin sp = cp+1;
15564887Schin ep = 0;
15574887Schin }
15584887Schin }
15594887Schin return(0);
15604887Schin }
15614887Schin
15624887Schin
path_addpath(Pathcomp_t * first,register const char * path,int type)15634887Schin Pathcomp_t *path_addpath(Pathcomp_t *first, register const char *path,int type)
15644887Schin {
15654887Schin register const char *cp;
15664887Schin Pathcomp_t *old=0;
15674887Schin int offset = staktell();
15684887Schin char *savptr;
15694887Schin
15704887Schin if(!path && type!=PATH_PATH)
15714887Schin return(first);
15724887Schin if(type!=PATH_FPATH)
15734887Schin {
15744887Schin old = first;
15754887Schin first = 0;
15764887Schin }
15774887Schin if(offset)
15784887Schin savptr = stakfreeze(0);
15794887Schin if(path) while(*(cp=path))
15804887Schin {
15814887Schin if(*cp==':')
15824887Schin {
15834887Schin if(type!=PATH_FPATH)
15844887Schin first = path_addcomp(first,old,".",type);
15854887Schin while(*++path == ':');
15864887Schin }
15874887Schin else
15884887Schin {
15894887Schin int c;
15904887Schin while(*path && *path!=':')
15914887Schin path++;
15924887Schin c = *path++;
15934887Schin first = path_addcomp(first,old,cp,type);
15944887Schin if(c==0)
15954887Schin break;
15964887Schin if(*path==0)
15974887Schin path--;
15984887Schin }
15994887Schin }
16004887Schin if(old)
16014887Schin {
16024887Schin if(!first && !path)
16034887Schin {
16044887Schin Pathcomp_t *pp = (Pathcomp_t*)old->shp->defpathlist;
16054887Schin if(!pp)
16064887Schin pp = defpath_init(old->shp);
16074887Schin first = path_dup(pp);
16084887Schin }
16094887Schin if(cp=(FPATHNOD)->nvalue.cp)
16104887Schin first = (void*)path_addpath((Pathcomp_t*)first,cp,PATH_FPATH);
16114887Schin path_delete(old);
16124887Schin }
16134887Schin if(offset)
16144887Schin stakset(savptr,offset);
16154887Schin else
16164887Schin stakseek(0);
16174887Schin return(first);
16184887Schin }
16194887Schin
16204887Schin /*
16214887Schin * duplicate the path give by <first> by incremented reference counts
16224887Schin */
path_dup(Pathcomp_t * first)16234887Schin Pathcomp_t *path_dup(Pathcomp_t *first)
16244887Schin {
16254887Schin register Pathcomp_t *pp=first;
16264887Schin while(pp)
16274887Schin {
16284887Schin pp->refcount++;
16294887Schin pp = pp->next;
16304887Schin }
16314887Schin return(first);
16324887Schin }
16334887Schin
16344887Schin /*
16354887Schin * called whenever the directory is changed
16364887Schin */
path_newdir(Pathcomp_t * first)16374887Schin void path_newdir(Pathcomp_t *first)
16384887Schin {
16394887Schin register Pathcomp_t *pp=first, *next, *pq;
16404887Schin struct stat statb;
16414887Schin for(pp=first; pp; pp=pp->next)
16424887Schin {
16434887Schin pp->flags &= ~PATH_SKIP;
16444887Schin if(*pp->name=='/')
16454887Schin continue;
16464887Schin /* delete .paths component */
16474887Schin if((next=pp->next) && (next->flags&PATH_BFPATH))
16484887Schin {
16494887Schin pp->next = next->next;
16504887Schin if(--next->refcount<=0)
16514887Schin free((void*)next);
16524887Schin }
16534887Schin if(stat(pp->name,&statb)<0 || !S_ISDIR(statb.st_mode))
16544887Schin {
16554887Schin pp->dev = 0;
16564887Schin pp->ino = 0;
16574887Schin continue;
16584887Schin }
16594887Schin pp->dev = statb.st_dev;
16604887Schin pp->ino = statb.st_ino;
16618462SApril.Chin@Sun.COM pp->mtime = statb.st_mtime;
16624887Schin for(pq=first;pq!=pp;pq=pq->next)
16634887Schin {
16644887Schin if(pp->ino==pq->ino && pp->dev==pq->dev)
16654887Schin pp->flags |= PATH_SKIP;
16664887Schin }
16674887Schin for(pq=pp;pq=pq->next;)
16684887Schin {
16694887Schin if(pp->ino==pq->ino && pp->dev==pq->dev)
16704887Schin pq->flags |= PATH_SKIP;
16714887Schin }
16724887Schin if((pp->flags&(PATH_PATH|PATH_SKIP))==PATH_PATH)
16734887Schin {
16744887Schin /* try to insert .paths component */
16754887Schin int offset = staktell();
16764887Schin stakputs(pp->name);
16774887Schin stakseek(offset);
16784887Schin next = pp->next;
16794887Schin pp->next = 0;
16804887Schin path_chkpaths(first,(Pathcomp_t*)0,pp,offset);
16814887Schin if(pp->next)
16824887Schin pp = pp->next;
16834887Schin pp->next = next;
16844887Schin }
16854887Schin }
16864887Schin #if 0
16874887Schin path_dump(first);
16884887Schin #endif
16894887Schin }
16904887Schin
path_unsetfpath(Pathcomp_t * first)16914887Schin Pathcomp_t *path_unsetfpath(Pathcomp_t *first)
16924887Schin {
16934887Schin register Pathcomp_t *pp=first, *old=0;
16948462SApril.Chin@Sun.COM Shell_t *shp = &sh;
16958462SApril.Chin@Sun.COM if(shp->fpathdict)
16968462SApril.Chin@Sun.COM {
16978462SApril.Chin@Sun.COM struct Ufunction *rp, *rpnext;
16988462SApril.Chin@Sun.COM for(rp=(struct Ufunction*)dtfirst(shp->fpathdict);rp;rp=rpnext)
16998462SApril.Chin@Sun.COM {
17008462SApril.Chin@Sun.COM rpnext = (struct Ufunction*)dtnext(shp->fpathdict,rp);
17018462SApril.Chin@Sun.COM if(rp->fdict)
17028462SApril.Chin@Sun.COM nv_delete(rp->np,rp->fdict,NV_NOFREE);
17038462SApril.Chin@Sun.COM rp->fdict = 0;
17048462SApril.Chin@Sun.COM }
17058462SApril.Chin@Sun.COM }
17064887Schin while(pp)
17074887Schin {
17084887Schin if((pp->flags&PATH_FPATH) && !(pp->flags&PATH_BFPATH))
17094887Schin {
17104887Schin if(pp->flags&PATH_PATH)
17114887Schin pp->flags &= ~PATH_FPATH;
17124887Schin else
17134887Schin {
17144887Schin Pathcomp_t *ppsave=pp;
17154887Schin if(old)
17164887Schin old->next = pp->next;
17174887Schin else
17184887Schin first = pp->next;
17194887Schin pp = pp->next;
17204887Schin if(--ppsave->refcount<=0)
17214887Schin {
17224887Schin if(ppsave->lib)
17234887Schin free((void*)ppsave->lib);
17244887Schin free((void*)ppsave);
17254887Schin }
17264887Schin continue;
17274887Schin }
17284887Schin
17294887Schin }
17304887Schin old = pp;
17314887Schin pp = pp->next;
17324887Schin }
17334887Schin return(first);
17344887Schin }
17354887Schin
path_dirfind(Pathcomp_t * first,const char * name,int c)17364887Schin Pathcomp_t *path_dirfind(Pathcomp_t *first,const char *name,int c)
17374887Schin {
17384887Schin register Pathcomp_t *pp=first;
17394887Schin while(pp)
17404887Schin {
17414887Schin if(memcmp(name,pp->name,pp->len)==0 && name[pp->len]==c)
17424887Schin return(pp);
17434887Schin pp = pp->next;
17444887Schin }
17454887Schin return(0);
17464887Schin }
17474887Schin
17484887Schin /*
17494887Schin * get discipline for tracked alias
17504887Schin */
talias_get(Namval_t * np,Namfun_t * nvp)17514887Schin static char *talias_get(Namval_t *np, Namfun_t *nvp)
17524887Schin {
17534887Schin Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp;
17544887Schin char *ptr;
17554887Schin if(!pp)
17564887Schin return(NULL);
17574887Schin path_nextcomp(pp,nv_name(np),pp);
17584887Schin ptr = stakfreeze(0);
17594887Schin return(ptr+PATH_OFFSET);
17604887Schin }
17614887Schin
talias_put(register Namval_t * np,const char * val,int flags,Namfun_t * fp)17624887Schin static void talias_put(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
17634887Schin {
17644887Schin if(!val && np->nvalue.cp)
17654887Schin {
17664887Schin Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp;
17674887Schin if(--pp->refcount<=0)
17684887Schin free((void*)pp);
17694887Schin }
17704887Schin nv_putv(np,val,flags,fp);
17714887Schin }
17724887Schin
17734887Schin static const Namdisc_t talias_disc = { 0, talias_put, talias_get };
17744887Schin static Namfun_t talias_init = { &talias_disc, 1 };
17754887Schin
17764887Schin /*
17774887Schin * set tracked alias node <np> to value <pp>
17784887Schin */
path_alias(register Namval_t * np,register Pathcomp_t * pp)17794887Schin void path_alias(register Namval_t *np,register Pathcomp_t *pp)
17804887Schin {
17814887Schin if(pp)
17824887Schin {
17834887Schin struct stat statb;
17844887Schin char *sp;
17854887Schin nv_offattr(np,NV_NOPRINT);
17864887Schin nv_stack(np,&talias_init);
17874887Schin np->nvalue.cp = (char*)pp;
17884887Schin pp->refcount++;
17894887Schin nv_setattr(np,NV_TAGGED|NV_NOFREE);
17904887Schin path_nextcomp(pp,nv_name(np),pp);
17914887Schin sp = stakptr(PATH_OFFSET);
17924887Schin if(sp && lstat(sp,&statb)>=0 && S_ISLNK(statb.st_mode))
17934887Schin nv_setsize(np,statb.st_size+1);
17944887Schin else
17954887Schin nv_setsize(np,0);
17964887Schin }
17974887Schin else
17984887Schin nv_unset(np);
17994887Schin }
18004887Schin
1801