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 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 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 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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 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 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 */ 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 */ 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 */ 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 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 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 */ 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 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 */ 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 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 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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 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 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 */ 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 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 */ 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