14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1982-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.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" 37*8462SApril.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 45*8462SApril.Chin@Sun.COM # if _lib_vfork 46*8462SApril.Chin@Sun.COM # include <ast_vfork.h> 47*8462SApril.Chin@Sun.COM # else 48*8462SApril.Chin@Sun.COM # define vfork() fork() 49*8462SApril.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); 604887Schin 614887Schin static const char *std_path; 624887Schin 634887Schin static int onstdpath(const char *name) 644887Schin { 654887Schin register const char *cp = std_path, *sp; 664887Schin if(cp) 674887Schin while(*cp) 684887Schin { 694887Schin for(sp=name; *sp && (*cp == *sp); sp++,cp++); 704887Schin if(*sp==0 && (*cp==0 || *cp==':')) 714887Schin return(1); 724887Schin while(*cp && *cp++!=':'); 734887Schin } 744887Schin return(0); 754887Schin } 764887Schin 77*8462SApril.Chin@Sun.COM static pid_t path_pfexecve(const char *path, char *argv[],char *const envp[],int spawn) 784887Schin { 794887Schin #if SHOPT_PFSH 80*8462SApril.Chin@Sun.COM pid_t pid; 814887Schin char resolvedpath[PATH_MAX + 1]; 82*8462SApril.Chin@Sun.COM if(spawn) 83*8462SApril.Chin@Sun.COM { 84*8462SApril.Chin@Sun.COM while((pid = vfork()) < 0) 85*8462SApril.Chin@Sun.COM _sh_fork(pid, 0, (int*)0); 86*8462SApril.Chin@Sun.COM if(pid) 87*8462SApril.Chin@Sun.COM return(pid); 88*8462SApril.Chin@Sun.COM } 894887Schin if(!sh_isoption(SH_PFSH)) 904887Schin return(execve(path, argv, envp)); 914887Schin /* Solaris implements realpath(3C) using the resolvepath(2) */ 924887Schin /* system call so we can save us to call access(2) first */ 934887Schin if (!realpath(path, resolvedpath)) 944887Schin return -1; 954887Schin 964887Schin /* we can exec the command directly instead of via pfexec(1) if */ 974887Schin /* there is a matching entry without attributes in exec_attr(4) */ 984887Schin if (sh.user && *sh.user) 994887Schin { 1004887Schin execattr_t *pf; 1014887Schin if(pf=getexecuser(sh.user, KV_COMMAND, resolvedpath, GET_ONE)) 1024887Schin { 1034887Schin if (!pf->attr || pf->attr->length == 0) 1044887Schin { 1054887Schin int r = execve(path, argv, envp); 1064887Schin free_execattr(pf); 1074887Schin return r; 1084887Schin } 1094887Schin free_execattr(pf); 1104887Schin } 1114887Schin else 1124887Schin { 1134887Schin errno = ENOENT; 1144887Schin return -1; 1154887Schin } 1164887Schin } 1174887Schin --argv; 1184887Schin argv[0] = argv[1]; 1194887Schin argv[1] = resolvedpath; 1204887Schin return(execve("/usr/bin/pfexec", argv, envp)); 1214887Schin #else 1224887Schin return(execve(path, argv, envp)); 1234887Schin #endif 1244887Schin } 1254887Schin 1264887Schin 127*8462SApril.Chin@Sun.COM static pid_t _spawnveg(const char *path, char* const argv[], char* const envp[], pid_t pgid) 1284887Schin { 1294887Schin int waitsafe = job.waitsafe; 130*8462SApril.Chin@Sun.COM pid_t pid; 1314887Schin job_lock(); 132*8462SApril.Chin@Sun.COM while(1) 133*8462SApril.Chin@Sun.COM { 134*8462SApril.Chin@Sun.COM sh_stats(STAT_SPAWN); 135*8462SApril.Chin@Sun.COM pid = spawnveg(path,argv,envp,pgid); 136*8462SApril.Chin@Sun.COM if(pid>=0 || errno!=EAGAIN) 137*8462SApril.Chin@Sun.COM break; 138*8462SApril.Chin@Sun.COM _sh_fork(pid, 0, (int*)0); 139*8462SApril.Chin@Sun.COM } 1404887Schin job.waitsafe = waitsafe; 1414887Schin job_unlock(); 1424887Schin return(pid); 1434887Schin } 1444887Schin /* 1454887Schin * used with command -x to run the command in multiple passes 1464887Schin * spawn is non-zero when invoked via spawn 1474887Schin * the exitval is set to the maximum for each execution 1484887Schin */ 1494887Schin static pid_t path_xargs(const char *path, char *argv[],char *const envp[], int spawn) 1504887Schin { 1514887Schin register char *cp, **av, **xv; 1524887Schin char **avlast= &argv[sh.xargmax], **saveargs=0; 1534887Schin char *const *ev; 1544887Schin long size, left; 1554887Schin int nlast=1,n,exitval=0; 1564887Schin pid_t pid; 1574887Schin if(sh.xargmin < 0) 1584887Schin return((pid_t)-1); 1594887Schin size = sh.lim.arg_max-1024; 1604887Schin for(ev=envp; cp= *ev; ev++) 1614887Schin size -= strlen(cp)-1; 1624887Schin for(av=argv; (cp= *av) && av< &argv[sh.xargmin]; av++) 1634887Schin size -= strlen(cp)-1; 1644887Schin for(av=avlast; cp= *av; av++,nlast++) 1654887Schin size -= strlen(cp)-1; 1664887Schin av = &argv[sh.xargmin]; 1674887Schin if(!spawn) 1684887Schin job_clear(); 1694887Schin sh.exitval = 0; 1704887Schin while(av<avlast) 1714887Schin { 1724887Schin for(xv=av,left=size; left>0 && av<avlast;) 1734887Schin left -= strlen(*av++)+1; 1744887Schin /* leave at least two for last */ 1754887Schin if(left<0 && (avlast-av)<2) 1764887Schin av--; 1774887Schin if(xv==&argv[sh.xargmin]) 1784887Schin { 1794887Schin n = nlast*sizeof(char*); 1804887Schin saveargs = (char**)malloc(n); 1814887Schin memcpy((void*)saveargs, (void*)av, n); 1824887Schin memcpy((void*)av,(void*)avlast,n); 1834887Schin } 1844887Schin else 1854887Schin { 1864887Schin for(n=sh.xargmin; xv < av; xv++) 1874887Schin argv[n++] = *xv; 1884887Schin for(xv=avlast; cp= *xv; xv++) 1894887Schin argv[n++] = cp; 1904887Schin argv[n] = 0; 1914887Schin } 1924887Schin if(saveargs || av<avlast || (exitval && !spawn)) 1934887Schin { 1944887Schin if((pid=_spawnveg(path,argv,envp,0)) < 0) 1954887Schin return(-1); 1964887Schin job_post(pid,0); 1974887Schin job_wait(pid); 1984887Schin if(sh.exitval>exitval) 1994887Schin exitval = sh.exitval; 2004887Schin if(saveargs) 2014887Schin { 2024887Schin memcpy((void*)av,saveargs,n); 2034887Schin free((void*)saveargs); 2044887Schin saveargs = 0; 2054887Schin } 2064887Schin } 2074887Schin else if(spawn && !sh_isoption(SH_PFSH)) 2084887Schin { 2094887Schin sh.xargexit = exitval; 2104887Schin return(_spawnveg(path,argv,envp,spawn>>1)); 2114887Schin } 2124887Schin else 213*8462SApril.Chin@Sun.COM return(path_pfexecve(path,argv,envp,spawn)); 2144887Schin } 2154887Schin if(!spawn) 2164887Schin exit(exitval); 2174887Schin return((pid_t)-1); 2184887Schin } 2194887Schin 2204887Schin /* 2214887Schin * make sure PWD is set up correctly 2224887Schin * Return the present working directory 2234887Schin * Invokes getcwd() if flag==0 and if necessary 2244887Schin * Sets the PWD variable to this value 2254887Schin */ 2264887Schin char *path_pwd(int flag) 2274887Schin { 2284887Schin register char *cp; 2294887Schin register char *dfault = (char*)e_dot; 2304887Schin register int count = 0; 2314887Schin Shell_t *shp = &sh; 2324887Schin if(shp->pwd) 2334887Schin return((char*)shp->pwd); 2344887Schin while(1) 2354887Schin { 2364887Schin /* try from lowest to highest */ 2374887Schin switch(count++) 2384887Schin { 2394887Schin case 0: 2404887Schin cp = nv_getval(PWDNOD); 2414887Schin break; 2424887Schin case 1: 2434887Schin cp = nv_getval(HOME); 2444887Schin break; 2454887Schin case 2: 2464887Schin cp = "/"; 2474887Schin break; 2484887Schin case 3: 2494887Schin cp = (char*)e_crondir; 2504887Schin if(flag) /* skip next case when non-zero flag */ 2514887Schin ++count; 2524887Schin break; 2534887Schin case 4: 2544887Schin { 2554887Schin if(cp=getcwd(NIL(char*),0)) 2564887Schin { 2574887Schin nv_offattr(PWDNOD,NV_NOFREE); 2584887Schin nv_unset(PWDNOD); 2594887Schin PWDNOD->nvalue.cp = cp; 2604887Schin goto skip; 2614887Schin } 2624887Schin break; 2634887Schin } 2644887Schin case 5: 2654887Schin return(dfault); 2664887Schin } 2674887Schin if(cp && *cp=='/' && test_inode(cp,e_dot)) 2684887Schin break; 2694887Schin } 2704887Schin if(count>1) 2714887Schin { 2724887Schin nv_offattr(PWDNOD,NV_NOFREE); 2734887Schin nv_putval(PWDNOD,cp,NV_RDONLY); 2744887Schin } 2754887Schin skip: 2764887Schin nv_onattr(PWDNOD,NV_NOFREE|NV_EXPORT); 2774887Schin shp->pwd = (char*)(PWDNOD->nvalue.cp); 2784887Schin return(cp); 2794887Schin } 2804887Schin 2814887Schin static void free_bltin(Namval_t *np,void *data) 2824887Schin { 2834887Schin register Pathcomp_t *pp= (Pathcomp_t*)data; 2844887Schin if(pp->flags&PATH_STD_DIR) 2854887Schin { 2864887Schin int offset=staktell();; 2874887Schin if(strcmp(pp->name,"/bin")==0 || memcmp(pp->name,np->nvname,pp->len) || np->nvname[pp->len]!='/') 2884887Schin return; 2894887Schin stakputs("/bin"); 2904887Schin stakputs(np->nvname+pp->len+1); 2914887Schin stakputc(0); 2924887Schin sh_addbuiltin(stakptr(offset),np->nvalue.bfp,NiL); 2934887Schin stakseek(offset); 2944887Schin return; 2954887Schin } 2964887Schin if((void*)np->nvenv==pp->bltin_lib) 297*8462SApril.Chin@Sun.COM nv_delete(np,sh_bltin_tree(),NV_NOFREE); 2984887Schin } 2994887Schin 3004887Schin /* 3014887Schin * delete current Pathcomp_t structure 3024887Schin */ 3034887Schin void path_delete(Pathcomp_t *first) 3044887Schin { 3054887Schin register Pathcomp_t *pp=first, *old=0, *ppnext; 3064887Schin while(pp) 3074887Schin { 3084887Schin ppnext = pp->next; 3094887Schin if(--pp->refcount<=0) 3104887Schin { 3114887Schin if(pp->lib) 3124887Schin free((void*)pp->lib); 3134887Schin if(pp->blib) 3144887Schin free((void*)pp->blib); 3154887Schin if(pp->bltin_lib || (pp->flags&PATH_STD_DIR)) 3164887Schin { 3174887Schin nv_scan(sh_bltin_tree(),free_bltin,pp,0,0); 318*8462SApril.Chin@Sun.COM #if SHOPT_DYNAMIC 3194887Schin if(pp->bltin_lib) 3204887Schin dlclose(pp->bltin_lib); 321*8462SApril.Chin@Sun.COM #endif /* SHOPT_DYNAMIC */ 3224887Schin } 3234887Schin free((void*)pp); 3244887Schin if(old) 3254887Schin old->next = ppnext; 3264887Schin } 3274887Schin else 3284887Schin old = pp; 3294887Schin pp = ppnext; 3304887Schin } 3314887Schin } 3324887Schin 3334887Schin /* 3344887Schin * returns library variable from .paths 3354887Schin * The value might be returned on the stack overwriting path 3364887Schin */ 3374887Schin static char *path_lib(Pathcomp_t *pp, char *path) 3384887Schin { 3394887Schin register char *last = strrchr(path,'/'); 3404887Schin register int r; 3414887Schin struct stat statb; 3424887Schin if(last) 3434887Schin *last = 0; 3444887Schin else 3454887Schin path = "."; 3464887Schin r = stat(path,&statb); 3474887Schin if(last) 3484887Schin *last = '/'; 3494887Schin if(r>=0) 3504887Schin { 3514887Schin Pathcomp_t pcomp; 3524887Schin char save[8]; 3534887Schin for( ;pp; pp=pp->next) 3544887Schin { 355*8462SApril.Chin@Sun.COM if(pp->ino==statb.st_ino && pp->dev==statb.st_dev && pp->mtime==statb.st_mtime) 3564887Schin return(pp->lib); 3574887Schin } 3584887Schin pcomp.len = 0; 3594887Schin if(last) 3604887Schin pcomp.len = last-path; 3614887Schin memcpy((void*)save, (void*)stakptr(PATH_OFFSET+pcomp.len),sizeof(save)); 3624887Schin if(path_chkpaths((Pathcomp_t*)0,(Pathcomp_t*)0,&pcomp,PATH_OFFSET)) 3634887Schin return(stakfreeze(1)); 3644887Schin memcpy((void*)stakptr(PATH_OFFSET+pcomp.len),(void*)save,sizeof(save)); 3654887Schin } 3664887Schin return(0); 3674887Schin } 3684887Schin 3694887Schin #if 0 3704887Schin void path_dump(register Pathcomp_t *pp) 3714887Schin { 3724887Schin sfprintf(sfstderr,"dump\n"); 3734887Schin while(pp) 3744887Schin { 3754887Schin sfprintf(sfstderr,"pp=%x dev=%d ino=%d len=%d flags=%o name=%.*s\n", 3764887Schin pp,pp->dev,pp->ino,pp->len,pp->flags,pp->len,pp->name); 3774887Schin pp = pp->next; 3784887Schin } 3794887Schin } 3804887Schin #endif 3814887Schin 3824887Schin /* 3834887Schin * write the next path to search on the current stack 3844887Schin * if last is given, all paths that come before <last> are skipped 3854887Schin * the next pathcomp is returned. 3864887Schin */ 3874887Schin Pathcomp_t *path_nextcomp(register Pathcomp_t *pp, const char *name, Pathcomp_t *last) 3884887Schin { 3894887Schin stakseek(PATH_OFFSET); 3904887Schin if(*name=='/') 3914887Schin pp = 0; 3924887Schin else 3934887Schin { 3944887Schin for(;pp && pp!=last;pp=pp->next) 3954887Schin { 3964887Schin if(pp->flags&PATH_SKIP) 3974887Schin continue; 3984887Schin if(!last || *pp->name!='/') 3994887Schin break; 4004887Schin } 4014887Schin if(!pp) /* this should not happen */ 4024887Schin pp = last; 4034887Schin } 4044887Schin if(pp && (pp->name[0]!='.' || pp->name[1])) 4054887Schin { 4064887Schin if(*pp->name!='/') 4074887Schin { 4084887Schin stakputs(path_pwd(1)); 4094887Schin if(*stakptr(staktell()-1)!='/') 4104887Schin stakputc('/'); 4114887Schin } 4124887Schin stakwrite(pp->name,pp->len); 4134887Schin if(pp->name[pp->len-1]!='/') 4144887Schin stakputc('/'); 4154887Schin } 4164887Schin stakputs(name); 4174887Schin stakputc(0); 4184887Schin while(pp && pp!=last && (pp=pp->next)) 4194887Schin { 4204887Schin if(!(pp->flags&PATH_SKIP)) 4214887Schin return(pp); 4224887Schin } 4234887Schin return((Pathcomp_t*)0); 4244887Schin } 4254887Schin 4264887Schin static Pathcomp_t* defpath_init(Shell_t *shp) 4274887Schin { 4284887Schin Pathcomp_t *pp = (void*)path_addpath((Pathcomp_t*)0,(std_path),PATH_PATH); 4294887Schin if(shp->defpathlist = (void*)pp) 4304887Schin pp->shp = shp; 4314887Schin return(pp); 4324887Schin } 4334887Schin 4344887Schin static void path_init(Shell_t *shp) 4354887Schin { 4364887Schin const char *val; 4374887Schin Pathcomp_t *pp; 4384887Schin if(!std_path && !(std_path=astconf("PATH",NIL(char*),NIL(char*)))) 4394887Schin std_path = e_defpath; 440*8462SApril.Chin@Sun.COM if(val=sh_scoped(shp,(PATHNOD))->nvalue.cp) 4414887Schin { 4424887Schin pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_PATH); 4434887Schin if(shp->pathlist = (void*)pp) 4444887Schin pp->shp = shp; 4454887Schin } 4464887Schin else 4474887Schin { 4484887Schin if(!(pp=(Pathcomp_t*)shp->defpathlist)) 4494887Schin pp = defpath_init(shp); 4504887Schin shp->pathlist = (void*)path_dup(pp); 4514887Schin } 452*8462SApril.Chin@Sun.COM if(val=sh_scoped(shp,(FPATHNOD))->nvalue.cp) 4534887Schin { 4544887Schin pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_FPATH); 4554887Schin if(shp->pathlist = (void*)pp) 4564887Schin pp->shp = shp; 4574887Schin } 4584887Schin } 4594887Schin 4604887Schin /* 4614887Schin * returns that pathlist to search 4624887Schin */ 4634887Schin Pathcomp_t *path_get(register const char *name) 4644887Schin { 4654887Schin register Shell_t *shp = &sh; 4664887Schin register Pathcomp_t *pp=0; 4674887Schin if(*name && strchr(name,'/')) 4684887Schin return(0); 4694887Schin if(!sh_isstate(SH_DEFPATH)) 4704887Schin { 4714887Schin if(!shp->pathlist) 4724887Schin path_init(shp); 4734887Schin pp = (Pathcomp_t*)shp->pathlist; 4744887Schin } 4754887Schin if(!pp && (!(PATHNOD)->nvalue.cp) || sh_isstate(SH_DEFPATH)) 4764887Schin { 4774887Schin if(!(pp=(Pathcomp_t*)shp->defpathlist)) 4784887Schin pp = defpath_init(shp); 4794887Schin } 4804887Schin return(pp); 4814887Schin } 4824887Schin 4834887Schin /* 4844887Schin * open file corresponding to name using path give by <pp> 4854887Schin */ 4864887Schin static int path_opentype(const char *name, register Pathcomp_t *pp, int fun) 4874887Schin { 4884887Schin register int fd= -1; 4894887Schin struct stat statb; 4904887Schin Pathcomp_t *oldpp; 4914887Schin Shell_t *shp; 4924887Schin if(pp) 4934887Schin shp = pp->shp; 4944887Schin else 4954887Schin { 4964887Schin shp = sh_getinterp(); 4974887Schin if(!shp->pathlist) 4984887Schin path_init(shp); 4994887Schin } 5004887Schin if(!fun && strchr(name,'/')) 5014887Schin { 5024887Schin if(sh_isoption(SH_RESTRICTED)) 5034887Schin errormsg(SH_DICT,ERROR_exit(1),e_restricted,name); 5044887Schin } 5054887Schin do 5064887Schin { 5074887Schin pp = path_nextcomp(oldpp=pp,name,0); 5084887Schin while(oldpp && (oldpp->flags&PATH_SKIP)) 5094887Schin oldpp = oldpp->next; 5104887Schin if(fun && (!oldpp || !(oldpp->flags&PATH_FPATH))) 5114887Schin continue; 5124887Schin if((fd = sh_open(path_relative(stakptr(PATH_OFFSET)),O_RDONLY,0)) >= 0) 5134887Schin { 5144887Schin if(fstat(fd,&statb)<0 || S_ISDIR(statb.st_mode)) 5154887Schin { 5164887Schin errno = EISDIR; 5174887Schin sh_close(fd); 5184887Schin fd = -1; 5194887Schin } 5204887Schin } 5214887Schin } 5224887Schin while( fd<0 && pp); 5234887Schin if(fd>=0 && (fd = sh_iomovefd(fd)) > 0) 5244887Schin { 5254887Schin fcntl(fd,F_SETFD,FD_CLOEXEC); 5264887Schin shp->fdstatus[fd] |= IOCLEX; 5274887Schin } 5284887Schin return(fd); 5294887Schin } 5304887Schin 5314887Schin /* 5324887Schin * open file corresponding to name using path give by <pp> 5334887Schin */ 5344887Schin int path_open(const char *name, register Pathcomp_t *pp) 5354887Schin { 5364887Schin return(path_opentype(name,pp,0)); 5374887Schin } 5384887Schin 5394887Schin /* 5404887Schin * given a pathname return the base name 5414887Schin */ 5424887Schin 5434887Schin char *path_basename(register const char *name) 5444887Schin { 5454887Schin register const char *start = name; 5464887Schin while (*name) 5474887Schin if ((*name++ == '/') && *name) /* don't trim trailing / */ 5484887Schin start = name; 5494887Schin return ((char*)start); 5504887Schin } 5514887Schin 5524887Schin char *path_fullname(const char *name) 5534887Schin { 5544887Schin int len=strlen(name)+1,dirlen=0; 5554887Schin char *path,*pwd; 5564887Schin if(*name!='/') 5574887Schin { 5584887Schin pwd = path_pwd(1); 5594887Schin dirlen = strlen(pwd)+1; 5604887Schin } 5614887Schin path = (char*)malloc(len+dirlen); 5624887Schin if(dirlen) 5634887Schin { 5644887Schin memcpy((void*)path,(void*)pwd,dirlen); 5654887Schin path[dirlen-1] = '/'; 5664887Schin } 5674887Schin memcpy((void*)&path[dirlen],(void*)name,len); 5684887Schin pathcanon(path,0); 5694887Schin return(path); 5704887Schin } 5714887Schin 5724887Schin /* 5734887Schin * load functions from file <fno> 5744887Schin */ 5754887Schin static void funload(Shell_t *shp,int fno, const char *name) 5764887Schin { 577*8462SApril.Chin@Sun.COM char *pname,*oldname=shp->st.filename, buff[IOBSIZE+1]; 578*8462SApril.Chin@Sun.COM Namval_t *np; 579*8462SApril.Chin@Sun.COM struct Ufunction *rp; 580*8462SApril.Chin@Sun.COM int savestates = sh_getstate(), oldload=shp->funload; 581*8462SApril.Chin@Sun.COM pname = path_fullname(stakptr(PATH_OFFSET)); 582*8462SApril.Chin@Sun.COM if(shp->fpathdict && (rp = dtmatch(shp->fpathdict,(void*)pname))) 583*8462SApril.Chin@Sun.COM { 584*8462SApril.Chin@Sun.COM do 585*8462SApril.Chin@Sun.COM { 586*8462SApril.Chin@Sun.COM if((np = dtsearch(shp->fun_tree,rp->np)) && is_afunction(np)) 587*8462SApril.Chin@Sun.COM { 588*8462SApril.Chin@Sun.COM if(np->nvalue.rp) 589*8462SApril.Chin@Sun.COM np->nvalue.rp->fdict = 0; 590*8462SApril.Chin@Sun.COM nv_delete(np,shp->fun_tree,NV_NOFREE); 591*8462SApril.Chin@Sun.COM } 592*8462SApril.Chin@Sun.COM dtinsert(shp->fun_tree,rp->np); 593*8462SApril.Chin@Sun.COM rp->fdict = shp->fun_tree; 594*8462SApril.Chin@Sun.COM } 595*8462SApril.Chin@Sun.COM while((rp=dtnext(shp->fpathdict,rp)) && strcmp(pname,rp->fname)==0); 596*8462SApril.Chin@Sun.COM return; 597*8462SApril.Chin@Sun.COM } 5984887Schin sh_onstate(SH_NOLOG); 5994887Schin sh_onstate(SH_NOALIAS); 6004887Schin shp->readscript = (char*)name; 601*8462SApril.Chin@Sun.COM shp->st.filename = pname; 602*8462SApril.Chin@Sun.COM shp->funload = 1; 6034887Schin error_info.line = 0; 6044887Schin sh_eval(sfnew(NIL(Sfio_t*),buff,IOBSIZE,fno,SF_READ),0); 6054887Schin shp->readscript = 0; 6064887Schin free((void*)shp->st.filename); 607*8462SApril.Chin@Sun.COM shp->funload = oldload; 6084887Schin shp->st.filename = oldname; 6094887Schin sh_setstate(savestates); 6104887Schin } 6114887Schin 6124887Schin /* 6134887Schin * do a path search and track alias if requested 6144887Schin * if flag is 0, or if name not found, then try autoloading function 615*8462SApril.Chin@Sun.COM * if flag==2 or 3, returns 1 if name found on FPATH 616*8462SApril.Chin@Sun.COM * if flag==3 no tracked alias will be set 6174887Schin * returns 1, if function was autoloaded. 618*8462SApril.Chin@Sun.COM * If oldpp is not NULL, it will contain a pointer to the path component 619*8462SApril.Chin@Sun.COM * where it was found. 6204887Schin */ 6214887Schin 622*8462SApril.Chin@Sun.COM int path_search(register const char *name,Pathcomp_t **oldpp, int flag) 6234887Schin { 6244887Schin register Namval_t *np; 6254887Schin register int fno; 6264887Schin Pathcomp_t *pp=0; 6274887Schin Shell_t *shp = &sh; 6284887Schin if(name && strchr(name,'/')) 6294887Schin { 6304887Schin stakseek(PATH_OFFSET); 6314887Schin stakputs(name); 6324887Schin if(canexecute(stakptr(PATH_OFFSET),0)<0) 6334887Schin { 6344887Schin *stakptr(PATH_OFFSET) = 0; 6354887Schin return(0); 6364887Schin } 6374887Schin if(*name=='/') 6384887Schin return(1); 6394887Schin stakseek(PATH_OFFSET); 6404887Schin stakputs(path_pwd(1)); 6414887Schin stakputc('/'); 6424887Schin stakputs(name); 6434887Schin stakputc(0); 6444887Schin return(0); 6454887Schin } 6464887Schin if(sh_isstate(SH_DEFPATH)) 6474887Schin { 6484887Schin if(!shp->defpathlist) 6494887Schin defpath_init(shp); 6504887Schin } 6514887Schin else if(!shp->pathlist) 6524887Schin path_init(shp); 6534887Schin if(flag) 6544887Schin { 655*8462SApril.Chin@Sun.COM pp = path_absolute(name,oldpp?*oldpp:NIL(Pathcomp_t*)); 656*8462SApril.Chin@Sun.COM if(oldpp) 657*8462SApril.Chin@Sun.COM *oldpp = pp; 6584887Schin if(!pp && (np=nv_search(name,sh.fun_tree,HASH_NOSCOPE))&&np->nvalue.ip) 6594887Schin return(1); 6604887Schin if(!pp) 6614887Schin *stakptr(PATH_OFFSET) = 0; 6624887Schin } 6634887Schin if(flag==0 || !pp || (pp->flags&PATH_FPATH)) 6644887Schin { 6654887Schin if(!pp) 6664887Schin pp=sh_isstate(SH_DEFPATH)?shp->defpathlist:shp->pathlist; 6674887Schin if(pp && strmatch(name,e_alphanum) && (fno=path_opentype(name,pp,1))>=0) 6684887Schin { 6694887Schin if(flag==2) 6704887Schin { 6714887Schin sh_close(fno); 6724887Schin return(1); 6734887Schin } 6744887Schin funload(shp,fno,name); 6754887Schin return(1); 6764887Schin } 6774887Schin *stakptr(PATH_OFFSET) = 0; 6784887Schin return(0); 6794887Schin } 680*8462SApril.Chin@Sun.COM else if(pp && !sh_isstate(SH_DEFPATH) && *name!='/' && flag<3) 6814887Schin { 6824887Schin if(np=nv_search(name,shp->track_tree,NV_ADD)) 6834887Schin path_alias(np,pp); 6844887Schin } 6854887Schin return(0); 6864887Schin } 6874887Schin 6884887Schin 6894887Schin /* 6904887Schin * do a path search and find the full pathname of file name 6914887Schin */ 6924887Schin 693*8462SApril.Chin@Sun.COM Pathcomp_t *path_absolute(register const char *name, Pathcomp_t *pp) 6944887Schin { 6954887Schin register int f,isfun; 6964887Schin int noexec=0; 697*8462SApril.Chin@Sun.COM Pathcomp_t *oldpp; 6984887Schin Shell_t *shp = &sh; 6994887Schin Namval_t *np; 7004887Schin shp->path_err = ENOENT; 701*8462SApril.Chin@Sun.COM if(!pp && !(pp=path_get(""))) 7024887Schin return(0); 7034887Schin shp->path_err = 0; 7044887Schin while(1) 7054887Schin { 7064887Schin sh_sigcheck(); 7074887Schin isfun = (pp->flags&PATH_FPATH); 7084887Schin if(oldpp=pp) 7094887Schin pp = path_nextcomp(pp,name,0); 7104887Schin if(!isfun && !sh_isoption(SH_RESTRICTED)) 7114887Schin { 712*8462SApril.Chin@Sun.COM if(*stakptr(PATH_OFFSET)=='/' && nv_search(stakptr(PATH_OFFSET),sh.bltin_tree,0)) 7134887Schin return(oldpp); 714*8462SApril.Chin@Sun.COM #if SHOPT_DYNAMIC 7154887Schin if(oldpp->blib) 7164887Schin { 7174887Schin typedef int (*Fptr_t)(int, char*[], void*); 7184887Schin Fptr_t addr; 7194887Schin int n = staktell(); 7204887Schin char *cp; 7214887Schin stakputs("b_"); 7224887Schin stakputs(name); 7234887Schin stakputc(0); 7244887Schin if(!oldpp->bltin_lib) 7254887Schin { 7264887Schin if(cp = strrchr(oldpp->blib,'/')) 7274887Schin cp++; 7284887Schin else 7294887Schin cp = oldpp->blib; 7304887Schin if(strcmp(cp,LIBCMD)==0 && (addr=(Fptr_t)dlllook((void*)0,stakptr(n)))) 7314887Schin { 732*8462SApril.Chin@Sun.COM if((np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL)) && nv_isattr(np,NV_BLTINOPT)) 733*8462SApril.Chin@Sun.COM return(oldpp); 7344887Schin } 7354887Schin #if (_AST_VERSION>=20040404) 7364887Schin if (oldpp->bltin_lib = dllplug(SH_ID, oldpp->blib, NiL, RTLD_LAZY, NiL, 0)) 7374887Schin #else 7384887Schin if (oldpp->bltin_lib = dllfind(oldpp->blib, NiL, RTLD_LAZY, NiL, 0)) 7394887Schin #endif 7404887Schin sh_addlib(oldpp->bltin_lib); 7414887Schin } 7424887Schin if((addr=(Fptr_t)dlllook(oldpp->bltin_lib,stakptr(n))) && 7434887Schin (!(np = sh_addbuiltin(stakptr(PATH_OFFSET),NiL,NiL)) || np->nvalue.bfp!=addr) && 7444887Schin (np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL))) 7454887Schin { 7464887Schin np->nvenv = oldpp->bltin_lib; 7474887Schin return(oldpp); 7484887Schin } 7494887Schin } 750*8462SApril.Chin@Sun.COM #endif /* SHOPT_DYNAMIC */ 7514887Schin } 752*8462SApril.Chin@Sun.COM sh_stats(STAT_PATHS); 7534887Schin f = canexecute(stakptr(PATH_OFFSET),isfun); 7544887Schin if(isfun && f>=0) 7554887Schin { 7564887Schin nv_onattr(nv_open(name,shp->fun_tree,NV_NOARRAY|NV_IDENT|NV_NOSCOPE),NV_LTOU|NV_FUNCTION); 7574887Schin close(f); 7584887Schin f = -1; 7594887Schin return(0); 7604887Schin } 7614887Schin else if(f>=0 && (oldpp->flags & PATH_STD_DIR)) 7624887Schin { 763*8462SApril.Chin@Sun.COM int n = staktell(); 7644887Schin stakputs("/bin/"); 7654887Schin stakputs(name); 7664887Schin stakputc(0); 767*8462SApril.Chin@Sun.COM np = nv_search(stakptr(n),sh.bltin_tree,0); 768*8462SApril.Chin@Sun.COM stakseek(n); 7694887Schin if(np) 7704887Schin { 771*8462SApril.Chin@Sun.COM n = np->nvflag; 772*8462SApril.Chin@Sun.COM np = sh_addbuiltin(stakptr(PATH_OFFSET),np->nvalue.bfp,nv_context(np)); 773*8462SApril.Chin@Sun.COM np->nvflag = n; 7744887Schin } 7754887Schin } 7764887Schin if(!pp || f>=0) 7774887Schin break; 7784887Schin if(errno!=ENOENT) 7794887Schin noexec = errno; 7804887Schin } 7814887Schin if(f<0) 7824887Schin { 783*8462SApril.Chin@Sun.COM shp->path_err = (noexec?noexec:ENOENT); 7844887Schin return(0); 7854887Schin } 7864887Schin stakputc(0); 7874887Schin return(oldpp); 7884887Schin } 7894887Schin 7904887Schin /* 7914887Schin * returns 0 if path can execute 7924887Schin * sets exec_err if file is found but can't be executable 7934887Schin */ 7944887Schin #undef S_IXALL 7954887Schin #ifdef S_IXUSR 7964887Schin # define S_IXALL (S_IXUSR|S_IXGRP|S_IXOTH) 7974887Schin #else 7984887Schin # ifdef S_IEXEC 7994887Schin # define S_IXALL (S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6)) 8004887Schin # else 8014887Schin # define S_IXALL 0111 8024887Schin # endif /*S_EXEC */ 8034887Schin #endif /* S_IXUSR */ 8044887Schin 8054887Schin static int canexecute(register char *path, int isfun) 8064887Schin { 8074887Schin struct stat statb; 8084887Schin register int fd=0; 8094887Schin path = path_relative(path); 8104887Schin if(isfun) 8114887Schin { 8124887Schin if((fd=open(path,O_RDONLY,0))<0 || fstat(fd,&statb)<0) 8134887Schin goto err; 8144887Schin } 8154887Schin else if(stat(path,&statb) < 0) 8164887Schin { 8174887Schin #if _WINIX 8184887Schin /* check for .exe or .bat suffix */ 8194887Schin char *cp; 8204887Schin if(errno==ENOENT && (!(cp=strrchr(path,'.')) || strlen(cp)>4 || strchr(cp,'/'))) 8214887Schin { 8224887Schin int offset = staktell()-1; 8234887Schin stakseek(offset); 8244887Schin stakputs(".bat"); 8254887Schin path = stakptr(PATH_OFFSET); 8264887Schin if(stat(path,&statb) < 0) 8274887Schin { 8284887Schin if(errno!=ENOENT) 8294887Schin goto err; 8304887Schin memcpy(stakptr(offset),".sh",4); 8314887Schin if(stat(path,&statb) < 0) 8324887Schin goto err; 8334887Schin } 8344887Schin } 8354887Schin else 8364887Schin #endif /* _WINIX */ 8374887Schin goto err; 8384887Schin } 8394887Schin errno = EPERM; 8404887Schin if(S_ISDIR(statb.st_mode)) 8414887Schin errno = EISDIR; 8424887Schin else if((statb.st_mode&S_IXALL)==S_IXALL || sh_access(path,X_OK)>=0) 8434887Schin return(fd); 8444887Schin if(isfun && fd>=0) 8454887Schin sh_close(fd); 8464887Schin err: 8474887Schin return(-1); 8484887Schin } 8494887Schin 8504887Schin /* 8514887Schin * Return path relative to present working directory 8524887Schin */ 8534887Schin 8544887Schin char *path_relative(register const char* file) 8554887Schin { 8564887Schin register const char *pwd; 8574887Schin register const char *fp = file; 8584887Schin /* can't relpath when sh.pwd not set */ 8594887Schin if(!(pwd=sh.pwd)) 8604887Schin return((char*)fp); 8614887Schin while(*pwd==*fp) 8624887Schin { 8634887Schin if(*pwd++==0) 8644887Schin return((char*)e_dot); 8654887Schin fp++; 8664887Schin } 8674887Schin if(*pwd==0 && *fp == '/') 8684887Schin { 8694887Schin while(*++fp=='/'); 8704887Schin if(*fp) 8714887Schin return((char*)fp); 8724887Schin return((char*)e_dot); 8734887Schin } 8744887Schin return((char*)file); 8754887Schin } 8764887Schin 8774887Schin void path_exec(register const char *arg0,register char *argv[],struct argnod *local) 8784887Schin { 8794887Schin char **envp; 8804887Schin const char *opath; 8814887Schin Pathcomp_t *libpath, *pp=0; 8824887Schin Shell_t *shp = &sh; 8834887Schin int slash=0; 8844887Schin nv_setlist(local,NV_EXPORT|NV_IDENT|NV_ASSIGN); 8854887Schin envp = sh_envgen(); 8864887Schin if(strchr(arg0,'/')) 8874887Schin { 8884887Schin slash=1; 8894887Schin /* name containing / not allowed for restricted shell */ 8904887Schin if(sh_isoption(SH_RESTRICTED)) 8914887Schin errormsg(SH_DICT,ERROR_exit(1),e_restricted,arg0); 8924887Schin } 8934887Schin else 8944887Schin pp=path_get(arg0); 8954887Schin shp->path_err= ENOENT; 8964887Schin sfsync(NIL(Sfio_t*)); 8974887Schin timerdel(NIL(void*)); 8984887Schin /* find first path that has a library component */ 8994887Schin if(pp || slash) do 9004887Schin { 9014887Schin sh_sigcheck(); 9024887Schin if(libpath=pp) 9034887Schin { 9044887Schin pp = path_nextcomp(pp,arg0,0); 9054887Schin opath = stakfreeze(1)+PATH_OFFSET; 9064887Schin } 9074887Schin else 9084887Schin opath = arg0; 9094887Schin path_spawn(opath,argv,envp,libpath,0); 9104887Schin while(pp && (pp->flags&PATH_FPATH)) 9114887Schin pp = path_nextcomp(pp,arg0,0); 9124887Schin } 9134887Schin while(pp); 9144887Schin /* force an exit */ 9154887Schin ((struct checkpt*)shp->jmplist)->mode = SH_JMPEXIT; 9164887Schin if((errno=shp->path_err)==ENOENT) 9174887Schin errormsg(SH_DICT,ERROR_exit(ERROR_NOENT),e_found,arg0); 9184887Schin else 9194887Schin errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,arg0); 9204887Schin } 9214887Schin 9224887Schin pid_t path_spawn(const char *opath,register char **argv, char **envp, Pathcomp_t *libpath, int spawn) 9234887Schin { 9244887Schin Shell_t *shp = sh_getinterp(); 9254887Schin register char *path; 9264887Schin char **xp=0, *xval, *libenv = (libpath?libpath->lib:0); 9274887Schin Namval_t* np; 9284887Schin char *s, *v; 9294887Schin int r, n; 9304887Schin pid_t pid= -1; 9314887Schin /* leave room for inserting _= pathname in environment */ 9324887Schin envp--; 9334887Schin #if _lib_readlink 9344887Schin /* save original pathname */ 9354887Schin stakseek(PATH_OFFSET); 9364887Schin stakputs(opath); 9374887Schin opath = stakfreeze(1)+PATH_OFFSET; 9384887Schin np=nv_search(argv[0],shp->track_tree,0); 9394887Schin while(libpath && !libpath->lib) 9404887Schin libpath=libpath->next; 9414887Schin if(libpath && (!np || nv_size(np)>0)) 9424887Schin { 9434887Schin /* check for symlink and use symlink name */ 9444887Schin char buff[PATH_MAX+1]; 9454887Schin char save[PATH_MAX+1]; 9464887Schin stakseek(PATH_OFFSET); 9474887Schin stakputs(opath); 9484887Schin path = stakptr(PATH_OFFSET); 9494887Schin while((n=readlink(path,buff,PATH_MAX))>0) 9504887Schin { 9514887Schin buff[n] = 0; 9524887Schin n = PATH_OFFSET; 9534887Schin r = 0; 9544887Schin if((v=strrchr(path,'/')) && *buff!='/') 9554887Schin { 9564887Schin if(buff[0]=='.' && buff[1]=='.' && (r = strlen(path) + 1) <= PATH_MAX) 9574887Schin memcpy(save, path, r); 9584887Schin else 9594887Schin r = 0; 9604887Schin n += (v+1-path); 9614887Schin } 9624887Schin stakseek(n); 9634887Schin stakputs(buff); 9644887Schin stakputc(0); 9654887Schin path = stakptr(PATH_OFFSET); 9664887Schin if(v && buff[0]=='.' && buff[1]=='.') 9674887Schin { 9684887Schin pathcanon(path, 0); 9694887Schin if(r && access(path,X_OK)) 9704887Schin { 9714887Schin memcpy(path, save, r); 9724887Schin break; 9734887Schin } 9744887Schin } 9754887Schin if(libenv = path_lib(libpath,path)) 9764887Schin break; 9774887Schin } 9784887Schin stakseek(0); 9794887Schin } 9804887Schin #endif 9814887Schin if(libenv && (v = strchr(libenv,'='))) 9824887Schin { 9834887Schin n = v - libenv; 9844887Schin *v = 0; 9854887Schin np = nv_open(libenv,shp->var_tree,0); 9864887Schin *v = '='; 9874887Schin s = nv_getval(np); 9884887Schin stakputs(libenv); 9894887Schin if(s) 9904887Schin { 9914887Schin stakputc(':'); 9924887Schin stakputs(s); 9934887Schin } 9944887Schin v = stakfreeze(1); 9954887Schin r = 1; 996*8462SApril.Chin@Sun.COM xp = envp + 1; 9974887Schin while (s = *xp++) 9984887Schin { 9994887Schin if (strneq(s, v, n) && s[n] == '=') 10004887Schin { 10014887Schin xval = *--xp; 10024887Schin *xp = v; 10034887Schin r = 0; 10044887Schin break; 10054887Schin } 10064887Schin } 10074887Schin if (r) 10084887Schin { 10094887Schin *envp-- = v; 10104887Schin xp = 0; 10114887Schin } 10124887Schin } 10134887Schin if(!opath) 10144887Schin opath = stakptr(PATH_OFFSET); 10154887Schin envp[0] = (char*)opath-PATH_OFFSET; 10164887Schin envp[0][0] = '_'; 10174887Schin envp[0][1] = '='; 10184887Schin sfsync(sfstderr); 10194887Schin sh_sigcheck(); 10204887Schin path = path_relative(opath); 10214887Schin #ifdef SHELLMAGIC 10224887Schin if(*path!='/' && path!=opath) 10234887Schin { 10244887Schin /* 10254887Schin * The following code because execv(foo,) and execv(./foo,) 10264887Schin * may not yield the same results 10274887Schin */ 10284887Schin char *sp = (char*)malloc(strlen(path)+3); 10294887Schin sp[0] = '.'; 10304887Schin sp[1] = '/'; 10314887Schin strcpy(sp+2,path); 10324887Schin path = sp; 10334887Schin } 10344887Schin #endif /* SHELLMAGIC */ 10354887Schin if(spawn && !sh_isoption(SH_PFSH)) 10364887Schin pid = _spawnveg(opath, &argv[0],envp, spawn>>1); 10374887Schin else 1038*8462SApril.Chin@Sun.COM pid = path_pfexecve(opath, &argv[0] ,envp,spawn); 10394887Schin if(xp) 10404887Schin *xp = xval; 10414887Schin #ifdef SHELLMAGIC 10424887Schin if(*path=='.' && path!=opath) 10434887Schin { 10444887Schin free(path); 10454887Schin path = path_relative(opath); 10464887Schin } 10474887Schin #endif /* SHELLMAGIC */ 10484887Schin if(pid>0) 10494887Schin return(pid); 10504887Schin retry: 10514887Schin switch(sh.path_err = errno) 10524887Schin { 10534887Schin #ifdef apollo 10544887Schin /* 10554887Schin * On apollo's execve will fail with eacces when 10564887Schin * file has execute but not read permissions. So, 10574887Schin * for now we will pretend that EACCES and ENOEXEC 10584887Schin * mean the same thing. 10594887Schin */ 10604887Schin case EACCES: 10614887Schin #endif /* apollo */ 10624887Schin case ENOEXEC: 10634887Schin #if SHOPT_SUID_EXEC 10644887Schin case EPERM: 10654887Schin /* some systems return EPERM if setuid bit is on */ 10664887Schin #endif 10674887Schin errno = ENOEXEC; 10684887Schin if(spawn) 10694887Schin { 10704887Schin #ifdef _lib_fork 10714887Schin if(sh.subshell) 10724887Schin return(-1); 10734887Schin do 10744887Schin { 10754887Schin if((pid=fork())>0) 10764887Schin return(pid); 10774887Schin } 10784887Schin while(_sh_fork(pid,0,(int*)0) < 0); 1079*8462SApril.Chin@Sun.COM ((struct checkpt*)shp->jmplist)->mode = SH_JMPEXIT; 10804887Schin #else 10814887Schin return(-1); 10824887Schin #endif 10834887Schin } 10844887Schin exscript(shp,path,argv,envp); 10854887Schin #ifndef apollo 10864887Schin case EACCES: 10874887Schin { 10884887Schin struct stat statb; 10894887Schin if(stat(path,&statb)>=0) 10904887Schin { 10914887Schin if(S_ISDIR(statb.st_mode)) 10924887Schin errno = EISDIR; 10934887Schin #ifdef S_ISSOCK 10944887Schin if(S_ISSOCK(statb.st_mode)) 10954887Schin exscript(shp,path,argv,envp); 10964887Schin #endif 10974887Schin } 10984887Schin } 10994887Schin /* FALL THROUGH */ 11004887Schin #endif /* !apollo */ 11014887Schin #ifdef ENAMETOOLONG 11024887Schin case ENAMETOOLONG: 11034887Schin #endif /* ENAMETOOLONG */ 11044887Schin #if !SHOPT_SUID_EXEC 11054887Schin case EPERM: 11064887Schin #endif 11074887Schin shp->path_err = errno; 11084887Schin return(-1); 11094887Schin case ENOTDIR: 11104887Schin case ENOENT: 11114887Schin case EINTR: 11124887Schin #ifdef EMLINK 11134887Schin case EMLINK: 11144887Schin #endif /* EMLINK */ 11154887Schin return(-1); 11164887Schin case E2BIG: 11174887Schin if(sh.xargmin) 11184887Schin { 11194887Schin pid = path_xargs(opath, &argv[0] ,envp,spawn); 11204887Schin if(pid<0) 11214887Schin goto retry; 11224887Schin return(pid); 11234887Schin } 11244887Schin default: 11254887Schin errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path); 11264887Schin } 11274887Schin return 0; 11284887Schin } 11294887Schin 11304887Schin /* 11314887Schin * File is executable but not machine code. 11324887Schin * Assume file is a Shell script and execute it. 11334887Schin */ 11344887Schin 11354887Schin static void exscript(Shell_t *shp,register char *path,register char *argv[],char **envp) 11364887Schin { 11374887Schin register Sfio_t *sp; 11384887Schin path = path_relative(path); 11394887Schin shp->comdiv=0; 11404887Schin shp->bckpid = 0; 11414887Schin shp->st.ioset=0; 11424887Schin /* clean up any cooperating processes */ 11434887Schin if(shp->cpipe[0]>0) 11444887Schin sh_pclose(shp->cpipe); 11454887Schin if(shp->cpid && shp->outpipe) 11464887Schin sh_close(*shp->outpipe); 11474887Schin shp->cpid = 0; 11484887Schin if(sp=fcfile()) 11494887Schin while(sfstack(sp,SF_POPSTACK)); 11504887Schin job_clear(); 11514887Schin if(shp->infd>0 && (shp->fdstatus[shp->infd]&IOCLEX)) 11524887Schin sh_close(shp->infd); 11534887Schin sh_setstate(sh_state(SH_FORKED)); 11544887Schin sfsync(sfstderr); 11554887Schin #if SHOPT_SUID_EXEC && !SHOPT_PFSH 11564887Schin /* check if file cannot open for read or script is setuid/setgid */ 11574887Schin { 11584887Schin static char name[] = "/tmp/euidXXXXXXXXXX"; 11594887Schin register int n; 11604887Schin register uid_t euserid; 11614887Schin char *savet=0; 11624887Schin struct stat statb; 11634887Schin if((n=sh_open(path,O_RDONLY,0)) >= 0) 11644887Schin { 11654887Schin /* move <n> if n=0,1,2 */ 11664887Schin n = sh_iomovefd(n); 11674887Schin if(fstat(n,&statb)>=0 && !(statb.st_mode&(S_ISUID|S_ISGID))) 11684887Schin goto openok; 11694887Schin sh_close(n); 11704887Schin } 11714887Schin if((euserid=geteuid()) != shp->userid) 11724887Schin { 11734887Schin strncpy(name+9,fmtbase((long)getpid(),10,0),sizeof(name)-10); 11744887Schin /* create a suid open file with owner equal effective uid */ 11754887Schin if((n=open(name,O_CREAT|O_TRUNC|O_WRONLY,S_ISUID|S_IXUSR)) < 0) 11764887Schin goto fail; 11774887Schin unlink(name); 11784887Schin /* make sure that file has right owner */ 11794887Schin if(fstat(n,&statb)<0 || statb.st_uid != euserid) 11804887Schin goto fail; 11814887Schin if(n!=10) 11824887Schin { 11834887Schin sh_close(10); 11844887Schin fcntl(n, F_DUPFD, 10); 11854887Schin sh_close(n); 11864887Schin n=10; 11874887Schin } 11884887Schin } 11894887Schin savet = *--argv; 11904887Schin *argv = path; 1191*8462SApril.Chin@Sun.COM path_pfexecve(e_suidexec,argv,envp,0); 11924887Schin fail: 11934887Schin /* 11944887Schin * The following code is just for compatibility 11954887Schin */ 11964887Schin if((n=open(path,O_RDONLY,0)) < 0) 1197*8462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path); 11984887Schin if(savet) 11994887Schin *argv++ = savet; 12004887Schin openok: 12014887Schin shp->infd = n; 12024887Schin } 12034887Schin #else 1204*8462SApril.Chin@Sun.COM if((shp->infd = sh_open(path,O_RDONLY,0)) < 0) 1205*8462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path); 12064887Schin #endif 12074887Schin shp->infd = sh_iomovefd(shp->infd); 12084887Schin #if SHOPT_ACCT 12094887Schin sh_accbegin(path) ; /* reset accounting */ 12104887Schin #endif /* SHOPT_ACCT */ 12114887Schin shp->arglist = sh_argcreate(argv); 12124887Schin shp->lastarg = strdup(path); 12134887Schin /* save name of calling command */ 12144887Schin shp->readscript = error_info.id; 12154887Schin /* close history file if name has changed */ 12164887Schin if(shp->hist_ptr && (path=nv_getval(HISTFILE)) && strcmp(path,shp->hist_ptr->histname)) 12174887Schin { 12184887Schin hist_close(shp->hist_ptr); 12194887Schin (HISTCUR)->nvalue.lp = 0; 12204887Schin } 12214887Schin sh_offstate(SH_FORKED); 12224887Schin siglongjmp(*shp->jmplist,SH_JMPSCRIPT); 12234887Schin } 12244887Schin 12254887Schin #if SHOPT_ACCT 12264887Schin # include <sys/acct.h> 12274887Schin # include "FEATURE/time" 12284887Schin 12294887Schin static struct acct sabuf; 12304887Schin static struct tms buffer; 12314887Schin static clock_t before; 12324887Schin static char *SHACCT; /* set to value of SHACCT environment variable */ 12334887Schin static shaccton; /* non-zero causes accounting record to be written */ 12344887Schin static int compress(time_t); 12354887Schin /* 12364887Schin * initialize accounting, i.e., see if SHACCT variable set 12374887Schin */ 12384887Schin void sh_accinit(void) 12394887Schin { 12404887Schin SHACCT = getenv("SHACCT"); 12414887Schin } 12424887Schin /* 1243*8462SApril.Chin@Sun.COM * suspend accounting until turned on by sh_accbegin() 12444887Schin */ 12454887Schin void sh_accsusp(void) 12464887Schin { 12474887Schin shaccton=0; 12484887Schin #ifdef AEXPAND 12494887Schin sabuf.ac_flag |= AEXPND; 12504887Schin #endif /* AEXPAND */ 12514887Schin } 12524887Schin 12534887Schin /* 12544887Schin * begin an accounting record by recording start time 12554887Schin */ 12564887Schin void sh_accbegin(const char *cmdname) 12574887Schin { 12584887Schin if(SHACCT) 12594887Schin { 12604887Schin sabuf.ac_btime = time(NIL(time_t *)); 12614887Schin before = times(&buffer); 12624887Schin sabuf.ac_uid = getuid(); 12634887Schin sabuf.ac_gid = getgid(); 12644887Schin strncpy(sabuf.ac_comm, (char*)path_basename(cmdname), 12654887Schin sizeof(sabuf.ac_comm)); 12664887Schin shaccton = 1; 12674887Schin } 12684887Schin } 12694887Schin /* 12704887Schin * terminate an accounting record and append to accounting file 12714887Schin */ 12724887Schin void sh_accend(void) 12734887Schin { 12744887Schin int fd; 12754887Schin clock_t after; 12764887Schin 12774887Schin if(shaccton) 12784887Schin { 12794887Schin after = times(&buffer); 12804887Schin sabuf.ac_utime = compress(buffer.tms_utime + buffer.tms_cutime); 12814887Schin sabuf.ac_stime = compress(buffer.tms_stime + buffer.tms_cstime); 12824887Schin sabuf.ac_etime = compress( (time_t)(after-before)); 12834887Schin fd = open( SHACCT , O_WRONLY | O_APPEND | O_CREAT,RW_ALL); 12844887Schin write(fd, (const char*)&sabuf, sizeof( sabuf )); 12854887Schin close( fd); 12864887Schin } 12874887Schin } 12884887Schin 12894887Schin /* 12904887Schin * Produce a pseudo-floating point representation 12914887Schin * with 3 bits base-8 exponent, 13 bits fraction. 12924887Schin */ 12934887Schin static int compress(register time_t t) 12944887Schin { 12954887Schin register int exp = 0, rund = 0; 12964887Schin 12974887Schin while (t >= 8192) 12984887Schin { 12994887Schin exp++; 13004887Schin rund = t&04; 13014887Schin t >>= 3; 13024887Schin } 13034887Schin if (rund) 13044887Schin { 13054887Schin t++; 13064887Schin if (t >= 8192) 13074887Schin { 13084887Schin t >>= 3; 13094887Schin exp++; 13104887Schin } 13114887Schin } 13124887Schin return((exp<<13) + t); 13134887Schin } 13144887Schin #endif /* SHOPT_ACCT */ 13154887Schin 13164887Schin 13174887Schin 13184887Schin /* 13194887Schin * add a pathcomponent to the path search list and eliminate duplicates 13204887Schin * and non-existing absolute paths. 13214887Schin */ 13224887Schin static Pathcomp_t *path_addcomp(Pathcomp_t *first, Pathcomp_t *old,const char *name, int flag) 13234887Schin { 13244887Schin register Pathcomp_t *pp, *oldpp; 13254887Schin struct stat statb; 13264887Schin int len, offset=staktell(); 13274887Schin if(!(flag&PATH_BFPATH)) 13284887Schin { 13294887Schin register const char *cp = name; 13304887Schin while(*cp && *cp!=':') 13314887Schin stakputc(*cp++); 13324887Schin len = staktell()-offset; 13334887Schin stakputc(0); 13344887Schin stakseek(offset); 13354887Schin name = (const char*)stakptr(offset); 13364887Schin } 13374887Schin else 13384887Schin len = strlen(name); 13394887Schin for(pp=first; pp; pp=pp->next) 13404887Schin { 13414887Schin if(memcmp(name,pp->name,len)==0 && (pp->name[len]==':' || pp->name[len]==0)) 13424887Schin { 13434887Schin pp->flags |= flag; 13444887Schin return(first); 13454887Schin } 13464887Schin } 13474887Schin if(old && (old=path_dirfind(old,name,0))) 13484887Schin { 13494887Schin statb.st_ino = old->ino; 13504887Schin statb.st_dev = old->dev; 1351*8462SApril.Chin@Sun.COM statb.st_mtime = old->mtime; 13524887Schin if(old->ino==0 && old->dev==0) 13534887Schin flag |= PATH_SKIP; 13544887Schin } 13554887Schin else if(stat(name,&statb)<0 || !S_ISDIR(statb.st_mode)) 13564887Schin { 13574887Schin if(*name=='/') 13584887Schin { 13594887Schin if(strcmp(name,SH_CMDLIB_DIR)) 13604887Schin return(first); 13614887Schin statb.st_dev = 1; 13624887Schin } 13634887Schin else 13644887Schin { 13654887Schin flag |= PATH_SKIP; 13664887Schin statb.st_dev = 0; 13674887Schin } 13684887Schin statb.st_ino = 0; 1369*8462SApril.Chin@Sun.COM statb.st_mtime = 0; 13704887Schin } 13714887Schin if(*name=='/' && onstdpath(name)) 13724887Schin flag |= PATH_STD_DIR; 13734887Schin for(pp=first, oldpp=0; pp; oldpp=pp, pp=pp->next) 13744887Schin { 1375*8462SApril.Chin@Sun.COM if(pp->ino==statb.st_ino && pp->dev==statb.st_dev && pp->mtime==statb.st_mtime) 13764887Schin { 13774887Schin /* if both absolute paths, eliminate second */ 13784887Schin pp->flags |= flag; 13794887Schin if(*name=='/' && *pp->name=='/') 13804887Schin return(first); 13814887Schin /* keep the path but mark it as skip */ 13824887Schin flag |= PATH_SKIP; 13834887Schin } 13844887Schin } 13854887Schin pp = newof((Pathcomp_t*)0,Pathcomp_t,1,len+1); 13864887Schin pp->refcount = 1; 13874887Schin memcpy((char*)(pp+1),name,len+1); 13884887Schin pp->name = (char*)(pp+1); 13894887Schin pp->len = len; 13904887Schin pp->dev = statb.st_dev; 13914887Schin pp->ino = statb.st_ino; 1392*8462SApril.Chin@Sun.COM pp->mtime = statb.st_mtime; 13934887Schin if(oldpp) 13944887Schin oldpp->next = pp; 13954887Schin else 13964887Schin first = pp; 13974887Schin pp->flags = flag; 13984887Schin if(pp->ino==0 && pp->dev==1) 13994887Schin { 14004887Schin pp->flags |= PATH_BUILTIN_LIB; 14014887Schin pp->blib = malloc(4); 14024887Schin strcpy(pp->blib,LIBCMD); 14034887Schin return(first); 14044887Schin } 14054887Schin if((flag&(PATH_PATH|PATH_SKIP))==PATH_PATH) 14064887Schin path_chkpaths(first,old,pp,offset); 14074887Schin return(first); 14084887Schin } 14094887Schin 14104887Schin /* 14114887Schin * This function checks for the .paths file in directory in <pp> 14124887Schin * it assumes that the directory is on the stack at <offset> 14134887Schin */ 14144887Schin static int path_chkpaths(Pathcomp_t *first, Pathcomp_t* old,Pathcomp_t *pp, int offset) 14154887Schin { 14164887Schin struct stat statb; 14174887Schin int k,m,n,fd; 14184887Schin char *sp,*cp,*ep; 14194887Schin stakseek(offset+pp->len); 14204887Schin if(pp->len==1 && *stakptr(offset)=='/') 14214887Schin stakseek(offset); 14224887Schin stakputs("/.paths"); 14234887Schin if((fd=open(stakptr(offset),O_RDONLY))>=0) 14244887Schin { 14254887Schin fstat(fd,&statb); 14264887Schin n = statb.st_size; 14274887Schin stakseek(offset+pp->len+n+2); 14284887Schin sp = stakptr(offset+pp->len); 14294887Schin *sp++ = '/'; 14304887Schin n=read(fd,cp=sp,n); 14314887Schin sp[n] = 0; 14324887Schin close(fd); 14334887Schin for(ep=0; n--; cp++) 14344887Schin { 14354887Schin if(*cp=='=') 14364887Schin { 14374887Schin ep = cp+1; 14384887Schin continue; 14394887Schin } 14404887Schin else if(*cp!='\r' && *cp!='\n') 14414887Schin continue; 14424887Schin if(*sp=='#' || sp==cp) 14434887Schin { 14444887Schin sp = cp+1; 14454887Schin continue; 14464887Schin } 14474887Schin *cp = 0; 14484887Schin m = ep ? (ep-sp) : 0; 14494887Schin if(!m || m==6 && memcmp((void*)sp,(void*)"FPATH=",6)==0) 14504887Schin { 14514887Schin if(first) 14524887Schin { 14534887Schin char *ptr = stakptr(offset+pp->len+1); 14544887Schin if(ep) 14554887Schin strcpy(ptr,ep); 14564887Schin path_addcomp(first,old,stakptr(offset),PATH_FPATH|PATH_BFPATH); 14574887Schin } 14584887Schin } 14594887Schin else if(m==12 && memcmp((void*)sp,(void*)"BUILTIN_LIB=",12)==0) 14604887Schin { 14614887Schin if(!(pp->flags & PATH_BUILTIN_LIB)) 14624887Schin { 14634887Schin pp->flags |= PATH_BUILTIN_LIB; 14644887Schin if (*ep == '.' && !*(ep + 1)) 14654887Schin pp->flags |= PATH_STD_DIR; 14664887Schin else 14674887Schin { 14684887Schin k = strlen(ep)+1; 14694887Schin if (*ep != '/') 14704887Schin k += pp->len+1; 14714887Schin pp->blib = sp = malloc(k); 14724887Schin if (*ep != '/') 14734887Schin { 14744887Schin strcpy(pp->blib,pp->name); 14754887Schin sp += pp->len; 14764887Schin *sp++ = '/'; 14774887Schin } 14784887Schin strcpy(sp,ep); 14794887Schin } 14804887Schin } 14814887Schin } 14824887Schin else if(m) 14834887Schin { 14844887Schin pp->lib = (char*)malloc(cp-sp+pp->len+2); 14854887Schin memcpy((void*)pp->lib,(void*)sp,m); 14864887Schin memcpy((void*)&pp->lib[m],stakptr(offset),pp->len); 14874887Schin pp->lib[k=m+pp->len] = '/'; 14884887Schin strcpy((void*)&pp->lib[k+1],ep); 14894887Schin pathcanon(&pp->lib[m],0); 14904887Schin if(!first) 14914887Schin { 14924887Schin stakseek(0); 14934887Schin stakputs(pp->lib); 14944887Schin free((void*)pp->lib); 14954887Schin return(1); 14964887Schin } 14974887Schin } 14984887Schin sp = cp+1; 14994887Schin ep = 0; 15004887Schin } 15014887Schin } 15024887Schin return(0); 15034887Schin } 15044887Schin 15054887Schin 15064887Schin Pathcomp_t *path_addpath(Pathcomp_t *first, register const char *path,int type) 15074887Schin { 15084887Schin register const char *cp; 15094887Schin Pathcomp_t *old=0; 15104887Schin int offset = staktell(); 15114887Schin char *savptr; 15124887Schin 15134887Schin if(!path && type!=PATH_PATH) 15144887Schin return(first); 15154887Schin if(type!=PATH_FPATH) 15164887Schin { 15174887Schin old = first; 15184887Schin first = 0; 15194887Schin } 15204887Schin if(offset) 15214887Schin savptr = stakfreeze(0); 15224887Schin if(path) while(*(cp=path)) 15234887Schin { 15244887Schin if(*cp==':') 15254887Schin { 15264887Schin if(type!=PATH_FPATH) 15274887Schin first = path_addcomp(first,old,".",type); 15284887Schin while(*++path == ':'); 15294887Schin } 15304887Schin else 15314887Schin { 15324887Schin int c; 15334887Schin while(*path && *path!=':') 15344887Schin path++; 15354887Schin c = *path++; 15364887Schin first = path_addcomp(first,old,cp,type); 15374887Schin if(c==0) 15384887Schin break; 15394887Schin if(*path==0) 15404887Schin path--; 15414887Schin } 15424887Schin } 15434887Schin if(old) 15444887Schin { 15454887Schin if(!first && !path) 15464887Schin { 15474887Schin Pathcomp_t *pp = (Pathcomp_t*)old->shp->defpathlist; 15484887Schin if(!pp) 15494887Schin pp = defpath_init(old->shp); 15504887Schin first = path_dup(pp); 15514887Schin } 15524887Schin if(cp=(FPATHNOD)->nvalue.cp) 15534887Schin first = (void*)path_addpath((Pathcomp_t*)first,cp,PATH_FPATH); 15544887Schin path_delete(old); 15554887Schin } 15564887Schin if(offset) 15574887Schin stakset(savptr,offset); 15584887Schin else 15594887Schin stakseek(0); 15604887Schin return(first); 15614887Schin } 15624887Schin 15634887Schin /* 15644887Schin * duplicate the path give by <first> by incremented reference counts 15654887Schin */ 15664887Schin Pathcomp_t *path_dup(Pathcomp_t *first) 15674887Schin { 15684887Schin register Pathcomp_t *pp=first; 15694887Schin while(pp) 15704887Schin { 15714887Schin pp->refcount++; 15724887Schin pp = pp->next; 15734887Schin } 15744887Schin return(first); 15754887Schin } 15764887Schin 15774887Schin /* 15784887Schin * called whenever the directory is changed 15794887Schin */ 15804887Schin void path_newdir(Pathcomp_t *first) 15814887Schin { 15824887Schin register Pathcomp_t *pp=first, *next, *pq; 15834887Schin struct stat statb; 15844887Schin for(pp=first; pp; pp=pp->next) 15854887Schin { 15864887Schin pp->flags &= ~PATH_SKIP; 15874887Schin if(*pp->name=='/') 15884887Schin continue; 15894887Schin /* delete .paths component */ 15904887Schin if((next=pp->next) && (next->flags&PATH_BFPATH)) 15914887Schin { 15924887Schin pp->next = next->next; 15934887Schin if(--next->refcount<=0) 15944887Schin free((void*)next); 15954887Schin } 15964887Schin if(stat(pp->name,&statb)<0 || !S_ISDIR(statb.st_mode)) 15974887Schin { 15984887Schin pp->dev = 0; 15994887Schin pp->ino = 0; 16004887Schin continue; 16014887Schin } 16024887Schin pp->dev = statb.st_dev; 16034887Schin pp->ino = statb.st_ino; 1604*8462SApril.Chin@Sun.COM pp->mtime = statb.st_mtime; 16054887Schin for(pq=first;pq!=pp;pq=pq->next) 16064887Schin { 16074887Schin if(pp->ino==pq->ino && pp->dev==pq->dev) 16084887Schin pp->flags |= PATH_SKIP; 16094887Schin } 16104887Schin for(pq=pp;pq=pq->next;) 16114887Schin { 16124887Schin if(pp->ino==pq->ino && pp->dev==pq->dev) 16134887Schin pq->flags |= PATH_SKIP; 16144887Schin } 16154887Schin if((pp->flags&(PATH_PATH|PATH_SKIP))==PATH_PATH) 16164887Schin { 16174887Schin /* try to insert .paths component */ 16184887Schin int offset = staktell(); 16194887Schin stakputs(pp->name); 16204887Schin stakseek(offset); 16214887Schin next = pp->next; 16224887Schin pp->next = 0; 16234887Schin path_chkpaths(first,(Pathcomp_t*)0,pp,offset); 16244887Schin if(pp->next) 16254887Schin pp = pp->next; 16264887Schin pp->next = next; 16274887Schin } 16284887Schin } 16294887Schin #if 0 16304887Schin path_dump(first); 16314887Schin #endif 16324887Schin } 16334887Schin 16344887Schin Pathcomp_t *path_unsetfpath(Pathcomp_t *first) 16354887Schin { 16364887Schin register Pathcomp_t *pp=first, *old=0; 1637*8462SApril.Chin@Sun.COM Shell_t *shp = &sh; 1638*8462SApril.Chin@Sun.COM if(shp->fpathdict) 1639*8462SApril.Chin@Sun.COM { 1640*8462SApril.Chin@Sun.COM struct Ufunction *rp, *rpnext; 1641*8462SApril.Chin@Sun.COM for(rp=(struct Ufunction*)dtfirst(shp->fpathdict);rp;rp=rpnext) 1642*8462SApril.Chin@Sun.COM { 1643*8462SApril.Chin@Sun.COM rpnext = (struct Ufunction*)dtnext(shp->fpathdict,rp); 1644*8462SApril.Chin@Sun.COM if(rp->fdict) 1645*8462SApril.Chin@Sun.COM nv_delete(rp->np,rp->fdict,NV_NOFREE); 1646*8462SApril.Chin@Sun.COM rp->fdict = 0; 1647*8462SApril.Chin@Sun.COM } 1648*8462SApril.Chin@Sun.COM } 16494887Schin while(pp) 16504887Schin { 16514887Schin if((pp->flags&PATH_FPATH) && !(pp->flags&PATH_BFPATH)) 16524887Schin { 16534887Schin if(pp->flags&PATH_PATH) 16544887Schin pp->flags &= ~PATH_FPATH; 16554887Schin else 16564887Schin { 16574887Schin Pathcomp_t *ppsave=pp; 16584887Schin if(old) 16594887Schin old->next = pp->next; 16604887Schin else 16614887Schin first = pp->next; 16624887Schin pp = pp->next; 16634887Schin if(--ppsave->refcount<=0) 16644887Schin { 16654887Schin if(ppsave->lib) 16664887Schin free((void*)ppsave->lib); 16674887Schin free((void*)ppsave); 16684887Schin } 16694887Schin continue; 16704887Schin } 16714887Schin 16724887Schin } 16734887Schin old = pp; 16744887Schin pp = pp->next; 16754887Schin } 16764887Schin return(first); 16774887Schin } 16784887Schin 16794887Schin Pathcomp_t *path_dirfind(Pathcomp_t *first,const char *name,int c) 16804887Schin { 16814887Schin register Pathcomp_t *pp=first; 16824887Schin while(pp) 16834887Schin { 16844887Schin if(memcmp(name,pp->name,pp->len)==0 && name[pp->len]==c) 16854887Schin return(pp); 16864887Schin pp = pp->next; 16874887Schin } 16884887Schin return(0); 16894887Schin } 16904887Schin 16914887Schin /* 16924887Schin * get discipline for tracked alias 16934887Schin */ 16944887Schin static char *talias_get(Namval_t *np, Namfun_t *nvp) 16954887Schin { 16964887Schin Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp; 16974887Schin char *ptr; 16984887Schin if(!pp) 16994887Schin return(NULL); 17004887Schin path_nextcomp(pp,nv_name(np),pp); 17014887Schin ptr = stakfreeze(0); 17024887Schin return(ptr+PATH_OFFSET); 17034887Schin } 17044887Schin 17054887Schin static void talias_put(register Namval_t* np,const char *val,int flags,Namfun_t *fp) 17064887Schin { 17074887Schin if(!val && np->nvalue.cp) 17084887Schin { 17094887Schin Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp; 17104887Schin if(--pp->refcount<=0) 17114887Schin free((void*)pp); 17124887Schin } 17134887Schin nv_putv(np,val,flags,fp); 17144887Schin } 17154887Schin 17164887Schin static const Namdisc_t talias_disc = { 0, talias_put, talias_get }; 17174887Schin static Namfun_t talias_init = { &talias_disc, 1 }; 17184887Schin 17194887Schin /* 17204887Schin * set tracked alias node <np> to value <pp> 17214887Schin */ 17224887Schin void path_alias(register Namval_t *np,register Pathcomp_t *pp) 17234887Schin { 17244887Schin if(pp) 17254887Schin { 17264887Schin struct stat statb; 17274887Schin char *sp; 17284887Schin nv_offattr(np,NV_NOPRINT); 17294887Schin nv_stack(np,&talias_init); 17304887Schin np->nvalue.cp = (char*)pp; 17314887Schin pp->refcount++; 17324887Schin nv_setattr(np,NV_TAGGED|NV_NOFREE); 17334887Schin path_nextcomp(pp,nv_name(np),pp); 17344887Schin sp = stakptr(PATH_OFFSET); 17354887Schin if(sp && lstat(sp,&statb)>=0 && S_ISLNK(statb.st_mode)) 17364887Schin nv_setsize(np,statb.st_size+1); 17374887Schin else 17384887Schin nv_setsize(np,0); 17394887Schin } 17404887Schin else 17414887Schin nv_unset(np); 17424887Schin } 17434887Schin 1744