14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*10898Sroland.mainz@nrubsig.org * Copyright (c) 1982-2009 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 # else 434887Schin # undef SHOPT_PFSH 444887Schin # endif 458462SApril.Chin@Sun.COM # if _lib_vfork 468462SApril.Chin@Sun.COM # include <ast_vfork.h> 478462SApril.Chin@Sun.COM # else 488462SApril.Chin@Sun.COM # define vfork() fork() 498462SApril.Chin@Sun.COM # endif 504887Schin #endif 514887Schin 524887Schin #define RW_ALL (S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH) 534887Schin #define LIBCMD "cmd" 544887Schin 554887Schin 564887Schin static int canexecute(char*,int); 574887Schin static void funload(Shell_t*,int,const char*); 584887Schin static void exscript(Shell_t*,char*, char*[], char**); 594887Schin static int path_chkpaths(Pathcomp_t*,Pathcomp_t*,Pathcomp_t*,int); 60*10898Sroland.mainz@nrubsig.org static void path_checkdup(register Pathcomp_t*); 614887Schin 624887Schin static const char *std_path; 634887Schin 644887Schin static int onstdpath(const char *name) 654887Schin { 664887Schin register const char *cp = std_path, *sp; 674887Schin if(cp) 684887Schin while(*cp) 694887Schin { 704887Schin for(sp=name; *sp && (*cp == *sp); sp++,cp++); 714887Schin if(*sp==0 && (*cp==0 || *cp==':')) 724887Schin return(1); 734887Schin while(*cp && *cp++!=':'); 744887Schin } 754887Schin return(0); 764887Schin } 774887Schin 788462SApril.Chin@Sun.COM static pid_t path_pfexecve(const char *path, char *argv[],char *const envp[],int spawn) 794887Schin { 804887Schin #if SHOPT_PFSH 818462SApril.Chin@Sun.COM pid_t pid; 824887Schin char resolvedpath[PATH_MAX + 1]; 838462SApril.Chin@Sun.COM if(spawn) 848462SApril.Chin@Sun.COM { 858462SApril.Chin@Sun.COM while((pid = vfork()) < 0) 868462SApril.Chin@Sun.COM _sh_fork(pid, 0, (int*)0); 878462SApril.Chin@Sun.COM if(pid) 888462SApril.Chin@Sun.COM return(pid); 898462SApril.Chin@Sun.COM } 904887Schin if(!sh_isoption(SH_PFSH)) 914887Schin return(execve(path, argv, envp)); 924887Schin /* Solaris implements realpath(3C) using the resolvepath(2) */ 934887Schin /* system call so we can save us to call access(2) first */ 944887Schin if (!realpath(path, resolvedpath)) 954887Schin return -1; 964887Schin 974887Schin /* we can exec the command directly instead of via pfexec(1) if */ 984887Schin /* there is a matching entry without attributes in exec_attr(4) */ 994887Schin if (sh.user && *sh.user) 1004887Schin { 1014887Schin execattr_t *pf; 1024887Schin if(pf=getexecuser(sh.user, KV_COMMAND, resolvedpath, GET_ONE)) 1034887Schin { 1044887Schin if (!pf->attr || pf->attr->length == 0) 1054887Schin { 1064887Schin int r = execve(path, argv, envp); 1074887Schin free_execattr(pf); 1084887Schin return r; 1094887Schin } 1104887Schin free_execattr(pf); 1114887Schin } 1124887Schin else 1134887Schin { 1144887Schin errno = ENOENT; 1154887Schin return -1; 1164887Schin } 1174887Schin } 1184887Schin --argv; 1194887Schin argv[0] = argv[1]; 1204887Schin argv[1] = resolvedpath; 1214887Schin return(execve("/usr/bin/pfexec", argv, envp)); 1224887Schin #else 1234887Schin return(execve(path, argv, envp)); 1244887Schin #endif 1254887Schin } 1264887Schin 1274887Schin 1288462SApril.Chin@Sun.COM static pid_t _spawnveg(const char *path, char* const argv[], char* const envp[], pid_t pgid) 1294887Schin { 1304887Schin int waitsafe = job.waitsafe; 1318462SApril.Chin@Sun.COM pid_t pid; 1324887Schin job_lock(); 1338462SApril.Chin@Sun.COM while(1) 1348462SApril.Chin@Sun.COM { 1358462SApril.Chin@Sun.COM sh_stats(STAT_SPAWN); 1368462SApril.Chin@Sun.COM pid = spawnveg(path,argv,envp,pgid); 1378462SApril.Chin@Sun.COM if(pid>=0 || errno!=EAGAIN) 1388462SApril.Chin@Sun.COM break; 1398462SApril.Chin@Sun.COM _sh_fork(pid, 0, (int*)0); 1408462SApril.Chin@Sun.COM } 1414887Schin job.waitsafe = waitsafe; 1424887Schin job_unlock(); 1434887Schin return(pid); 1444887Schin } 1454887Schin /* 1464887Schin * used with command -x to run the command in multiple passes 1474887Schin * spawn is non-zero when invoked via spawn 1484887Schin * the exitval is set to the maximum for each execution 1494887Schin */ 1504887Schin static pid_t path_xargs(const char *path, char *argv[],char *const envp[], int spawn) 1514887Schin { 1524887Schin register char *cp, **av, **xv; 1534887Schin char **avlast= &argv[sh.xargmax], **saveargs=0; 1544887Schin char *const *ev; 1554887Schin long size, left; 1564887Schin int nlast=1,n,exitval=0; 1574887Schin pid_t pid; 1584887Schin if(sh.xargmin < 0) 1594887Schin return((pid_t)-1); 1604887Schin size = sh.lim.arg_max-1024; 1614887Schin for(ev=envp; cp= *ev; ev++) 1624887Schin size -= strlen(cp)-1; 1634887Schin for(av=argv; (cp= *av) && av< &argv[sh.xargmin]; av++) 1644887Schin size -= strlen(cp)-1; 1654887Schin for(av=avlast; cp= *av; av++,nlast++) 1664887Schin size -= strlen(cp)-1; 1674887Schin av = &argv[sh.xargmin]; 1684887Schin if(!spawn) 1694887Schin job_clear(); 1704887Schin sh.exitval = 0; 1714887Schin while(av<avlast) 1724887Schin { 1734887Schin for(xv=av,left=size; left>0 && av<avlast;) 1744887Schin left -= strlen(*av++)+1; 1754887Schin /* leave at least two for last */ 1764887Schin if(left<0 && (avlast-av)<2) 1774887Schin av--; 1784887Schin if(xv==&argv[sh.xargmin]) 1794887Schin { 1804887Schin n = nlast*sizeof(char*); 1814887Schin saveargs = (char**)malloc(n); 1824887Schin memcpy((void*)saveargs, (void*)av, n); 1834887Schin memcpy((void*)av,(void*)avlast,n); 1844887Schin } 1854887Schin else 1864887Schin { 1874887Schin for(n=sh.xargmin; xv < av; xv++) 1884887Schin argv[n++] = *xv; 1894887Schin for(xv=avlast; cp= *xv; xv++) 1904887Schin argv[n++] = cp; 1914887Schin argv[n] = 0; 1924887Schin } 1934887Schin if(saveargs || av<avlast || (exitval && !spawn)) 1944887Schin { 1954887Schin if((pid=_spawnveg(path,argv,envp,0)) < 0) 1964887Schin return(-1); 1974887Schin job_post(pid,0); 1984887Schin job_wait(pid); 1994887Schin if(sh.exitval>exitval) 2004887Schin exitval = sh.exitval; 2014887Schin if(saveargs) 2024887Schin { 2034887Schin memcpy((void*)av,saveargs,n); 2044887Schin free((void*)saveargs); 2054887Schin saveargs = 0; 2064887Schin } 2074887Schin } 2084887Schin else if(spawn && !sh_isoption(SH_PFSH)) 2094887Schin { 2104887Schin sh.xargexit = exitval; 2114887Schin return(_spawnveg(path,argv,envp,spawn>>1)); 2124887Schin } 2134887Schin else 2148462SApril.Chin@Sun.COM return(path_pfexecve(path,argv,envp,spawn)); 2154887Schin } 2164887Schin if(!spawn) 2174887Schin exit(exitval); 2184887Schin return((pid_t)-1); 2194887Schin } 2204887Schin 2214887Schin /* 2224887Schin * make sure PWD is set up correctly 2234887Schin * Return the present working directory 2244887Schin * Invokes getcwd() if flag==0 and if necessary 2254887Schin * Sets the PWD variable to this value 2264887Schin */ 2274887Schin char *path_pwd(int flag) 2284887Schin { 2294887Schin register char *cp; 2304887Schin register char *dfault = (char*)e_dot; 2314887Schin register int count = 0; 2324887Schin Shell_t *shp = &sh; 2334887Schin if(shp->pwd) 2344887Schin return((char*)shp->pwd); 2354887Schin while(1) 2364887Schin { 2374887Schin /* try from lowest to highest */ 2384887Schin switch(count++) 2394887Schin { 2404887Schin case 0: 2414887Schin cp = nv_getval(PWDNOD); 2424887Schin break; 2434887Schin case 1: 2444887Schin cp = nv_getval(HOME); 2454887Schin break; 2464887Schin case 2: 2474887Schin cp = "/"; 2484887Schin break; 2494887Schin case 3: 2504887Schin cp = (char*)e_crondir; 2514887Schin if(flag) /* skip next case when non-zero flag */ 2524887Schin ++count; 2534887Schin break; 2544887Schin case 4: 2554887Schin { 2564887Schin if(cp=getcwd(NIL(char*),0)) 2574887Schin { 2584887Schin nv_offattr(PWDNOD,NV_NOFREE); 2594887Schin nv_unset(PWDNOD); 2604887Schin PWDNOD->nvalue.cp = cp; 2614887Schin goto skip; 2624887Schin } 2634887Schin break; 2644887Schin } 2654887Schin case 5: 2664887Schin return(dfault); 2674887Schin } 2684887Schin if(cp && *cp=='/' && test_inode(cp,e_dot)) 2694887Schin break; 2704887Schin } 2714887Schin if(count>1) 2724887Schin { 2734887Schin nv_offattr(PWDNOD,NV_NOFREE); 2744887Schin nv_putval(PWDNOD,cp,NV_RDONLY); 2754887Schin } 2764887Schin skip: 2774887Schin nv_onattr(PWDNOD,NV_NOFREE|NV_EXPORT); 2784887Schin shp->pwd = (char*)(PWDNOD->nvalue.cp); 2794887Schin return(cp); 2804887Schin } 2814887Schin 2824887Schin static void free_bltin(Namval_t *np,void *data) 2834887Schin { 2844887Schin register Pathcomp_t *pp= (Pathcomp_t*)data; 2854887Schin if(pp->flags&PATH_STD_DIR) 2864887Schin { 2874887Schin int offset=staktell();; 2884887Schin if(strcmp(pp->name,"/bin")==0 || memcmp(pp->name,np->nvname,pp->len) || np->nvname[pp->len]!='/') 2894887Schin return; 2904887Schin stakputs("/bin"); 2914887Schin stakputs(np->nvname+pp->len+1); 2924887Schin stakputc(0); 2934887Schin sh_addbuiltin(stakptr(offset),np->nvalue.bfp,NiL); 2944887Schin stakseek(offset); 2954887Schin return; 2964887Schin } 2974887Schin if((void*)np->nvenv==pp->bltin_lib) 2988462SApril.Chin@Sun.COM nv_delete(np,sh_bltin_tree(),NV_NOFREE); 2994887Schin } 3004887Schin 3014887Schin /* 3024887Schin * delete current Pathcomp_t structure 3034887Schin */ 3044887Schin void path_delete(Pathcomp_t *first) 3054887Schin { 3064887Schin register Pathcomp_t *pp=first, *old=0, *ppnext; 3074887Schin while(pp) 3084887Schin { 3094887Schin ppnext = pp->next; 3104887Schin if(--pp->refcount<=0) 3114887Schin { 3124887Schin if(pp->lib) 3134887Schin free((void*)pp->lib); 3144887Schin if(pp->blib) 3154887Schin free((void*)pp->blib); 3164887Schin if(pp->bltin_lib || (pp->flags&PATH_STD_DIR)) 3174887Schin { 3184887Schin nv_scan(sh_bltin_tree(),free_bltin,pp,0,0); 3198462SApril.Chin@Sun.COM #if SHOPT_DYNAMIC 3204887Schin if(pp->bltin_lib) 3214887Schin dlclose(pp->bltin_lib); 3228462SApril.Chin@Sun.COM #endif /* SHOPT_DYNAMIC */ 3234887Schin } 3244887Schin free((void*)pp); 3254887Schin if(old) 3264887Schin old->next = ppnext; 3274887Schin } 3284887Schin else 3294887Schin old = pp; 3304887Schin pp = ppnext; 3314887Schin } 3324887Schin } 3334887Schin 3344887Schin /* 3354887Schin * returns library variable from .paths 3364887Schin * The value might be returned on the stack overwriting path 3374887Schin */ 3384887Schin static char *path_lib(Pathcomp_t *pp, char *path) 3394887Schin { 3404887Schin register char *last = strrchr(path,'/'); 3414887Schin register int r; 3424887Schin struct stat statb; 3434887Schin if(last) 3444887Schin *last = 0; 3454887Schin else 3464887Schin path = "."; 3474887Schin r = stat(path,&statb); 3484887Schin if(last) 3494887Schin *last = '/'; 3504887Schin if(r>=0) 3514887Schin { 3524887Schin Pathcomp_t pcomp; 3534887Schin char save[8]; 3544887Schin for( ;pp; pp=pp->next) 3554887Schin { 356*10898Sroland.mainz@nrubsig.org path_checkdup(pp); 3578462SApril.Chin@Sun.COM if(pp->ino==statb.st_ino && pp->dev==statb.st_dev && pp->mtime==statb.st_mtime) 3584887Schin return(pp->lib); 3594887Schin } 3604887Schin pcomp.len = 0; 3614887Schin if(last) 3624887Schin pcomp.len = last-path; 3634887Schin memcpy((void*)save, (void*)stakptr(PATH_OFFSET+pcomp.len),sizeof(save)); 3644887Schin if(path_chkpaths((Pathcomp_t*)0,(Pathcomp_t*)0,&pcomp,PATH_OFFSET)) 3654887Schin return(stakfreeze(1)); 3664887Schin memcpy((void*)stakptr(PATH_OFFSET+pcomp.len),(void*)save,sizeof(save)); 3674887Schin } 3684887Schin return(0); 3694887Schin } 3704887Schin 3714887Schin #if 0 3724887Schin void path_dump(register Pathcomp_t *pp) 3734887Schin { 3744887Schin sfprintf(sfstderr,"dump\n"); 3754887Schin while(pp) 3764887Schin { 3774887Schin sfprintf(sfstderr,"pp=%x dev=%d ino=%d len=%d flags=%o name=%.*s\n", 3784887Schin pp,pp->dev,pp->ino,pp->len,pp->flags,pp->len,pp->name); 3794887Schin pp = pp->next; 3804887Schin } 3814887Schin } 3824887Schin #endif 3834887Schin 3844887Schin /* 385*10898Sroland.mainz@nrubsig.org * check for duplicate directories on PATH 386*10898Sroland.mainz@nrubsig.org */ 387*10898Sroland.mainz@nrubsig.org static void path_checkdup(register Pathcomp_t *pp) 388*10898Sroland.mainz@nrubsig.org { 389*10898Sroland.mainz@nrubsig.org register char *name = pp->name; 390*10898Sroland.mainz@nrubsig.org register Pathcomp_t *oldpp,*first; 391*10898Sroland.mainz@nrubsig.org register int flag=0; 392*10898Sroland.mainz@nrubsig.org struct stat statb; 393*10898Sroland.mainz@nrubsig.org if(stat(name,&statb)<0 || !S_ISDIR(statb.st_mode)) 394*10898Sroland.mainz@nrubsig.org { 395*10898Sroland.mainz@nrubsig.org pp->flags |= PATH_SKIP; 396*10898Sroland.mainz@nrubsig.org pp->dev = *name=='/'; 397*10898Sroland.mainz@nrubsig.org return; 398*10898Sroland.mainz@nrubsig.org } 399*10898Sroland.mainz@nrubsig.org pp->mtime = statb.st_mtime; 400*10898Sroland.mainz@nrubsig.org pp->ino = statb.st_ino; 401*10898Sroland.mainz@nrubsig.org pp->dev = statb.st_dev; 402*10898Sroland.mainz@nrubsig.org if(*name=='/' && onstdpath(name)) 403*10898Sroland.mainz@nrubsig.org flag = PATH_STD_DIR; 404*10898Sroland.mainz@nrubsig.org first = (pp->flags&PATH_CDPATH)?pp->shp->cdpathlist:path_get(""); 405*10898Sroland.mainz@nrubsig.org for(oldpp=first; oldpp && oldpp!=pp; oldpp=oldpp->next) 406*10898Sroland.mainz@nrubsig.org { 407*10898Sroland.mainz@nrubsig.org if(pp->ino==oldpp->ino && pp->dev==oldpp->dev && pp->mtime==oldpp->mtime) 408*10898Sroland.mainz@nrubsig.org { 409*10898Sroland.mainz@nrubsig.org flag |= PATH_SKIP; 410*10898Sroland.mainz@nrubsig.org break; 411*10898Sroland.mainz@nrubsig.org } 412*10898Sroland.mainz@nrubsig.org } 413*10898Sroland.mainz@nrubsig.org pp->flags |= flag; 414*10898Sroland.mainz@nrubsig.org if(((pp->flags&(PATH_PATH|PATH_SKIP))==PATH_PATH)) 415*10898Sroland.mainz@nrubsig.org { 416*10898Sroland.mainz@nrubsig.org int offset = staktell(); 417*10898Sroland.mainz@nrubsig.org stakputs(name); 418*10898Sroland.mainz@nrubsig.org path_chkpaths(first,0,pp,offset); 419*10898Sroland.mainz@nrubsig.org stakseek(offset); 420*10898Sroland.mainz@nrubsig.org } 421*10898Sroland.mainz@nrubsig.org } 422*10898Sroland.mainz@nrubsig.org 423*10898Sroland.mainz@nrubsig.org /* 4244887Schin * write the next path to search on the current stack 4254887Schin * if last is given, all paths that come before <last> are skipped 4264887Schin * the next pathcomp is returned. 4274887Schin */ 4284887Schin Pathcomp_t *path_nextcomp(register Pathcomp_t *pp, const char *name, Pathcomp_t *last) 4294887Schin { 430*10898Sroland.mainz@nrubsig.org Pathcomp_t *ppnext; 4314887Schin stakseek(PATH_OFFSET); 4324887Schin if(*name=='/') 4334887Schin pp = 0; 4344887Schin else 4354887Schin { 436*10898Sroland.mainz@nrubsig.org for(;pp && pp!=last;pp=ppnext) 4374887Schin { 438*10898Sroland.mainz@nrubsig.org if(ppnext=pp->next) 439*10898Sroland.mainz@nrubsig.org ppnext->shp = pp->shp; 440*10898Sroland.mainz@nrubsig.org if(!pp->dev && !pp->ino) 441*10898Sroland.mainz@nrubsig.org path_checkdup(pp); 4424887Schin if(pp->flags&PATH_SKIP) 4434887Schin continue; 4444887Schin if(!last || *pp->name!='/') 4454887Schin break; 4464887Schin } 4474887Schin if(!pp) /* this should not happen */ 4484887Schin pp = last; 4494887Schin } 4504887Schin if(pp && (pp->name[0]!='.' || pp->name[1])) 4514887Schin { 4524887Schin if(*pp->name!='/') 4534887Schin { 4544887Schin stakputs(path_pwd(1)); 4554887Schin if(*stakptr(staktell()-1)!='/') 4564887Schin stakputc('/'); 4574887Schin } 4584887Schin stakwrite(pp->name,pp->len); 4594887Schin if(pp->name[pp->len-1]!='/') 4604887Schin stakputc('/'); 4614887Schin } 4624887Schin stakputs(name); 4634887Schin stakputc(0); 4644887Schin while(pp && pp!=last && (pp=pp->next)) 4654887Schin { 4664887Schin if(!(pp->flags&PATH_SKIP)) 4674887Schin return(pp); 4684887Schin } 4694887Schin return((Pathcomp_t*)0); 4704887Schin } 4714887Schin 4724887Schin static Pathcomp_t* defpath_init(Shell_t *shp) 4734887Schin { 4744887Schin Pathcomp_t *pp = (void*)path_addpath((Pathcomp_t*)0,(std_path),PATH_PATH); 4754887Schin if(shp->defpathlist = (void*)pp) 4764887Schin pp->shp = shp; 4774887Schin return(pp); 4784887Schin } 4794887Schin 4804887Schin static void path_init(Shell_t *shp) 4814887Schin { 4824887Schin const char *val; 4834887Schin Pathcomp_t *pp; 4844887Schin if(!std_path && !(std_path=astconf("PATH",NIL(char*),NIL(char*)))) 4854887Schin std_path = e_defpath; 4868462SApril.Chin@Sun.COM if(val=sh_scoped(shp,(PATHNOD))->nvalue.cp) 4874887Schin { 4884887Schin pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_PATH); 4894887Schin if(shp->pathlist = (void*)pp) 4904887Schin pp->shp = shp; 4914887Schin } 4924887Schin else 4934887Schin { 4944887Schin if(!(pp=(Pathcomp_t*)shp->defpathlist)) 4954887Schin pp = defpath_init(shp); 4964887Schin shp->pathlist = (void*)path_dup(pp); 4974887Schin } 4988462SApril.Chin@Sun.COM if(val=sh_scoped(shp,(FPATHNOD))->nvalue.cp) 4994887Schin { 5004887Schin pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_FPATH); 5014887Schin if(shp->pathlist = (void*)pp) 5024887Schin pp->shp = shp; 5034887Schin } 5044887Schin } 5054887Schin 5064887Schin /* 5074887Schin * returns that pathlist to search 5084887Schin */ 5094887Schin Pathcomp_t *path_get(register const char *name) 5104887Schin { 5114887Schin register Shell_t *shp = &sh; 5124887Schin register Pathcomp_t *pp=0; 5134887Schin if(*name && strchr(name,'/')) 5144887Schin return(0); 5154887Schin if(!sh_isstate(SH_DEFPATH)) 5164887Schin { 5174887Schin if(!shp->pathlist) 5184887Schin path_init(shp); 5194887Schin pp = (Pathcomp_t*)shp->pathlist; 5204887Schin } 5214887Schin if(!pp && (!(PATHNOD)->nvalue.cp) || sh_isstate(SH_DEFPATH)) 5224887Schin { 5234887Schin if(!(pp=(Pathcomp_t*)shp->defpathlist)) 5244887Schin pp = defpath_init(shp); 5254887Schin } 5264887Schin return(pp); 5274887Schin } 5284887Schin 5294887Schin /* 5304887Schin * open file corresponding to name using path give by <pp> 5314887Schin */ 5324887Schin static int path_opentype(const char *name, register Pathcomp_t *pp, int fun) 5334887Schin { 5344887Schin register int fd= -1; 5354887Schin struct stat statb; 5364887Schin Pathcomp_t *oldpp; 5374887Schin Shell_t *shp; 5384887Schin if(pp) 5394887Schin shp = pp->shp; 5404887Schin else 5414887Schin { 5424887Schin shp = sh_getinterp(); 5434887Schin if(!shp->pathlist) 5444887Schin path_init(shp); 5454887Schin } 5464887Schin if(!fun && strchr(name,'/')) 5474887Schin { 5484887Schin if(sh_isoption(SH_RESTRICTED)) 5494887Schin errormsg(SH_DICT,ERROR_exit(1),e_restricted,name); 5504887Schin } 5514887Schin do 5524887Schin { 5534887Schin pp = path_nextcomp(oldpp=pp,name,0); 5544887Schin while(oldpp && (oldpp->flags&PATH_SKIP)) 5554887Schin oldpp = oldpp->next; 5564887Schin if(fun && (!oldpp || !(oldpp->flags&PATH_FPATH))) 5574887Schin continue; 5584887Schin if((fd = sh_open(path_relative(stakptr(PATH_OFFSET)),O_RDONLY,0)) >= 0) 5594887Schin { 5604887Schin if(fstat(fd,&statb)<0 || S_ISDIR(statb.st_mode)) 5614887Schin { 5624887Schin errno = EISDIR; 5634887Schin sh_close(fd); 5644887Schin fd = -1; 5654887Schin } 5664887Schin } 5674887Schin } 5684887Schin while( fd<0 && pp); 5694887Schin if(fd>=0 && (fd = sh_iomovefd(fd)) > 0) 5704887Schin { 5714887Schin fcntl(fd,F_SETFD,FD_CLOEXEC); 572*10898Sroland.mainz@nrubsig.org if(!shp) 573*10898Sroland.mainz@nrubsig.org { 574*10898Sroland.mainz@nrubsig.org shp = sh_getinterp(); 575*10898Sroland.mainz@nrubsig.org #if _UWIN 576*10898Sroland.mainz@nrubsig.org close(0x10001); /* this results in a /var/log/uwin message with "0x10001" for debugging */ 577*10898Sroland.mainz@nrubsig.org #endif 578*10898Sroland.mainz@nrubsig.org } 5794887Schin shp->fdstatus[fd] |= IOCLEX; 5804887Schin } 5814887Schin return(fd); 5824887Schin } 5834887Schin 5844887Schin /* 5854887Schin * open file corresponding to name using path give by <pp> 5864887Schin */ 5874887Schin int path_open(const char *name, register Pathcomp_t *pp) 5884887Schin { 5894887Schin return(path_opentype(name,pp,0)); 5904887Schin } 5914887Schin 5924887Schin /* 5934887Schin * given a pathname return the base name 5944887Schin */ 5954887Schin 5964887Schin char *path_basename(register const char *name) 5974887Schin { 5984887Schin register const char *start = name; 5994887Schin while (*name) 6004887Schin if ((*name++ == '/') && *name) /* don't trim trailing / */ 6014887Schin start = name; 6024887Schin return ((char*)start); 6034887Schin } 6044887Schin 6054887Schin char *path_fullname(const char *name) 6064887Schin { 6074887Schin int len=strlen(name)+1,dirlen=0; 6084887Schin char *path,*pwd; 6094887Schin if(*name!='/') 6104887Schin { 6114887Schin pwd = path_pwd(1); 6124887Schin dirlen = strlen(pwd)+1; 6134887Schin } 6144887Schin path = (char*)malloc(len+dirlen); 6154887Schin if(dirlen) 6164887Schin { 6174887Schin memcpy((void*)path,(void*)pwd,dirlen); 6184887Schin path[dirlen-1] = '/'; 6194887Schin } 6204887Schin memcpy((void*)&path[dirlen],(void*)name,len); 6214887Schin pathcanon(path,0); 6224887Schin return(path); 6234887Schin } 6244887Schin 6254887Schin /* 6264887Schin * load functions from file <fno> 6274887Schin */ 6284887Schin static void funload(Shell_t *shp,int fno, const char *name) 6294887Schin { 6308462SApril.Chin@Sun.COM char *pname,*oldname=shp->st.filename, buff[IOBSIZE+1]; 6318462SApril.Chin@Sun.COM Namval_t *np; 6328462SApril.Chin@Sun.COM struct Ufunction *rp; 6338462SApril.Chin@Sun.COM int savestates = sh_getstate(), oldload=shp->funload; 6348462SApril.Chin@Sun.COM pname = path_fullname(stakptr(PATH_OFFSET)); 6358462SApril.Chin@Sun.COM if(shp->fpathdict && (rp = dtmatch(shp->fpathdict,(void*)pname))) 6368462SApril.Chin@Sun.COM { 637*10898Sroland.mainz@nrubsig.org Dt_t *funtree = sh_subfuntree(1); 6388462SApril.Chin@Sun.COM do 6398462SApril.Chin@Sun.COM { 640*10898Sroland.mainz@nrubsig.org if((np = dtsearch(funtree,rp->np)) && is_afunction(np)) 6418462SApril.Chin@Sun.COM { 6428462SApril.Chin@Sun.COM if(np->nvalue.rp) 6438462SApril.Chin@Sun.COM np->nvalue.rp->fdict = 0; 644*10898Sroland.mainz@nrubsig.org nv_delete(np,funtree,NV_NOFREE); 6458462SApril.Chin@Sun.COM } 646*10898Sroland.mainz@nrubsig.org dtinsert(funtree,rp->np); 647*10898Sroland.mainz@nrubsig.org rp->fdict = funtree; 6488462SApril.Chin@Sun.COM } 6498462SApril.Chin@Sun.COM while((rp=dtnext(shp->fpathdict,rp)) && strcmp(pname,rp->fname)==0); 6508462SApril.Chin@Sun.COM return; 6518462SApril.Chin@Sun.COM } 6524887Schin sh_onstate(SH_NOLOG); 6534887Schin sh_onstate(SH_NOALIAS); 6544887Schin shp->readscript = (char*)name; 6558462SApril.Chin@Sun.COM shp->st.filename = pname; 6568462SApril.Chin@Sun.COM shp->funload = 1; 6574887Schin error_info.line = 0; 658*10898Sroland.mainz@nrubsig.org sh_eval(sfnew(NIL(Sfio_t*),buff,IOBSIZE,fno,SF_READ),SH_FUNEVAL); 6594887Schin shp->readscript = 0; 6604887Schin free((void*)shp->st.filename); 6618462SApril.Chin@Sun.COM shp->funload = oldload; 6624887Schin shp->st.filename = oldname; 6634887Schin sh_setstate(savestates); 6644887Schin } 6654887Schin 6664887Schin /* 6674887Schin * do a path search and track alias if requested 6684887Schin * if flag is 0, or if name not found, then try autoloading function 6698462SApril.Chin@Sun.COM * if flag==2 or 3, returns 1 if name found on FPATH 6708462SApril.Chin@Sun.COM * if flag==3 no tracked alias will be set 6714887Schin * returns 1, if function was autoloaded. 6728462SApril.Chin@Sun.COM * If oldpp is not NULL, it will contain a pointer to the path component 6738462SApril.Chin@Sun.COM * where it was found. 6744887Schin */ 6754887Schin 6768462SApril.Chin@Sun.COM int path_search(register const char *name,Pathcomp_t **oldpp, int flag) 6774887Schin { 6784887Schin register Namval_t *np; 6794887Schin register int fno; 6804887Schin Pathcomp_t *pp=0; 6814887Schin Shell_t *shp = &sh; 6824887Schin if(name && strchr(name,'/')) 6834887Schin { 6844887Schin stakseek(PATH_OFFSET); 6854887Schin stakputs(name); 6864887Schin if(canexecute(stakptr(PATH_OFFSET),0)<0) 6874887Schin { 6884887Schin *stakptr(PATH_OFFSET) = 0; 6894887Schin return(0); 6904887Schin } 6914887Schin if(*name=='/') 6924887Schin return(1); 6934887Schin stakseek(PATH_OFFSET); 6944887Schin stakputs(path_pwd(1)); 6954887Schin stakputc('/'); 6964887Schin stakputs(name); 6974887Schin stakputc(0); 6984887Schin return(0); 6994887Schin } 7004887Schin if(sh_isstate(SH_DEFPATH)) 7014887Schin { 7024887Schin if(!shp->defpathlist) 7034887Schin defpath_init(shp); 7044887Schin } 7054887Schin else if(!shp->pathlist) 7064887Schin path_init(shp); 7074887Schin if(flag) 7084887Schin { 709*10898Sroland.mainz@nrubsig.org if((np=nv_search(name,shp->track_tree,0)) && !nv_isattr(np,NV_NOALIAS) && (pp=(Pathcomp_t*)np->nvalue.cp)) 710*10898Sroland.mainz@nrubsig.org { 711*10898Sroland.mainz@nrubsig.org stakseek(PATH_OFFSET); 712*10898Sroland.mainz@nrubsig.org path_nextcomp(pp,name,pp); 713*10898Sroland.mainz@nrubsig.org stakputc(0); 714*10898Sroland.mainz@nrubsig.org return(0); 715*10898Sroland.mainz@nrubsig.org } 7168462SApril.Chin@Sun.COM pp = path_absolute(name,oldpp?*oldpp:NIL(Pathcomp_t*)); 7178462SApril.Chin@Sun.COM if(oldpp) 7188462SApril.Chin@Sun.COM *oldpp = pp; 719*10898Sroland.mainz@nrubsig.org if(!pp && (np=nv_search(name,shp->fun_tree,HASH_NOSCOPE))&&np->nvalue.ip) 7204887Schin return(1); 7214887Schin if(!pp) 7224887Schin *stakptr(PATH_OFFSET) = 0; 7234887Schin } 7244887Schin if(flag==0 || !pp || (pp->flags&PATH_FPATH)) 7254887Schin { 7264887Schin if(!pp) 7274887Schin pp=sh_isstate(SH_DEFPATH)?shp->defpathlist:shp->pathlist; 7284887Schin if(pp && strmatch(name,e_alphanum) && (fno=path_opentype(name,pp,1))>=0) 7294887Schin { 7304887Schin if(flag==2) 7314887Schin { 7324887Schin sh_close(fno); 7334887Schin return(1); 7344887Schin } 7354887Schin funload(shp,fno,name); 7364887Schin return(1); 7374887Schin } 7384887Schin *stakptr(PATH_OFFSET) = 0; 7394887Schin return(0); 7404887Schin } 7418462SApril.Chin@Sun.COM else if(pp && !sh_isstate(SH_DEFPATH) && *name!='/' && flag<3) 7424887Schin { 7434887Schin if(np=nv_search(name,shp->track_tree,NV_ADD)) 7444887Schin path_alias(np,pp); 7454887Schin } 7464887Schin return(0); 7474887Schin } 7484887Schin 7494887Schin /* 7504887Schin * do a path search and find the full pathname of file name 7514887Schin */ 7528462SApril.Chin@Sun.COM Pathcomp_t *path_absolute(register const char *name, Pathcomp_t *pp) 7534887Schin { 7544887Schin register int f,isfun; 7554887Schin int noexec=0; 7568462SApril.Chin@Sun.COM Pathcomp_t *oldpp; 7574887Schin Shell_t *shp = &sh; 7584887Schin Namval_t *np; 7594887Schin shp->path_err = ENOENT; 7608462SApril.Chin@Sun.COM if(!pp && !(pp=path_get(""))) 7614887Schin return(0); 7624887Schin shp->path_err = 0; 7634887Schin while(1) 7644887Schin { 7654887Schin sh_sigcheck(); 7664887Schin isfun = (pp->flags&PATH_FPATH); 7674887Schin if(oldpp=pp) 768*10898Sroland.mainz@nrubsig.org { 7694887Schin pp = path_nextcomp(pp,name,0); 770*10898Sroland.mainz@nrubsig.org while(oldpp->flags&PATH_SKIP) 771*10898Sroland.mainz@nrubsig.org { 772*10898Sroland.mainz@nrubsig.org if(!(oldpp=oldpp->next)) 773*10898Sroland.mainz@nrubsig.org { 774*10898Sroland.mainz@nrubsig.org shp->path_err = ENOENT; 775*10898Sroland.mainz@nrubsig.org return(0); 776*10898Sroland.mainz@nrubsig.org } 777*10898Sroland.mainz@nrubsig.org } 778*10898Sroland.mainz@nrubsig.org } 779*10898Sroland.mainz@nrubsig.org 7804887Schin if(!isfun && !sh_isoption(SH_RESTRICTED)) 7814887Schin { 7828462SApril.Chin@Sun.COM if(*stakptr(PATH_OFFSET)=='/' && nv_search(stakptr(PATH_OFFSET),sh.bltin_tree,0)) 7834887Schin return(oldpp); 7848462SApril.Chin@Sun.COM #if SHOPT_DYNAMIC 7854887Schin if(oldpp->blib) 7864887Schin { 7874887Schin typedef int (*Fptr_t)(int, char*[], void*); 7884887Schin Fptr_t addr; 7894887Schin int n = staktell(); 790*10898Sroland.mainz@nrubsig.org int libcmd; 7914887Schin char *cp; 7924887Schin stakputs("b_"); 7934887Schin stakputs(name); 7944887Schin stakputc(0); 7954887Schin if(!oldpp->bltin_lib) 7964887Schin { 7974887Schin if(cp = strrchr(oldpp->blib,'/')) 7984887Schin cp++; 7994887Schin else 8004887Schin cp = oldpp->blib; 801*10898Sroland.mainz@nrubsig.org if((libcmd = !strcmp(cp,LIBCMD)) && (addr=(Fptr_t)dlllook((void*)0,stakptr(n)))) 8024887Schin { 8038462SApril.Chin@Sun.COM if((np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL)) && nv_isattr(np,NV_BLTINOPT)) 8048462SApril.Chin@Sun.COM return(oldpp); 8054887Schin } 8064887Schin #if (_AST_VERSION>=20040404) 8074887Schin if (oldpp->bltin_lib = dllplug(SH_ID, oldpp->blib, NiL, RTLD_LAZY, NiL, 0)) 8084887Schin #else 8094887Schin if (oldpp->bltin_lib = dllfind(oldpp->blib, NiL, RTLD_LAZY, NiL, 0)) 8104887Schin #endif 811*10898Sroland.mainz@nrubsig.org { 812*10898Sroland.mainz@nrubsig.org /* 813*10898Sroland.mainz@nrubsig.org * this detects the 2007-05-11 builtin context change and also 814*10898Sroland.mainz@nrubsig.org * the 2008-03-30 opt_info.num change that hit libcmd::b_head 815*10898Sroland.mainz@nrubsig.org */ 816*10898Sroland.mainz@nrubsig.org 817*10898Sroland.mainz@nrubsig.org if (libcmd && !dlllook(oldpp->bltin_lib, "b_pids")) 818*10898Sroland.mainz@nrubsig.org { 819*10898Sroland.mainz@nrubsig.org dlclose(oldpp->bltin_lib); 820*10898Sroland.mainz@nrubsig.org oldpp->bltin_lib = 0; 821*10898Sroland.mainz@nrubsig.org oldpp->blib = 0; 822*10898Sroland.mainz@nrubsig.org } 823*10898Sroland.mainz@nrubsig.org else 824*10898Sroland.mainz@nrubsig.org sh_addlib(oldpp->bltin_lib); 825*10898Sroland.mainz@nrubsig.org } 8264887Schin } 8274887Schin if((addr=(Fptr_t)dlllook(oldpp->bltin_lib,stakptr(n))) && 8284887Schin (!(np = sh_addbuiltin(stakptr(PATH_OFFSET),NiL,NiL)) || np->nvalue.bfp!=addr) && 8294887Schin (np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL))) 8304887Schin { 8314887Schin np->nvenv = oldpp->bltin_lib; 8324887Schin return(oldpp); 8334887Schin } 8344887Schin } 8358462SApril.Chin@Sun.COM #endif /* SHOPT_DYNAMIC */ 8364887Schin } 8378462SApril.Chin@Sun.COM sh_stats(STAT_PATHS); 8384887Schin f = canexecute(stakptr(PATH_OFFSET),isfun); 8394887Schin if(isfun && f>=0) 8404887Schin { 841*10898Sroland.mainz@nrubsig.org nv_onattr(nv_open(name,sh_subfuntree(1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE),NV_LTOU|NV_FUNCTION); 842*10898Sroland.mainz@nrubsig.org funload(shp,f,name); 8434887Schin close(f); 8444887Schin f = -1; 8454887Schin return(0); 8464887Schin } 8474887Schin else if(f>=0 && (oldpp->flags & PATH_STD_DIR)) 8484887Schin { 8498462SApril.Chin@Sun.COM int n = staktell(); 8504887Schin stakputs("/bin/"); 8514887Schin stakputs(name); 8524887Schin stakputc(0); 8538462SApril.Chin@Sun.COM np = nv_search(stakptr(n),sh.bltin_tree,0); 8548462SApril.Chin@Sun.COM stakseek(n); 8554887Schin if(np) 8564887Schin { 8578462SApril.Chin@Sun.COM n = np->nvflag; 8588462SApril.Chin@Sun.COM np = sh_addbuiltin(stakptr(PATH_OFFSET),np->nvalue.bfp,nv_context(np)); 8598462SApril.Chin@Sun.COM np->nvflag = n; 8604887Schin } 8614887Schin } 8624887Schin if(!pp || f>=0) 8634887Schin break; 8644887Schin if(errno!=ENOENT) 8654887Schin noexec = errno; 8664887Schin } 8674887Schin if(f<0) 8684887Schin { 8698462SApril.Chin@Sun.COM shp->path_err = (noexec?noexec:ENOENT); 8704887Schin return(0); 8714887Schin } 8724887Schin stakputc(0); 8734887Schin return(oldpp); 8744887Schin } 8754887Schin 8764887Schin /* 8774887Schin * returns 0 if path can execute 8784887Schin * sets exec_err if file is found but can't be executable 8794887Schin */ 8804887Schin #undef S_IXALL 8814887Schin #ifdef S_IXUSR 8824887Schin # define S_IXALL (S_IXUSR|S_IXGRP|S_IXOTH) 8834887Schin #else 8844887Schin # ifdef S_IEXEC 8854887Schin # define S_IXALL (S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6)) 8864887Schin # else 8874887Schin # define S_IXALL 0111 8884887Schin # endif /*S_EXEC */ 8894887Schin #endif /* S_IXUSR */ 8904887Schin 8914887Schin static int canexecute(register char *path, int isfun) 8924887Schin { 8934887Schin struct stat statb; 8944887Schin register int fd=0; 8954887Schin path = path_relative(path); 8964887Schin if(isfun) 8974887Schin { 8984887Schin if((fd=open(path,O_RDONLY,0))<0 || fstat(fd,&statb)<0) 8994887Schin goto err; 9004887Schin } 9014887Schin else if(stat(path,&statb) < 0) 9024887Schin { 9034887Schin #if _WINIX 9044887Schin /* check for .exe or .bat suffix */ 9054887Schin char *cp; 9064887Schin if(errno==ENOENT && (!(cp=strrchr(path,'.')) || strlen(cp)>4 || strchr(cp,'/'))) 9074887Schin { 9084887Schin int offset = staktell()-1; 9094887Schin stakseek(offset); 9104887Schin stakputs(".bat"); 9114887Schin path = stakptr(PATH_OFFSET); 9124887Schin if(stat(path,&statb) < 0) 9134887Schin { 9144887Schin if(errno!=ENOENT) 9154887Schin goto err; 9164887Schin memcpy(stakptr(offset),".sh",4); 9174887Schin if(stat(path,&statb) < 0) 9184887Schin goto err; 9194887Schin } 9204887Schin } 9214887Schin else 9224887Schin #endif /* _WINIX */ 9234887Schin goto err; 9244887Schin } 9254887Schin errno = EPERM; 9264887Schin if(S_ISDIR(statb.st_mode)) 9274887Schin errno = EISDIR; 9284887Schin else if((statb.st_mode&S_IXALL)==S_IXALL || sh_access(path,X_OK)>=0) 9294887Schin return(fd); 9304887Schin if(isfun && fd>=0) 9314887Schin sh_close(fd); 9324887Schin err: 9334887Schin return(-1); 9344887Schin } 9354887Schin 9364887Schin /* 9374887Schin * Return path relative to present working directory 9384887Schin */ 9394887Schin 9404887Schin char *path_relative(register const char* file) 9414887Schin { 9424887Schin register const char *pwd; 9434887Schin register const char *fp = file; 9444887Schin /* can't relpath when sh.pwd not set */ 9454887Schin if(!(pwd=sh.pwd)) 9464887Schin return((char*)fp); 9474887Schin while(*pwd==*fp) 9484887Schin { 9494887Schin if(*pwd++==0) 9504887Schin return((char*)e_dot); 9514887Schin fp++; 9524887Schin } 9534887Schin if(*pwd==0 && *fp == '/') 9544887Schin { 9554887Schin while(*++fp=='/'); 9564887Schin if(*fp) 9574887Schin return((char*)fp); 9584887Schin return((char*)e_dot); 9594887Schin } 9604887Schin return((char*)file); 9614887Schin } 9624887Schin 9634887Schin void path_exec(register const char *arg0,register char *argv[],struct argnod *local) 9644887Schin { 9654887Schin char **envp; 9664887Schin const char *opath; 9674887Schin Pathcomp_t *libpath, *pp=0; 9684887Schin Shell_t *shp = &sh; 9694887Schin int slash=0; 970*10898Sroland.mainz@nrubsig.org nv_setlist(local,NV_EXPORT|NV_IDENT|NV_ASSIGN,0); 9714887Schin envp = sh_envgen(); 9724887Schin if(strchr(arg0,'/')) 9734887Schin { 9744887Schin slash=1; 9754887Schin /* name containing / not allowed for restricted shell */ 9764887Schin if(sh_isoption(SH_RESTRICTED)) 9774887Schin errormsg(SH_DICT,ERROR_exit(1),e_restricted,arg0); 9784887Schin } 9794887Schin else 9804887Schin pp=path_get(arg0); 9814887Schin shp->path_err= ENOENT; 9824887Schin sfsync(NIL(Sfio_t*)); 9834887Schin timerdel(NIL(void*)); 9844887Schin /* find first path that has a library component */ 985*10898Sroland.mainz@nrubsig.org while(pp && (pp->flags&PATH_SKIP)) 986*10898Sroland.mainz@nrubsig.org pp = pp->next; 9874887Schin if(pp || slash) do 9884887Schin { 9894887Schin sh_sigcheck(); 9904887Schin if(libpath=pp) 9914887Schin { 9924887Schin pp = path_nextcomp(pp,arg0,0); 9934887Schin opath = stakfreeze(1)+PATH_OFFSET; 9944887Schin } 9954887Schin else 9964887Schin opath = arg0; 9974887Schin path_spawn(opath,argv,envp,libpath,0); 9984887Schin while(pp && (pp->flags&PATH_FPATH)) 9994887Schin pp = path_nextcomp(pp,arg0,0); 10004887Schin } 10014887Schin while(pp); 10024887Schin /* force an exit */ 10034887Schin ((struct checkpt*)shp->jmplist)->mode = SH_JMPEXIT; 10044887Schin if((errno=shp->path_err)==ENOENT) 10054887Schin errormsg(SH_DICT,ERROR_exit(ERROR_NOENT),e_found,arg0); 10064887Schin else 10074887Schin errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,arg0); 10084887Schin } 10094887Schin 10104887Schin pid_t path_spawn(const char *opath,register char **argv, char **envp, Pathcomp_t *libpath, int spawn) 10114887Schin { 10124887Schin Shell_t *shp = sh_getinterp(); 10134887Schin register char *path; 10144887Schin char **xp=0, *xval, *libenv = (libpath?libpath->lib:0); 10154887Schin Namval_t* np; 10164887Schin char *s, *v; 1017*10898Sroland.mainz@nrubsig.org int r, n, pidsize; 10184887Schin pid_t pid= -1; 10194887Schin /* leave room for inserting _= pathname in environment */ 10204887Schin envp--; 10214887Schin #if _lib_readlink 10224887Schin /* save original pathname */ 10234887Schin stakseek(PATH_OFFSET); 1024*10898Sroland.mainz@nrubsig.org pidsize = sfprintf(stkstd,"*%d*",spawn?getpid():getppid()); 10254887Schin stakputs(opath); 1026*10898Sroland.mainz@nrubsig.org opath = stakfreeze(1)+PATH_OFFSET+pidsize; 10274887Schin np=nv_search(argv[0],shp->track_tree,0); 10284887Schin while(libpath && !libpath->lib) 10294887Schin libpath=libpath->next; 10304887Schin if(libpath && (!np || nv_size(np)>0)) 10314887Schin { 10324887Schin /* check for symlink and use symlink name */ 10334887Schin char buff[PATH_MAX+1]; 10344887Schin char save[PATH_MAX+1]; 10354887Schin stakseek(PATH_OFFSET); 10364887Schin stakputs(opath); 10374887Schin path = stakptr(PATH_OFFSET); 10384887Schin while((n=readlink(path,buff,PATH_MAX))>0) 10394887Schin { 10404887Schin buff[n] = 0; 10414887Schin n = PATH_OFFSET; 10424887Schin r = 0; 10434887Schin if((v=strrchr(path,'/')) && *buff!='/') 10444887Schin { 10454887Schin if(buff[0]=='.' && buff[1]=='.' && (r = strlen(path) + 1) <= PATH_MAX) 10464887Schin memcpy(save, path, r); 10474887Schin else 10484887Schin r = 0; 10494887Schin n += (v+1-path); 10504887Schin } 10514887Schin stakseek(n); 10524887Schin stakputs(buff); 10534887Schin stakputc(0); 10544887Schin path = stakptr(PATH_OFFSET); 10554887Schin if(v && buff[0]=='.' && buff[1]=='.') 10564887Schin { 10574887Schin pathcanon(path, 0); 10584887Schin if(r && access(path,X_OK)) 10594887Schin { 10604887Schin memcpy(path, save, r); 10614887Schin break; 10624887Schin } 10634887Schin } 10644887Schin if(libenv = path_lib(libpath,path)) 10654887Schin break; 10664887Schin } 10674887Schin stakseek(0); 10684887Schin } 10694887Schin #endif 10704887Schin if(libenv && (v = strchr(libenv,'='))) 10714887Schin { 10724887Schin n = v - libenv; 10734887Schin *v = 0; 10744887Schin np = nv_open(libenv,shp->var_tree,0); 10754887Schin *v = '='; 10764887Schin s = nv_getval(np); 10774887Schin stakputs(libenv); 10784887Schin if(s) 10794887Schin { 10804887Schin stakputc(':'); 10814887Schin stakputs(s); 10824887Schin } 10834887Schin v = stakfreeze(1); 10844887Schin r = 1; 10858462SApril.Chin@Sun.COM xp = envp + 1; 10864887Schin while (s = *xp++) 10874887Schin { 10884887Schin if (strneq(s, v, n) && s[n] == '=') 10894887Schin { 10904887Schin xval = *--xp; 10914887Schin *xp = v; 10924887Schin r = 0; 10934887Schin break; 10944887Schin } 10954887Schin } 10964887Schin if (r) 10974887Schin { 10984887Schin *envp-- = v; 10994887Schin xp = 0; 11004887Schin } 11014887Schin } 11024887Schin if(!opath) 11034887Schin opath = stakptr(PATH_OFFSET); 1104*10898Sroland.mainz@nrubsig.org envp[0] = (char*)opath-(PATH_OFFSET+pidsize); 11054887Schin envp[0][0] = '_'; 11064887Schin envp[0][1] = '='; 11074887Schin sfsync(sfstderr); 11084887Schin sh_sigcheck(); 11094887Schin path = path_relative(opath); 11104887Schin #ifdef SHELLMAGIC 11114887Schin if(*path!='/' && path!=opath) 11124887Schin { 11134887Schin /* 11144887Schin * The following code because execv(foo,) and execv(./foo,) 11154887Schin * may not yield the same results 11164887Schin */ 11174887Schin char *sp = (char*)malloc(strlen(path)+3); 11184887Schin sp[0] = '.'; 11194887Schin sp[1] = '/'; 11204887Schin strcpy(sp+2,path); 11214887Schin path = sp; 11224887Schin } 11234887Schin #endif /* SHELLMAGIC */ 11244887Schin if(spawn && !sh_isoption(SH_PFSH)) 11254887Schin pid = _spawnveg(opath, &argv[0],envp, spawn>>1); 11264887Schin else 11278462SApril.Chin@Sun.COM pid = path_pfexecve(opath, &argv[0] ,envp,spawn); 11284887Schin if(xp) 11294887Schin *xp = xval; 11304887Schin #ifdef SHELLMAGIC 11314887Schin if(*path=='.' && path!=opath) 11324887Schin { 11334887Schin free(path); 11344887Schin path = path_relative(opath); 11354887Schin } 11364887Schin #endif /* SHELLMAGIC */ 11374887Schin if(pid>0) 11384887Schin return(pid); 11394887Schin retry: 11404887Schin switch(sh.path_err = errno) 11414887Schin { 11424887Schin #ifdef apollo 11434887Schin /* 11444887Schin * On apollo's execve will fail with eacces when 11454887Schin * file has execute but not read permissions. So, 11464887Schin * for now we will pretend that EACCES and ENOEXEC 11474887Schin * mean the same thing. 11484887Schin */ 11494887Schin case EACCES: 11504887Schin #endif /* apollo */ 11514887Schin case ENOEXEC: 11524887Schin #if SHOPT_SUID_EXEC 11534887Schin case EPERM: 11544887Schin /* some systems return EPERM if setuid bit is on */ 11554887Schin #endif 11564887Schin errno = ENOEXEC; 11574887Schin if(spawn) 11584887Schin { 11594887Schin #ifdef _lib_fork 11604887Schin if(sh.subshell) 11614887Schin return(-1); 11624887Schin do 11634887Schin { 11644887Schin if((pid=fork())>0) 11654887Schin return(pid); 11664887Schin } 11674887Schin while(_sh_fork(pid,0,(int*)0) < 0); 11688462SApril.Chin@Sun.COM ((struct checkpt*)shp->jmplist)->mode = SH_JMPEXIT; 11694887Schin #else 11704887Schin return(-1); 11714887Schin #endif 11724887Schin } 11734887Schin exscript(shp,path,argv,envp); 11744887Schin #ifndef apollo 11754887Schin case EACCES: 11764887Schin { 11774887Schin struct stat statb; 11784887Schin if(stat(path,&statb)>=0) 11794887Schin { 11804887Schin if(S_ISDIR(statb.st_mode)) 11814887Schin errno = EISDIR; 11824887Schin #ifdef S_ISSOCK 11834887Schin if(S_ISSOCK(statb.st_mode)) 11844887Schin exscript(shp,path,argv,envp); 11854887Schin #endif 11864887Schin } 11874887Schin } 11884887Schin /* FALL THROUGH */ 11894887Schin #endif /* !apollo */ 11904887Schin #ifdef ENAMETOOLONG 11914887Schin case ENAMETOOLONG: 11924887Schin #endif /* ENAMETOOLONG */ 11934887Schin #if !SHOPT_SUID_EXEC 11944887Schin case EPERM: 11954887Schin #endif 11964887Schin shp->path_err = errno; 11974887Schin return(-1); 11984887Schin case ENOTDIR: 11994887Schin case ENOENT: 12004887Schin case EINTR: 12014887Schin #ifdef EMLINK 12024887Schin case EMLINK: 12034887Schin #endif /* EMLINK */ 12044887Schin return(-1); 12054887Schin case E2BIG: 12064887Schin if(sh.xargmin) 12074887Schin { 12084887Schin pid = path_xargs(opath, &argv[0] ,envp,spawn); 12094887Schin if(pid<0) 12104887Schin goto retry; 12114887Schin return(pid); 12124887Schin } 12134887Schin default: 12144887Schin errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path); 12154887Schin } 12164887Schin return 0; 12174887Schin } 12184887Schin 12194887Schin /* 12204887Schin * File is executable but not machine code. 12214887Schin * Assume file is a Shell script and execute it. 12224887Schin */ 12234887Schin 12244887Schin static void exscript(Shell_t *shp,register char *path,register char *argv[],char **envp) 12254887Schin { 12264887Schin register Sfio_t *sp; 12274887Schin path = path_relative(path); 12284887Schin shp->comdiv=0; 12294887Schin shp->bckpid = 0; 12304887Schin shp->st.ioset=0; 12314887Schin /* clean up any cooperating processes */ 12324887Schin if(shp->cpipe[0]>0) 12334887Schin sh_pclose(shp->cpipe); 12344887Schin if(shp->cpid && shp->outpipe) 12354887Schin sh_close(*shp->outpipe); 12364887Schin shp->cpid = 0; 12374887Schin if(sp=fcfile()) 12384887Schin while(sfstack(sp,SF_POPSTACK)); 12394887Schin job_clear(); 12404887Schin if(shp->infd>0 && (shp->fdstatus[shp->infd]&IOCLEX)) 12414887Schin sh_close(shp->infd); 12424887Schin sh_setstate(sh_state(SH_FORKED)); 12434887Schin sfsync(sfstderr); 12444887Schin #if SHOPT_SUID_EXEC && !SHOPT_PFSH 12454887Schin /* check if file cannot open for read or script is setuid/setgid */ 12464887Schin { 12474887Schin static char name[] = "/tmp/euidXXXXXXXXXX"; 12484887Schin register int n; 12494887Schin register uid_t euserid; 12504887Schin char *savet=0; 12514887Schin struct stat statb; 12524887Schin if((n=sh_open(path,O_RDONLY,0)) >= 0) 12534887Schin { 12544887Schin /* move <n> if n=0,1,2 */ 12554887Schin n = sh_iomovefd(n); 12564887Schin if(fstat(n,&statb)>=0 && !(statb.st_mode&(S_ISUID|S_ISGID))) 12574887Schin goto openok; 12584887Schin sh_close(n); 12594887Schin } 12604887Schin if((euserid=geteuid()) != shp->userid) 12614887Schin { 12624887Schin strncpy(name+9,fmtbase((long)getpid(),10,0),sizeof(name)-10); 12634887Schin /* create a suid open file with owner equal effective uid */ 12644887Schin if((n=open(name,O_CREAT|O_TRUNC|O_WRONLY,S_ISUID|S_IXUSR)) < 0) 12654887Schin goto fail; 12664887Schin unlink(name); 12674887Schin /* make sure that file has right owner */ 12684887Schin if(fstat(n,&statb)<0 || statb.st_uid != euserid) 12694887Schin goto fail; 12704887Schin if(n!=10) 12714887Schin { 12724887Schin sh_close(10); 12734887Schin fcntl(n, F_DUPFD, 10); 12744887Schin sh_close(n); 12754887Schin n=10; 12764887Schin } 12774887Schin } 12784887Schin savet = *--argv; 12794887Schin *argv = path; 12808462SApril.Chin@Sun.COM path_pfexecve(e_suidexec,argv,envp,0); 12814887Schin fail: 12824887Schin /* 12834887Schin * The following code is just for compatibility 12844887Schin */ 12854887Schin if((n=open(path,O_RDONLY,0)) < 0) 12868462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path); 12874887Schin if(savet) 12884887Schin *argv++ = savet; 12894887Schin openok: 12904887Schin shp->infd = n; 12914887Schin } 12924887Schin #else 12938462SApril.Chin@Sun.COM if((shp->infd = sh_open(path,O_RDONLY,0)) < 0) 12948462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path); 12954887Schin #endif 12964887Schin shp->infd = sh_iomovefd(shp->infd); 12974887Schin #if SHOPT_ACCT 12984887Schin sh_accbegin(path) ; /* reset accounting */ 12994887Schin #endif /* SHOPT_ACCT */ 13004887Schin shp->arglist = sh_argcreate(argv); 13014887Schin shp->lastarg = strdup(path); 13024887Schin /* save name of calling command */ 13034887Schin shp->readscript = error_info.id; 13044887Schin /* close history file if name has changed */ 13054887Schin if(shp->hist_ptr && (path=nv_getval(HISTFILE)) && strcmp(path,shp->hist_ptr->histname)) 13064887Schin { 13074887Schin hist_close(shp->hist_ptr); 13084887Schin (HISTCUR)->nvalue.lp = 0; 13094887Schin } 13104887Schin sh_offstate(SH_FORKED); 1311*10898Sroland.mainz@nrubsig.org if(shp->sigflag[SIGCHLD]==SH_SIGOFF) 1312*10898Sroland.mainz@nrubsig.org shp->sigflag[SIGCHLD] = SH_SIGFAULT; 13134887Schin siglongjmp(*shp->jmplist,SH_JMPSCRIPT); 13144887Schin } 13154887Schin 13164887Schin #if SHOPT_ACCT 13174887Schin # include <sys/acct.h> 13184887Schin # include "FEATURE/time" 13194887Schin 13204887Schin static struct acct sabuf; 13214887Schin static struct tms buffer; 13224887Schin static clock_t before; 13234887Schin static char *SHACCT; /* set to value of SHACCT environment variable */ 13244887Schin static shaccton; /* non-zero causes accounting record to be written */ 13254887Schin static int compress(time_t); 13264887Schin /* 13274887Schin * initialize accounting, i.e., see if SHACCT variable set 13284887Schin */ 13294887Schin void sh_accinit(void) 13304887Schin { 13314887Schin SHACCT = getenv("SHACCT"); 13324887Schin } 13334887Schin /* 13348462SApril.Chin@Sun.COM * suspend accounting until turned on by sh_accbegin() 13354887Schin */ 13364887Schin void sh_accsusp(void) 13374887Schin { 13384887Schin shaccton=0; 13394887Schin #ifdef AEXPAND 13404887Schin sabuf.ac_flag |= AEXPND; 13414887Schin #endif /* AEXPAND */ 13424887Schin } 13434887Schin 13444887Schin /* 13454887Schin * begin an accounting record by recording start time 13464887Schin */ 13474887Schin void sh_accbegin(const char *cmdname) 13484887Schin { 13494887Schin if(SHACCT) 13504887Schin { 13514887Schin sabuf.ac_btime = time(NIL(time_t *)); 13524887Schin before = times(&buffer); 13534887Schin sabuf.ac_uid = getuid(); 13544887Schin sabuf.ac_gid = getgid(); 13554887Schin strncpy(sabuf.ac_comm, (char*)path_basename(cmdname), 13564887Schin sizeof(sabuf.ac_comm)); 13574887Schin shaccton = 1; 13584887Schin } 13594887Schin } 13604887Schin /* 13614887Schin * terminate an accounting record and append to accounting file 13624887Schin */ 13634887Schin void sh_accend(void) 13644887Schin { 13654887Schin int fd; 13664887Schin clock_t after; 13674887Schin 13684887Schin if(shaccton) 13694887Schin { 13704887Schin after = times(&buffer); 13714887Schin sabuf.ac_utime = compress(buffer.tms_utime + buffer.tms_cutime); 13724887Schin sabuf.ac_stime = compress(buffer.tms_stime + buffer.tms_cstime); 13734887Schin sabuf.ac_etime = compress( (time_t)(after-before)); 13744887Schin fd = open( SHACCT , O_WRONLY | O_APPEND | O_CREAT,RW_ALL); 13754887Schin write(fd, (const char*)&sabuf, sizeof( sabuf )); 13764887Schin close( fd); 13774887Schin } 13784887Schin } 13794887Schin 13804887Schin /* 13814887Schin * Produce a pseudo-floating point representation 13824887Schin * with 3 bits base-8 exponent, 13 bits fraction. 13834887Schin */ 13844887Schin static int compress(register time_t t) 13854887Schin { 13864887Schin register int exp = 0, rund = 0; 13874887Schin 13884887Schin while (t >= 8192) 13894887Schin { 13904887Schin exp++; 13914887Schin rund = t&04; 13924887Schin t >>= 3; 13934887Schin } 13944887Schin if (rund) 13954887Schin { 13964887Schin t++; 13974887Schin if (t >= 8192) 13984887Schin { 13994887Schin t >>= 3; 14004887Schin exp++; 14014887Schin } 14024887Schin } 14034887Schin return((exp<<13) + t); 14044887Schin } 14054887Schin #endif /* SHOPT_ACCT */ 14064887Schin 14074887Schin 14084887Schin 14094887Schin /* 14104887Schin * add a pathcomponent to the path search list and eliminate duplicates 14114887Schin * and non-existing absolute paths. 14124887Schin */ 14134887Schin static Pathcomp_t *path_addcomp(Pathcomp_t *first, Pathcomp_t *old,const char *name, int flag) 14144887Schin { 14154887Schin register Pathcomp_t *pp, *oldpp; 14164887Schin int len, offset=staktell(); 14174887Schin if(!(flag&PATH_BFPATH)) 14184887Schin { 14194887Schin register const char *cp = name; 14204887Schin while(*cp && *cp!=':') 14214887Schin stakputc(*cp++); 14224887Schin len = staktell()-offset; 14234887Schin stakputc(0); 14244887Schin stakseek(offset); 14254887Schin name = (const char*)stakptr(offset); 14264887Schin } 14274887Schin else 14284887Schin len = strlen(name); 14294887Schin for(pp=first; pp; pp=pp->next) 14304887Schin { 14314887Schin if(memcmp(name,pp->name,len)==0 && (pp->name[len]==':' || pp->name[len]==0)) 14324887Schin { 14334887Schin pp->flags |= flag; 14344887Schin return(first); 14354887Schin } 14364887Schin } 1437*10898Sroland.mainz@nrubsig.org for(pp=first, oldpp=0; pp; oldpp=pp, pp=pp->next); 14384887Schin pp = newof((Pathcomp_t*)0,Pathcomp_t,1,len+1); 14394887Schin pp->refcount = 1; 14404887Schin memcpy((char*)(pp+1),name,len+1); 14414887Schin pp->name = (char*)(pp+1); 14424887Schin pp->len = len; 14434887Schin if(oldpp) 14444887Schin oldpp->next = pp; 14454887Schin else 14464887Schin first = pp; 14474887Schin pp->flags = flag; 1448*10898Sroland.mainz@nrubsig.org if(strcmp(name,SH_CMDLIB_DIR)==0) 14494887Schin { 1450*10898Sroland.mainz@nrubsig.org pp->dev = 1; 14514887Schin pp->flags |= PATH_BUILTIN_LIB; 14524887Schin pp->blib = malloc(4); 14534887Schin strcpy(pp->blib,LIBCMD); 14544887Schin return(first); 14554887Schin } 1456*10898Sroland.mainz@nrubsig.org if(old && ((flag&(PATH_PATH|PATH_SKIP))==PATH_PATH)) 14574887Schin path_chkpaths(first,old,pp,offset); 14584887Schin return(first); 14594887Schin } 14604887Schin 14614887Schin /* 14624887Schin * This function checks for the .paths file in directory in <pp> 14634887Schin * it assumes that the directory is on the stack at <offset> 14644887Schin */ 14654887Schin static int path_chkpaths(Pathcomp_t *first, Pathcomp_t* old,Pathcomp_t *pp, int offset) 14664887Schin { 14674887Schin struct stat statb; 14684887Schin int k,m,n,fd; 14694887Schin char *sp,*cp,*ep; 14704887Schin stakseek(offset+pp->len); 14714887Schin if(pp->len==1 && *stakptr(offset)=='/') 14724887Schin stakseek(offset); 14734887Schin stakputs("/.paths"); 14744887Schin if((fd=open(stakptr(offset),O_RDONLY))>=0) 14754887Schin { 14764887Schin fstat(fd,&statb); 14774887Schin n = statb.st_size; 14784887Schin stakseek(offset+pp->len+n+2); 14794887Schin sp = stakptr(offset+pp->len); 14804887Schin *sp++ = '/'; 14814887Schin n=read(fd,cp=sp,n); 14824887Schin sp[n] = 0; 14834887Schin close(fd); 14844887Schin for(ep=0; n--; cp++) 14854887Schin { 14864887Schin if(*cp=='=') 14874887Schin { 14884887Schin ep = cp+1; 14894887Schin continue; 14904887Schin } 14914887Schin else if(*cp!='\r' && *cp!='\n') 14924887Schin continue; 14934887Schin if(*sp=='#' || sp==cp) 14944887Schin { 14954887Schin sp = cp+1; 14964887Schin continue; 14974887Schin } 14984887Schin *cp = 0; 14994887Schin m = ep ? (ep-sp) : 0; 15004887Schin if(!m || m==6 && memcmp((void*)sp,(void*)"FPATH=",6)==0) 15014887Schin { 15024887Schin if(first) 15034887Schin { 15044887Schin char *ptr = stakptr(offset+pp->len+1); 15054887Schin if(ep) 15064887Schin strcpy(ptr,ep); 15074887Schin path_addcomp(first,old,stakptr(offset),PATH_FPATH|PATH_BFPATH); 15084887Schin } 15094887Schin } 15104887Schin else if(m==12 && memcmp((void*)sp,(void*)"BUILTIN_LIB=",12)==0) 15114887Schin { 15124887Schin if(!(pp->flags & PATH_BUILTIN_LIB)) 15134887Schin { 15144887Schin pp->flags |= PATH_BUILTIN_LIB; 15154887Schin if (*ep == '.' && !*(ep + 1)) 15164887Schin pp->flags |= PATH_STD_DIR; 15174887Schin else 15184887Schin { 15194887Schin k = strlen(ep)+1; 15204887Schin if (*ep != '/') 15214887Schin k += pp->len+1; 15224887Schin pp->blib = sp = malloc(k); 15234887Schin if (*ep != '/') 15244887Schin { 15254887Schin strcpy(pp->blib,pp->name); 15264887Schin sp += pp->len; 15274887Schin *sp++ = '/'; 15284887Schin } 15294887Schin strcpy(sp,ep); 15304887Schin } 15314887Schin } 15324887Schin } 15334887Schin else if(m) 15344887Schin { 15354887Schin pp->lib = (char*)malloc(cp-sp+pp->len+2); 15364887Schin memcpy((void*)pp->lib,(void*)sp,m); 15374887Schin memcpy((void*)&pp->lib[m],stakptr(offset),pp->len); 15384887Schin pp->lib[k=m+pp->len] = '/'; 15394887Schin strcpy((void*)&pp->lib[k+1],ep); 15404887Schin pathcanon(&pp->lib[m],0); 15414887Schin if(!first) 15424887Schin { 15434887Schin stakseek(0); 15444887Schin stakputs(pp->lib); 15454887Schin free((void*)pp->lib); 15464887Schin return(1); 15474887Schin } 15484887Schin } 15494887Schin sp = cp+1; 15504887Schin ep = 0; 15514887Schin } 15524887Schin } 15534887Schin return(0); 15544887Schin } 15554887Schin 15564887Schin 15574887Schin Pathcomp_t *path_addpath(Pathcomp_t *first, register const char *path,int type) 15584887Schin { 15594887Schin register const char *cp; 15604887Schin Pathcomp_t *old=0; 15614887Schin int offset = staktell(); 15624887Schin char *savptr; 15634887Schin 15644887Schin if(!path && type!=PATH_PATH) 15654887Schin return(first); 15664887Schin if(type!=PATH_FPATH) 15674887Schin { 15684887Schin old = first; 15694887Schin first = 0; 15704887Schin } 15714887Schin if(offset) 15724887Schin savptr = stakfreeze(0); 15734887Schin if(path) while(*(cp=path)) 15744887Schin { 15754887Schin if(*cp==':') 15764887Schin { 15774887Schin if(type!=PATH_FPATH) 15784887Schin first = path_addcomp(first,old,".",type); 15794887Schin while(*++path == ':'); 15804887Schin } 15814887Schin else 15824887Schin { 15834887Schin int c; 15844887Schin while(*path && *path!=':') 15854887Schin path++; 15864887Schin c = *path++; 15874887Schin first = path_addcomp(first,old,cp,type); 15884887Schin if(c==0) 15894887Schin break; 15904887Schin if(*path==0) 15914887Schin path--; 15924887Schin } 15934887Schin } 15944887Schin if(old) 15954887Schin { 15964887Schin if(!first && !path) 15974887Schin { 15984887Schin Pathcomp_t *pp = (Pathcomp_t*)old->shp->defpathlist; 15994887Schin if(!pp) 16004887Schin pp = defpath_init(old->shp); 16014887Schin first = path_dup(pp); 16024887Schin } 16034887Schin if(cp=(FPATHNOD)->nvalue.cp) 16044887Schin first = (void*)path_addpath((Pathcomp_t*)first,cp,PATH_FPATH); 16054887Schin path_delete(old); 16064887Schin } 16074887Schin if(offset) 16084887Schin stakset(savptr,offset); 16094887Schin else 16104887Schin stakseek(0); 16114887Schin return(first); 16124887Schin } 16134887Schin 16144887Schin /* 16154887Schin * duplicate the path give by <first> by incremented reference counts 16164887Schin */ 16174887Schin Pathcomp_t *path_dup(Pathcomp_t *first) 16184887Schin { 16194887Schin register Pathcomp_t *pp=first; 16204887Schin while(pp) 16214887Schin { 16224887Schin pp->refcount++; 16234887Schin pp = pp->next; 16244887Schin } 16254887Schin return(first); 16264887Schin } 16274887Schin 16284887Schin /* 16294887Schin * called whenever the directory is changed 16304887Schin */ 16314887Schin void path_newdir(Pathcomp_t *first) 16324887Schin { 16334887Schin register Pathcomp_t *pp=first, *next, *pq; 16344887Schin struct stat statb; 16354887Schin for(pp=first; pp; pp=pp->next) 16364887Schin { 16374887Schin pp->flags &= ~PATH_SKIP; 16384887Schin if(*pp->name=='/') 16394887Schin continue; 16404887Schin /* delete .paths component */ 16414887Schin if((next=pp->next) && (next->flags&PATH_BFPATH)) 16424887Schin { 16434887Schin pp->next = next->next; 16444887Schin if(--next->refcount<=0) 16454887Schin free((void*)next); 16464887Schin } 16474887Schin if(stat(pp->name,&statb)<0 || !S_ISDIR(statb.st_mode)) 16484887Schin { 16494887Schin pp->dev = 0; 16504887Schin pp->ino = 0; 16514887Schin continue; 16524887Schin } 16534887Schin pp->dev = statb.st_dev; 16544887Schin pp->ino = statb.st_ino; 16558462SApril.Chin@Sun.COM pp->mtime = statb.st_mtime; 16564887Schin for(pq=first;pq!=pp;pq=pq->next) 16574887Schin { 16584887Schin if(pp->ino==pq->ino && pp->dev==pq->dev) 16594887Schin pp->flags |= PATH_SKIP; 16604887Schin } 16614887Schin for(pq=pp;pq=pq->next;) 16624887Schin { 16634887Schin if(pp->ino==pq->ino && pp->dev==pq->dev) 16644887Schin pq->flags |= PATH_SKIP; 16654887Schin } 16664887Schin if((pp->flags&(PATH_PATH|PATH_SKIP))==PATH_PATH) 16674887Schin { 16684887Schin /* try to insert .paths component */ 16694887Schin int offset = staktell(); 16704887Schin stakputs(pp->name); 16714887Schin stakseek(offset); 16724887Schin next = pp->next; 16734887Schin pp->next = 0; 16744887Schin path_chkpaths(first,(Pathcomp_t*)0,pp,offset); 16754887Schin if(pp->next) 16764887Schin pp = pp->next; 16774887Schin pp->next = next; 16784887Schin } 16794887Schin } 16804887Schin #if 0 16814887Schin path_dump(first); 16824887Schin #endif 16834887Schin } 16844887Schin 16854887Schin Pathcomp_t *path_unsetfpath(Pathcomp_t *first) 16864887Schin { 16874887Schin register Pathcomp_t *pp=first, *old=0; 16888462SApril.Chin@Sun.COM Shell_t *shp = &sh; 16898462SApril.Chin@Sun.COM if(shp->fpathdict) 16908462SApril.Chin@Sun.COM { 16918462SApril.Chin@Sun.COM struct Ufunction *rp, *rpnext; 16928462SApril.Chin@Sun.COM for(rp=(struct Ufunction*)dtfirst(shp->fpathdict);rp;rp=rpnext) 16938462SApril.Chin@Sun.COM { 16948462SApril.Chin@Sun.COM rpnext = (struct Ufunction*)dtnext(shp->fpathdict,rp); 16958462SApril.Chin@Sun.COM if(rp->fdict) 16968462SApril.Chin@Sun.COM nv_delete(rp->np,rp->fdict,NV_NOFREE); 16978462SApril.Chin@Sun.COM rp->fdict = 0; 16988462SApril.Chin@Sun.COM } 16998462SApril.Chin@Sun.COM } 17004887Schin while(pp) 17014887Schin { 17024887Schin if((pp->flags&PATH_FPATH) && !(pp->flags&PATH_BFPATH)) 17034887Schin { 17044887Schin if(pp->flags&PATH_PATH) 17054887Schin pp->flags &= ~PATH_FPATH; 17064887Schin else 17074887Schin { 17084887Schin Pathcomp_t *ppsave=pp; 17094887Schin if(old) 17104887Schin old->next = pp->next; 17114887Schin else 17124887Schin first = pp->next; 17134887Schin pp = pp->next; 17144887Schin if(--ppsave->refcount<=0) 17154887Schin { 17164887Schin if(ppsave->lib) 17174887Schin free((void*)ppsave->lib); 17184887Schin free((void*)ppsave); 17194887Schin } 17204887Schin continue; 17214887Schin } 17224887Schin 17234887Schin } 17244887Schin old = pp; 17254887Schin pp = pp->next; 17264887Schin } 17274887Schin return(first); 17284887Schin } 17294887Schin 17304887Schin Pathcomp_t *path_dirfind(Pathcomp_t *first,const char *name,int c) 17314887Schin { 17324887Schin register Pathcomp_t *pp=first; 17334887Schin while(pp) 17344887Schin { 17354887Schin if(memcmp(name,pp->name,pp->len)==0 && name[pp->len]==c) 17364887Schin return(pp); 17374887Schin pp = pp->next; 17384887Schin } 17394887Schin return(0); 17404887Schin } 17414887Schin 17424887Schin /* 17434887Schin * get discipline for tracked alias 17444887Schin */ 17454887Schin static char *talias_get(Namval_t *np, Namfun_t *nvp) 17464887Schin { 17474887Schin Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp; 17484887Schin char *ptr; 17494887Schin if(!pp) 17504887Schin return(NULL); 17514887Schin path_nextcomp(pp,nv_name(np),pp); 17524887Schin ptr = stakfreeze(0); 17534887Schin return(ptr+PATH_OFFSET); 17544887Schin } 17554887Schin 17564887Schin static void talias_put(register Namval_t* np,const char *val,int flags,Namfun_t *fp) 17574887Schin { 17584887Schin if(!val && np->nvalue.cp) 17594887Schin { 17604887Schin Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp; 17614887Schin if(--pp->refcount<=0) 17624887Schin free((void*)pp); 17634887Schin } 17644887Schin nv_putv(np,val,flags,fp); 17654887Schin } 17664887Schin 17674887Schin static const Namdisc_t talias_disc = { 0, talias_put, talias_get }; 17684887Schin static Namfun_t talias_init = { &talias_disc, 1 }; 17694887Schin 17704887Schin /* 17714887Schin * set tracked alias node <np> to value <pp> 17724887Schin */ 17734887Schin void path_alias(register Namval_t *np,register Pathcomp_t *pp) 17744887Schin { 17754887Schin if(pp) 17764887Schin { 17774887Schin struct stat statb; 17784887Schin char *sp; 17794887Schin nv_offattr(np,NV_NOPRINT); 17804887Schin nv_stack(np,&talias_init); 17814887Schin np->nvalue.cp = (char*)pp; 17824887Schin pp->refcount++; 17834887Schin nv_setattr(np,NV_TAGGED|NV_NOFREE); 17844887Schin path_nextcomp(pp,nv_name(np),pp); 17854887Schin sp = stakptr(PATH_OFFSET); 17864887Schin if(sp && lstat(sp,&statb)>=0 && S_ISLNK(statb.st_mode)) 17874887Schin nv_setsize(np,statb.st_size+1); 17884887Schin else 17894887Schin nv_setsize(np,0); 17904887Schin } 17914887Schin else 17924887Schin nv_unset(np); 17934887Schin } 17944887Schin 1795