1*4887Schin /*********************************************************************** 2*4887Schin * * 3*4887Schin * This software is part of the ast package * 4*4887Schin * Copyright (c) 1982-2007 AT&T Knowledge Ventures * 5*4887Schin * and is licensed under the * 6*4887Schin * Common Public License, Version 1.0 * 7*4887Schin * by AT&T Knowledge Ventures * 8*4887Schin * * 9*4887Schin * A copy of the License is available at * 10*4887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 11*4887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12*4887Schin * * 13*4887Schin * Information and Software Systems Research * 14*4887Schin * AT&T Research * 15*4887Schin * Florham Park NJ * 16*4887Schin * * 17*4887Schin * David Korn <dgk@research.att.com> * 18*4887Schin * * 19*4887Schin ***********************************************************************/ 20*4887Schin #pragma prototyped 21*4887Schin /* 22*4887Schin * David Korn 23*4887Schin * AT&T Labs 24*4887Schin * 25*4887Schin */ 26*4887Schin 27*4887Schin #include "defs.h" 28*4887Schin #include <fcin.h> 29*4887Schin #include <ls.h> 30*4887Schin #include <nval.h> 31*4887Schin #include <dlldefs.h> 32*4887Schin #include "variables.h" 33*4887Schin #include "path.h" 34*4887Schin #include "io.h" 35*4887Schin #include "jobs.h" 36*4887Schin #include "history.h" 37*4887Schin #include "test.h" 38*4887Schin #include "FEATURE/externs" 39*4887Schin #if SHOPT_PFSH 40*4887Schin # ifdef _hdr_exec_attr 41*4887Schin # include <exec_attr.h> 42*4887Schin # else 43*4887Schin # undef SHOPT_PFSH 44*4887Schin # endif 45*4887Schin #endif 46*4887Schin 47*4887Schin #define RW_ALL (S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH) 48*4887Schin #define LIBCMD "cmd" 49*4887Schin 50*4887Schin 51*4887Schin static int canexecute(char*,int); 52*4887Schin static void funload(Shell_t*,int,const char*); 53*4887Schin static void exscript(Shell_t*,char*, char*[], char**); 54*4887Schin static int path_chkpaths(Pathcomp_t*,Pathcomp_t*,Pathcomp_t*,int); 55*4887Schin 56*4887Schin static const char *std_path; 57*4887Schin 58*4887Schin static int onstdpath(const char *name) 59*4887Schin { 60*4887Schin register const char *cp = std_path, *sp; 61*4887Schin if(cp) 62*4887Schin while(*cp) 63*4887Schin { 64*4887Schin for(sp=name; *sp && (*cp == *sp); sp++,cp++); 65*4887Schin if(*sp==0 && (*cp==0 || *cp==':')) 66*4887Schin return(1); 67*4887Schin while(*cp && *cp++!=':'); 68*4887Schin } 69*4887Schin return(0); 70*4887Schin } 71*4887Schin 72*4887Schin static int path_pfexecve(const char *path, char *argv[],char *const envp[]) 73*4887Schin { 74*4887Schin #if SHOPT_PFSH 75*4887Schin char resolvedpath[PATH_MAX + 1]; 76*4887Schin if(!sh_isoption(SH_PFSH)) 77*4887Schin return(execve(path, argv, envp)); 78*4887Schin /* Solaris implements realpath(3C) using the resolvepath(2) */ 79*4887Schin /* system call so we can save us to call access(2) first */ 80*4887Schin if (!realpath(path, resolvedpath)) 81*4887Schin return -1; 82*4887Schin 83*4887Schin /* we can exec the command directly instead of via pfexec(1) if */ 84*4887Schin /* there is a matching entry without attributes in exec_attr(4) */ 85*4887Schin if (sh.user && *sh.user) 86*4887Schin { 87*4887Schin execattr_t *pf; 88*4887Schin if(pf=getexecuser(sh.user, KV_COMMAND, resolvedpath, GET_ONE)) 89*4887Schin { 90*4887Schin if (!pf->attr || pf->attr->length == 0) 91*4887Schin { 92*4887Schin int r = execve(path, argv, envp); 93*4887Schin free_execattr(pf); 94*4887Schin return r; 95*4887Schin } 96*4887Schin free_execattr(pf); 97*4887Schin } 98*4887Schin else 99*4887Schin { 100*4887Schin errno = ENOENT; 101*4887Schin return -1; 102*4887Schin } 103*4887Schin } 104*4887Schin --argv; 105*4887Schin argv[0] = argv[1]; 106*4887Schin argv[1] = resolvedpath; 107*4887Schin return(execve("/usr/bin/pfexec", argv, envp)); 108*4887Schin #else 109*4887Schin return(execve(path, argv, envp)); 110*4887Schin #endif 111*4887Schin } 112*4887Schin 113*4887Schin 114*4887Schin static pid_t _spawnveg(const char *path, char* const argv[], char* const envp[], pid_t pid) 115*4887Schin { 116*4887Schin int waitsafe = job.waitsafe; 117*4887Schin job_lock(); 118*4887Schin pid = spawnveg(path,argv,envp,pid); 119*4887Schin job.waitsafe = waitsafe; 120*4887Schin job_unlock(); 121*4887Schin return(pid); 122*4887Schin } 123*4887Schin /* 124*4887Schin * used with command -x to run the command in multiple passes 125*4887Schin * spawn is non-zero when invoked via spawn 126*4887Schin * the exitval is set to the maximum for each execution 127*4887Schin */ 128*4887Schin static pid_t path_xargs(const char *path, char *argv[],char *const envp[], int spawn) 129*4887Schin { 130*4887Schin register char *cp, **av, **xv; 131*4887Schin char **avlast= &argv[sh.xargmax], **saveargs=0; 132*4887Schin char *const *ev; 133*4887Schin long size, left; 134*4887Schin int nlast=1,n,exitval=0; 135*4887Schin pid_t pid; 136*4887Schin if(sh.xargmin < 0) 137*4887Schin return((pid_t)-1); 138*4887Schin size = sh.lim.arg_max-1024; 139*4887Schin for(ev=envp; cp= *ev; ev++) 140*4887Schin size -= strlen(cp)-1; 141*4887Schin for(av=argv; (cp= *av) && av< &argv[sh.xargmin]; av++) 142*4887Schin size -= strlen(cp)-1; 143*4887Schin for(av=avlast; cp= *av; av++,nlast++) 144*4887Schin size -= strlen(cp)-1; 145*4887Schin av = &argv[sh.xargmin]; 146*4887Schin if(!spawn) 147*4887Schin job_clear(); 148*4887Schin sh.exitval = 0; 149*4887Schin while(av<avlast) 150*4887Schin { 151*4887Schin for(xv=av,left=size; left>0 && av<avlast;) 152*4887Schin left -= strlen(*av++)+1; 153*4887Schin /* leave at least two for last */ 154*4887Schin if(left<0 && (avlast-av)<2) 155*4887Schin av--; 156*4887Schin if(xv==&argv[sh.xargmin]) 157*4887Schin { 158*4887Schin n = nlast*sizeof(char*); 159*4887Schin saveargs = (char**)malloc(n); 160*4887Schin memcpy((void*)saveargs, (void*)av, n); 161*4887Schin memcpy((void*)av,(void*)avlast,n); 162*4887Schin } 163*4887Schin else 164*4887Schin { 165*4887Schin for(n=sh.xargmin; xv < av; xv++) 166*4887Schin argv[n++] = *xv; 167*4887Schin for(xv=avlast; cp= *xv; xv++) 168*4887Schin argv[n++] = cp; 169*4887Schin argv[n] = 0; 170*4887Schin } 171*4887Schin if(saveargs || av<avlast || (exitval && !spawn)) 172*4887Schin { 173*4887Schin if((pid=_spawnveg(path,argv,envp,0)) < 0) 174*4887Schin return(-1); 175*4887Schin job_post(pid,0); 176*4887Schin job_wait(pid); 177*4887Schin if(sh.exitval>exitval) 178*4887Schin exitval = sh.exitval; 179*4887Schin if(saveargs) 180*4887Schin { 181*4887Schin memcpy((void*)av,saveargs,n); 182*4887Schin free((void*)saveargs); 183*4887Schin saveargs = 0; 184*4887Schin } 185*4887Schin } 186*4887Schin else if(spawn && !sh_isoption(SH_PFSH)) 187*4887Schin { 188*4887Schin sh.xargexit = exitval; 189*4887Schin return(_spawnveg(path,argv,envp,spawn>>1)); 190*4887Schin } 191*4887Schin else 192*4887Schin return((pid_t)path_pfexecve(path,argv,envp)); 193*4887Schin } 194*4887Schin if(!spawn) 195*4887Schin exit(exitval); 196*4887Schin return((pid_t)-1); 197*4887Schin } 198*4887Schin 199*4887Schin /* 200*4887Schin * make sure PWD is set up correctly 201*4887Schin * Return the present working directory 202*4887Schin * Invokes getcwd() if flag==0 and if necessary 203*4887Schin * Sets the PWD variable to this value 204*4887Schin */ 205*4887Schin char *path_pwd(int flag) 206*4887Schin { 207*4887Schin register char *cp; 208*4887Schin register char *dfault = (char*)e_dot; 209*4887Schin register int count = 0; 210*4887Schin Shell_t *shp = &sh; 211*4887Schin if(shp->pwd) 212*4887Schin return((char*)shp->pwd); 213*4887Schin while(1) 214*4887Schin { 215*4887Schin /* try from lowest to highest */ 216*4887Schin switch(count++) 217*4887Schin { 218*4887Schin case 0: 219*4887Schin cp = nv_getval(PWDNOD); 220*4887Schin break; 221*4887Schin case 1: 222*4887Schin cp = nv_getval(HOME); 223*4887Schin break; 224*4887Schin case 2: 225*4887Schin cp = "/"; 226*4887Schin break; 227*4887Schin case 3: 228*4887Schin cp = (char*)e_crondir; 229*4887Schin if(flag) /* skip next case when non-zero flag */ 230*4887Schin ++count; 231*4887Schin break; 232*4887Schin case 4: 233*4887Schin { 234*4887Schin if(cp=getcwd(NIL(char*),0)) 235*4887Schin { 236*4887Schin nv_offattr(PWDNOD,NV_NOFREE); 237*4887Schin nv_unset(PWDNOD); 238*4887Schin PWDNOD->nvalue.cp = cp; 239*4887Schin goto skip; 240*4887Schin } 241*4887Schin break; 242*4887Schin } 243*4887Schin case 5: 244*4887Schin return(dfault); 245*4887Schin } 246*4887Schin if(cp && *cp=='/' && test_inode(cp,e_dot)) 247*4887Schin break; 248*4887Schin } 249*4887Schin if(count>1) 250*4887Schin { 251*4887Schin nv_offattr(PWDNOD,NV_NOFREE); 252*4887Schin nv_putval(PWDNOD,cp,NV_RDONLY); 253*4887Schin } 254*4887Schin skip: 255*4887Schin nv_onattr(PWDNOD,NV_NOFREE|NV_EXPORT); 256*4887Schin shp->pwd = (char*)(PWDNOD->nvalue.cp); 257*4887Schin return(cp); 258*4887Schin } 259*4887Schin 260*4887Schin static void free_bltin(Namval_t *np,void *data) 261*4887Schin { 262*4887Schin register Pathcomp_t *pp= (Pathcomp_t*)data; 263*4887Schin if(pp->flags&PATH_STD_DIR) 264*4887Schin { 265*4887Schin int offset=staktell();; 266*4887Schin if(strcmp(pp->name,"/bin")==0 || memcmp(pp->name,np->nvname,pp->len) || np->nvname[pp->len]!='/') 267*4887Schin return; 268*4887Schin stakputs("/bin"); 269*4887Schin stakputs(np->nvname+pp->len+1); 270*4887Schin stakputc(0); 271*4887Schin sh_addbuiltin(stakptr(offset),np->nvalue.bfp,NiL); 272*4887Schin stakseek(offset); 273*4887Schin return; 274*4887Schin } 275*4887Schin if((void*)np->nvenv==pp->bltin_lib) 276*4887Schin dtdelete(sh_bltin_tree(),np); 277*4887Schin } 278*4887Schin 279*4887Schin /* 280*4887Schin * delete current Pathcomp_t structure 281*4887Schin */ 282*4887Schin void path_delete(Pathcomp_t *first) 283*4887Schin { 284*4887Schin register Pathcomp_t *pp=first, *old=0, *ppnext; 285*4887Schin while(pp) 286*4887Schin { 287*4887Schin ppnext = pp->next; 288*4887Schin if(--pp->refcount<=0) 289*4887Schin { 290*4887Schin if(pp->lib) 291*4887Schin free((void*)pp->lib); 292*4887Schin if(pp->blib) 293*4887Schin free((void*)pp->blib); 294*4887Schin if(pp->bltin_lib || (pp->flags&PATH_STD_DIR)) 295*4887Schin { 296*4887Schin nv_scan(sh_bltin_tree(),free_bltin,pp,0,0); 297*4887Schin if(pp->bltin_lib) 298*4887Schin dlclose(pp->bltin_lib); 299*4887Schin } 300*4887Schin free((void*)pp); 301*4887Schin if(old) 302*4887Schin old->next = ppnext; 303*4887Schin } 304*4887Schin else 305*4887Schin old = pp; 306*4887Schin pp = ppnext; 307*4887Schin } 308*4887Schin } 309*4887Schin 310*4887Schin /* 311*4887Schin * returns library variable from .paths 312*4887Schin * The value might be returned on the stack overwriting path 313*4887Schin */ 314*4887Schin static char *path_lib(Pathcomp_t *pp, char *path) 315*4887Schin { 316*4887Schin register char *last = strrchr(path,'/'); 317*4887Schin register int r; 318*4887Schin struct stat statb; 319*4887Schin if(last) 320*4887Schin *last = 0; 321*4887Schin else 322*4887Schin path = "."; 323*4887Schin r = stat(path,&statb); 324*4887Schin if(last) 325*4887Schin *last = '/'; 326*4887Schin if(r>=0) 327*4887Schin { 328*4887Schin Pathcomp_t pcomp; 329*4887Schin char save[8]; 330*4887Schin for( ;pp; pp=pp->next) 331*4887Schin { 332*4887Schin if(pp->ino==statb.st_ino && pp->dev==statb.st_dev) 333*4887Schin return(pp->lib); 334*4887Schin } 335*4887Schin pcomp.len = 0; 336*4887Schin if(last) 337*4887Schin pcomp.len = last-path; 338*4887Schin memcpy((void*)save, (void*)stakptr(PATH_OFFSET+pcomp.len),sizeof(save)); 339*4887Schin if(path_chkpaths((Pathcomp_t*)0,(Pathcomp_t*)0,&pcomp,PATH_OFFSET)) 340*4887Schin return(stakfreeze(1)); 341*4887Schin memcpy((void*)stakptr(PATH_OFFSET+pcomp.len),(void*)save,sizeof(save)); 342*4887Schin } 343*4887Schin return(0); 344*4887Schin } 345*4887Schin 346*4887Schin #if 0 347*4887Schin void path_dump(register Pathcomp_t *pp) 348*4887Schin { 349*4887Schin sfprintf(sfstderr,"dump\n"); 350*4887Schin while(pp) 351*4887Schin { 352*4887Schin sfprintf(sfstderr,"pp=%x dev=%d ino=%d len=%d flags=%o name=%.*s\n", 353*4887Schin pp,pp->dev,pp->ino,pp->len,pp->flags,pp->len,pp->name); 354*4887Schin pp = pp->next; 355*4887Schin } 356*4887Schin } 357*4887Schin #endif 358*4887Schin 359*4887Schin /* 360*4887Schin * write the next path to search on the current stack 361*4887Schin * if last is given, all paths that come before <last> are skipped 362*4887Schin * the next pathcomp is returned. 363*4887Schin */ 364*4887Schin Pathcomp_t *path_nextcomp(register Pathcomp_t *pp, const char *name, Pathcomp_t *last) 365*4887Schin { 366*4887Schin stakseek(PATH_OFFSET); 367*4887Schin if(*name=='/') 368*4887Schin pp = 0; 369*4887Schin else 370*4887Schin { 371*4887Schin for(;pp && pp!=last;pp=pp->next) 372*4887Schin { 373*4887Schin if(pp->flags&PATH_SKIP) 374*4887Schin continue; 375*4887Schin if(!last || *pp->name!='/') 376*4887Schin break; 377*4887Schin } 378*4887Schin if(!pp) /* this should not happen */ 379*4887Schin pp = last; 380*4887Schin } 381*4887Schin if(pp && (pp->name[0]!='.' || pp->name[1])) 382*4887Schin { 383*4887Schin if(*pp->name!='/') 384*4887Schin { 385*4887Schin stakputs(path_pwd(1)); 386*4887Schin if(*stakptr(staktell()-1)!='/') 387*4887Schin stakputc('/'); 388*4887Schin } 389*4887Schin stakwrite(pp->name,pp->len); 390*4887Schin if(pp->name[pp->len-1]!='/') 391*4887Schin stakputc('/'); 392*4887Schin } 393*4887Schin stakputs(name); 394*4887Schin stakputc(0); 395*4887Schin while(pp && pp!=last && (pp=pp->next)) 396*4887Schin { 397*4887Schin if(!(pp->flags&PATH_SKIP)) 398*4887Schin return(pp); 399*4887Schin } 400*4887Schin return((Pathcomp_t*)0); 401*4887Schin } 402*4887Schin 403*4887Schin static Pathcomp_t* defpath_init(Shell_t *shp) 404*4887Schin { 405*4887Schin Pathcomp_t *pp = (void*)path_addpath((Pathcomp_t*)0,(std_path),PATH_PATH); 406*4887Schin if(shp->defpathlist = (void*)pp) 407*4887Schin pp->shp = shp; 408*4887Schin return(pp); 409*4887Schin } 410*4887Schin 411*4887Schin static void path_init(Shell_t *shp) 412*4887Schin { 413*4887Schin const char *val; 414*4887Schin Pathcomp_t *pp; 415*4887Schin if(!std_path && !(std_path=astconf("PATH",NIL(char*),NIL(char*)))) 416*4887Schin std_path = e_defpath; 417*4887Schin if(val=nv_scoped((PATHNOD))->nvalue.cp) 418*4887Schin { 419*4887Schin pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_PATH); 420*4887Schin if(shp->pathlist = (void*)pp) 421*4887Schin pp->shp = shp; 422*4887Schin } 423*4887Schin else 424*4887Schin { 425*4887Schin if(!(pp=(Pathcomp_t*)shp->defpathlist)) 426*4887Schin pp = defpath_init(shp); 427*4887Schin shp->pathlist = (void*)path_dup(pp); 428*4887Schin } 429*4887Schin if(val=nv_scoped((FPATHNOD))->nvalue.cp) 430*4887Schin { 431*4887Schin pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_FPATH); 432*4887Schin if(shp->pathlist = (void*)pp) 433*4887Schin pp->shp = shp; 434*4887Schin } 435*4887Schin } 436*4887Schin 437*4887Schin /* 438*4887Schin * returns that pathlist to search 439*4887Schin */ 440*4887Schin Pathcomp_t *path_get(register const char *name) 441*4887Schin { 442*4887Schin register Shell_t *shp = &sh; 443*4887Schin register Pathcomp_t *pp=0; 444*4887Schin if(*name && strchr(name,'/')) 445*4887Schin return(0); 446*4887Schin if(!sh_isstate(SH_DEFPATH)) 447*4887Schin { 448*4887Schin if(!shp->pathlist) 449*4887Schin path_init(shp); 450*4887Schin pp = (Pathcomp_t*)shp->pathlist; 451*4887Schin } 452*4887Schin if(!pp && (!(PATHNOD)->nvalue.cp) || sh_isstate(SH_DEFPATH)) 453*4887Schin { 454*4887Schin if(!(pp=(Pathcomp_t*)shp->defpathlist)) 455*4887Schin pp = defpath_init(shp); 456*4887Schin } 457*4887Schin return(pp); 458*4887Schin } 459*4887Schin 460*4887Schin /* 461*4887Schin * open file corresponding to name using path give by <pp> 462*4887Schin */ 463*4887Schin static int path_opentype(const char *name, register Pathcomp_t *pp, int fun) 464*4887Schin { 465*4887Schin register int fd= -1; 466*4887Schin struct stat statb; 467*4887Schin Pathcomp_t *oldpp; 468*4887Schin Shell_t *shp; 469*4887Schin if(pp) 470*4887Schin shp = pp->shp; 471*4887Schin else 472*4887Schin { 473*4887Schin shp = sh_getinterp(); 474*4887Schin if(!shp->pathlist) 475*4887Schin path_init(shp); 476*4887Schin } 477*4887Schin if(!fun && strchr(name,'/')) 478*4887Schin { 479*4887Schin if(sh_isoption(SH_RESTRICTED)) 480*4887Schin errormsg(SH_DICT,ERROR_exit(1),e_restricted,name); 481*4887Schin } 482*4887Schin do 483*4887Schin { 484*4887Schin pp = path_nextcomp(oldpp=pp,name,0); 485*4887Schin while(oldpp && (oldpp->flags&PATH_SKIP)) 486*4887Schin oldpp = oldpp->next; 487*4887Schin if(fun && (!oldpp || !(oldpp->flags&PATH_FPATH))) 488*4887Schin continue; 489*4887Schin if((fd = sh_open(path_relative(stakptr(PATH_OFFSET)),O_RDONLY,0)) >= 0) 490*4887Schin { 491*4887Schin if(fstat(fd,&statb)<0 || S_ISDIR(statb.st_mode)) 492*4887Schin { 493*4887Schin errno = EISDIR; 494*4887Schin sh_close(fd); 495*4887Schin fd = -1; 496*4887Schin } 497*4887Schin } 498*4887Schin } 499*4887Schin while( fd<0 && pp); 500*4887Schin if(fd>=0 && (fd = sh_iomovefd(fd)) > 0) 501*4887Schin { 502*4887Schin fcntl(fd,F_SETFD,FD_CLOEXEC); 503*4887Schin shp->fdstatus[fd] |= IOCLEX; 504*4887Schin } 505*4887Schin return(fd); 506*4887Schin } 507*4887Schin 508*4887Schin /* 509*4887Schin * open file corresponding to name using path give by <pp> 510*4887Schin */ 511*4887Schin int path_open(const char *name, register Pathcomp_t *pp) 512*4887Schin { 513*4887Schin return(path_opentype(name,pp,0)); 514*4887Schin } 515*4887Schin 516*4887Schin /* 517*4887Schin * given a pathname return the base name 518*4887Schin */ 519*4887Schin 520*4887Schin char *path_basename(register const char *name) 521*4887Schin { 522*4887Schin register const char *start = name; 523*4887Schin while (*name) 524*4887Schin if ((*name++ == '/') && *name) /* don't trim trailing / */ 525*4887Schin start = name; 526*4887Schin return ((char*)start); 527*4887Schin } 528*4887Schin 529*4887Schin char *path_fullname(const char *name) 530*4887Schin { 531*4887Schin int len=strlen(name)+1,dirlen=0; 532*4887Schin char *path,*pwd; 533*4887Schin if(*name!='/') 534*4887Schin { 535*4887Schin pwd = path_pwd(1); 536*4887Schin dirlen = strlen(pwd)+1; 537*4887Schin } 538*4887Schin path = (char*)malloc(len+dirlen); 539*4887Schin if(dirlen) 540*4887Schin { 541*4887Schin memcpy((void*)path,(void*)pwd,dirlen); 542*4887Schin path[dirlen-1] = '/'; 543*4887Schin } 544*4887Schin memcpy((void*)&path[dirlen],(void*)name,len); 545*4887Schin pathcanon(path,0); 546*4887Schin return(path); 547*4887Schin } 548*4887Schin 549*4887Schin /* 550*4887Schin * load functions from file <fno> 551*4887Schin */ 552*4887Schin static void funload(Shell_t *shp,int fno, const char *name) 553*4887Schin { 554*4887Schin char *oldname=shp->st.filename, buff[IOBSIZE+1]; 555*4887Schin int savestates = sh_getstate(); 556*4887Schin sh_onstate(SH_NOLOG); 557*4887Schin sh_onstate(SH_NOALIAS); 558*4887Schin shp->readscript = (char*)name; 559*4887Schin shp->st.filename = path_fullname(stakptr(PATH_OFFSET)); 560*4887Schin error_info.line = 0; 561*4887Schin sh_eval(sfnew(NIL(Sfio_t*),buff,IOBSIZE,fno,SF_READ),0); 562*4887Schin shp->readscript = 0; 563*4887Schin free((void*)shp->st.filename); 564*4887Schin shp->st.filename = oldname; 565*4887Schin sh_setstate(savestates); 566*4887Schin } 567*4887Schin 568*4887Schin /* 569*4887Schin * do a path search and track alias if requested 570*4887Schin * if flag is 0, or if name not found, then try autoloading function 571*4887Schin * if flag==2, returns 1 if name found on FPATH 572*4887Schin * returns 1, if function was autoloaded. 573*4887Schin * If endpath!=NULL, Path search ends when path matches endpath. 574*4887Schin */ 575*4887Schin 576*4887Schin int path_search(register const char *name,Pathcomp_t *endpath, int flag) 577*4887Schin { 578*4887Schin register Namval_t *np; 579*4887Schin register int fno; 580*4887Schin Pathcomp_t *pp=0; 581*4887Schin Shell_t *shp = &sh; 582*4887Schin if(name && strchr(name,'/')) 583*4887Schin { 584*4887Schin stakseek(PATH_OFFSET); 585*4887Schin stakputs(name); 586*4887Schin if(canexecute(stakptr(PATH_OFFSET),0)<0) 587*4887Schin { 588*4887Schin *stakptr(PATH_OFFSET) = 0; 589*4887Schin return(0); 590*4887Schin } 591*4887Schin if(*name=='/') 592*4887Schin return(1); 593*4887Schin stakseek(PATH_OFFSET); 594*4887Schin stakputs(path_pwd(1)); 595*4887Schin stakputc('/'); 596*4887Schin stakputs(name); 597*4887Schin stakputc(0); 598*4887Schin return(0); 599*4887Schin } 600*4887Schin if(sh_isstate(SH_DEFPATH)) 601*4887Schin { 602*4887Schin if(!shp->defpathlist) 603*4887Schin defpath_init(shp); 604*4887Schin } 605*4887Schin else if(!shp->pathlist) 606*4887Schin path_init(shp); 607*4887Schin if(flag) 608*4887Schin { 609*4887Schin if(!(pp=path_absolute(name,endpath)) && endpath) 610*4887Schin pp = path_absolute(name,NIL(Pathcomp_t*)); 611*4887Schin if(!pp && (np=nv_search(name,sh.fun_tree,HASH_NOSCOPE))&&np->nvalue.ip) 612*4887Schin return(1); 613*4887Schin if(!pp) 614*4887Schin *stakptr(PATH_OFFSET) = 0; 615*4887Schin } 616*4887Schin if(flag==0 || !pp || (pp->flags&PATH_FPATH)) 617*4887Schin { 618*4887Schin if(!pp) 619*4887Schin pp=sh_isstate(SH_DEFPATH)?shp->defpathlist:shp->pathlist; 620*4887Schin if(pp && strmatch(name,e_alphanum) && (fno=path_opentype(name,pp,1))>=0) 621*4887Schin { 622*4887Schin if(flag==2) 623*4887Schin { 624*4887Schin sh_close(fno); 625*4887Schin return(1); 626*4887Schin } 627*4887Schin funload(shp,fno,name); 628*4887Schin return(1); 629*4887Schin } 630*4887Schin *stakptr(PATH_OFFSET) = 0; 631*4887Schin return(0); 632*4887Schin } 633*4887Schin else if(pp && !sh_isstate(SH_DEFPATH) && *name!='/') 634*4887Schin { 635*4887Schin if(np=nv_search(name,shp->track_tree,NV_ADD)) 636*4887Schin path_alias(np,pp); 637*4887Schin } 638*4887Schin return(0); 639*4887Schin } 640*4887Schin 641*4887Schin 642*4887Schin /* 643*4887Schin * do a path search and find the full pathname of file name 644*4887Schin * end search of path matches endpath without checking execute permission 645*4887Schin */ 646*4887Schin 647*4887Schin Pathcomp_t *path_absolute(register const char *name, Pathcomp_t *endpath) 648*4887Schin { 649*4887Schin register int f,isfun; 650*4887Schin int noexec=0; 651*4887Schin Pathcomp_t *pp,*oldpp; 652*4887Schin Shell_t *shp = &sh; 653*4887Schin Namval_t *np; 654*4887Schin shp->path_err = ENOENT; 655*4887Schin if(!(pp=path_get(""))) 656*4887Schin return(0); 657*4887Schin shp->path_err = 0; 658*4887Schin while(1) 659*4887Schin { 660*4887Schin sh_sigcheck(); 661*4887Schin isfun = (pp->flags&PATH_FPATH); 662*4887Schin if(oldpp=pp) 663*4887Schin pp = path_nextcomp(pp,name,0); 664*4887Schin if(endpath) 665*4887Schin return(endpath); 666*4887Schin if(!isfun && !sh_isoption(SH_RESTRICTED)) 667*4887Schin { 668*4887Schin if(nv_search(stakptr(PATH_OFFSET),sh.bltin_tree,0)) 669*4887Schin return(oldpp); 670*4887Schin if(oldpp->blib) 671*4887Schin { 672*4887Schin typedef int (*Fptr_t)(int, char*[], void*); 673*4887Schin Fptr_t addr; 674*4887Schin int n = staktell(); 675*4887Schin char *cp; 676*4887Schin stakputs("b_"); 677*4887Schin stakputs(name); 678*4887Schin stakputc(0); 679*4887Schin if(!oldpp->bltin_lib) 680*4887Schin { 681*4887Schin if(cp = strrchr(oldpp->blib,'/')) 682*4887Schin cp++; 683*4887Schin else 684*4887Schin cp = oldpp->blib; 685*4887Schin if(strcmp(cp,LIBCMD)==0 && (addr=(Fptr_t)dlllook((void*)0,stakptr(n)))) 686*4887Schin { 687*4887Schin np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL); 688*4887Schin np->nvfun = (Namfun_t*)np->nvname; 689*4887Schin return(oldpp); 690*4887Schin } 691*4887Schin #if (_AST_VERSION>=20040404) 692*4887Schin if (oldpp->bltin_lib = dllplug(SH_ID, oldpp->blib, NiL, RTLD_LAZY, NiL, 0)) 693*4887Schin #else 694*4887Schin if (oldpp->bltin_lib = dllfind(oldpp->blib, NiL, RTLD_LAZY, NiL, 0)) 695*4887Schin #endif 696*4887Schin sh_addlib(oldpp->bltin_lib); 697*4887Schin } 698*4887Schin if((addr=(Fptr_t)dlllook(oldpp->bltin_lib,stakptr(n))) && 699*4887Schin (!(np = sh_addbuiltin(stakptr(PATH_OFFSET),NiL,NiL)) || np->nvalue.bfp!=addr) && 700*4887Schin (np = sh_addbuiltin(stakptr(PATH_OFFSET),addr,NiL))) 701*4887Schin { 702*4887Schin np->nvenv = oldpp->bltin_lib; 703*4887Schin return(oldpp); 704*4887Schin } 705*4887Schin } 706*4887Schin } 707*4887Schin f = canexecute(stakptr(PATH_OFFSET),isfun); 708*4887Schin if(isfun && f>=0) 709*4887Schin { 710*4887Schin nv_onattr(nv_open(name,shp->fun_tree,NV_NOARRAY|NV_IDENT|NV_NOSCOPE),NV_LTOU|NV_FUNCTION); 711*4887Schin close(f); 712*4887Schin f = -1; 713*4887Schin return(0); 714*4887Schin } 715*4887Schin else if(f>=0 && (oldpp->flags & PATH_STD_DIR)) 716*4887Schin { 717*4887Schin int offset = staktell(); 718*4887Schin stakputs("/bin/"); 719*4887Schin stakputs(name); 720*4887Schin stakputc(0); 721*4887Schin np = nv_search(stakptr(offset),sh.bltin_tree,0); 722*4887Schin stakseek(offset); 723*4887Schin if(np) 724*4887Schin { 725*4887Schin np = sh_addbuiltin(stakptr(PATH_OFFSET),np->nvalue.bfp,NiL); 726*4887Schin np->nvfun = (Namfun_t*)np->nvname; 727*4887Schin } 728*4887Schin } 729*4887Schin if(!pp || f>=0) 730*4887Schin break; 731*4887Schin if(errno!=ENOENT) 732*4887Schin noexec = errno; 733*4887Schin } 734*4887Schin if(f<0) 735*4887Schin { 736*4887Schin if(!endpath) 737*4887Schin shp->path_err = (noexec?noexec:ENOENT); 738*4887Schin return(0); 739*4887Schin } 740*4887Schin stakputc(0); 741*4887Schin return(oldpp); 742*4887Schin } 743*4887Schin 744*4887Schin /* 745*4887Schin * returns 0 if path can execute 746*4887Schin * sets exec_err if file is found but can't be executable 747*4887Schin */ 748*4887Schin #undef S_IXALL 749*4887Schin #ifdef S_IXUSR 750*4887Schin # define S_IXALL (S_IXUSR|S_IXGRP|S_IXOTH) 751*4887Schin #else 752*4887Schin # ifdef S_IEXEC 753*4887Schin # define S_IXALL (S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6)) 754*4887Schin # else 755*4887Schin # define S_IXALL 0111 756*4887Schin # endif /*S_EXEC */ 757*4887Schin #endif /* S_IXUSR */ 758*4887Schin 759*4887Schin static int canexecute(register char *path, int isfun) 760*4887Schin { 761*4887Schin struct stat statb; 762*4887Schin register int fd=0; 763*4887Schin path = path_relative(path); 764*4887Schin if(isfun) 765*4887Schin { 766*4887Schin if((fd=open(path,O_RDONLY,0))<0 || fstat(fd,&statb)<0) 767*4887Schin goto err; 768*4887Schin } 769*4887Schin else if(stat(path,&statb) < 0) 770*4887Schin { 771*4887Schin #if _WINIX 772*4887Schin /* check for .exe or .bat suffix */ 773*4887Schin char *cp; 774*4887Schin if(errno==ENOENT && (!(cp=strrchr(path,'.')) || strlen(cp)>4 || strchr(cp,'/'))) 775*4887Schin { 776*4887Schin int offset = staktell()-1; 777*4887Schin stakseek(offset); 778*4887Schin stakputs(".bat"); 779*4887Schin path = stakptr(PATH_OFFSET); 780*4887Schin if(stat(path,&statb) < 0) 781*4887Schin { 782*4887Schin if(errno!=ENOENT) 783*4887Schin goto err; 784*4887Schin memcpy(stakptr(offset),".sh",4); 785*4887Schin if(stat(path,&statb) < 0) 786*4887Schin goto err; 787*4887Schin } 788*4887Schin } 789*4887Schin else 790*4887Schin #endif /* _WINIX */ 791*4887Schin goto err; 792*4887Schin } 793*4887Schin errno = EPERM; 794*4887Schin if(S_ISDIR(statb.st_mode)) 795*4887Schin errno = EISDIR; 796*4887Schin else if((statb.st_mode&S_IXALL)==S_IXALL || sh_access(path,X_OK)>=0) 797*4887Schin return(fd); 798*4887Schin if(isfun && fd>=0) 799*4887Schin sh_close(fd); 800*4887Schin err: 801*4887Schin return(-1); 802*4887Schin } 803*4887Schin 804*4887Schin /* 805*4887Schin * Return path relative to present working directory 806*4887Schin */ 807*4887Schin 808*4887Schin char *path_relative(register const char* file) 809*4887Schin { 810*4887Schin register const char *pwd; 811*4887Schin register const char *fp = file; 812*4887Schin /* can't relpath when sh.pwd not set */ 813*4887Schin if(!(pwd=sh.pwd)) 814*4887Schin return((char*)fp); 815*4887Schin while(*pwd==*fp) 816*4887Schin { 817*4887Schin if(*pwd++==0) 818*4887Schin return((char*)e_dot); 819*4887Schin fp++; 820*4887Schin } 821*4887Schin if(*pwd==0 && *fp == '/') 822*4887Schin { 823*4887Schin while(*++fp=='/'); 824*4887Schin if(*fp) 825*4887Schin return((char*)fp); 826*4887Schin return((char*)e_dot); 827*4887Schin } 828*4887Schin return((char*)file); 829*4887Schin } 830*4887Schin 831*4887Schin void path_exec(register const char *arg0,register char *argv[],struct argnod *local) 832*4887Schin { 833*4887Schin char **envp; 834*4887Schin const char *opath; 835*4887Schin Pathcomp_t *libpath, *pp=0; 836*4887Schin Shell_t *shp = &sh; 837*4887Schin int slash=0; 838*4887Schin nv_setlist(local,NV_EXPORT|NV_IDENT|NV_ASSIGN); 839*4887Schin envp = sh_envgen(); 840*4887Schin if(strchr(arg0,'/')) 841*4887Schin { 842*4887Schin slash=1; 843*4887Schin /* name containing / not allowed for restricted shell */ 844*4887Schin if(sh_isoption(SH_RESTRICTED)) 845*4887Schin errormsg(SH_DICT,ERROR_exit(1),e_restricted,arg0); 846*4887Schin } 847*4887Schin else 848*4887Schin pp=path_get(arg0); 849*4887Schin shp->path_err= ENOENT; 850*4887Schin sfsync(NIL(Sfio_t*)); 851*4887Schin timerdel(NIL(void*)); 852*4887Schin /* find first path that has a library component */ 853*4887Schin if(pp || slash) do 854*4887Schin { 855*4887Schin sh_sigcheck(); 856*4887Schin if(libpath=pp) 857*4887Schin { 858*4887Schin pp = path_nextcomp(pp,arg0,0); 859*4887Schin opath = stakfreeze(1)+PATH_OFFSET; 860*4887Schin } 861*4887Schin else 862*4887Schin opath = arg0; 863*4887Schin path_spawn(opath,argv,envp,libpath,0); 864*4887Schin while(pp && (pp->flags&PATH_FPATH)) 865*4887Schin pp = path_nextcomp(pp,arg0,0); 866*4887Schin } 867*4887Schin while(pp); 868*4887Schin /* force an exit */ 869*4887Schin ((struct checkpt*)shp->jmplist)->mode = SH_JMPEXIT; 870*4887Schin if((errno=shp->path_err)==ENOENT) 871*4887Schin errormsg(SH_DICT,ERROR_exit(ERROR_NOENT),e_found,arg0); 872*4887Schin else 873*4887Schin errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,arg0); 874*4887Schin } 875*4887Schin 876*4887Schin pid_t path_spawn(const char *opath,register char **argv, char **envp, Pathcomp_t *libpath, int spawn) 877*4887Schin { 878*4887Schin Shell_t *shp = sh_getinterp(); 879*4887Schin register char *path; 880*4887Schin char **xp=0, *xval, *libenv = (libpath?libpath->lib:0); 881*4887Schin Namval_t* np; 882*4887Schin char *s, *v; 883*4887Schin int r, n; 884*4887Schin pid_t pid= -1; 885*4887Schin /* leave room for inserting _= pathname in environment */ 886*4887Schin envp--; 887*4887Schin #if _lib_readlink 888*4887Schin /* save original pathname */ 889*4887Schin stakseek(PATH_OFFSET); 890*4887Schin stakputs(opath); 891*4887Schin opath = stakfreeze(1)+PATH_OFFSET; 892*4887Schin np=nv_search(argv[0],shp->track_tree,0); 893*4887Schin while(libpath && !libpath->lib) 894*4887Schin libpath=libpath->next; 895*4887Schin if(libpath && (!np || nv_size(np)>0)) 896*4887Schin { 897*4887Schin /* check for symlink and use symlink name */ 898*4887Schin char buff[PATH_MAX+1]; 899*4887Schin char save[PATH_MAX+1]; 900*4887Schin stakseek(PATH_OFFSET); 901*4887Schin stakputs(opath); 902*4887Schin path = stakptr(PATH_OFFSET); 903*4887Schin while((n=readlink(path,buff,PATH_MAX))>0) 904*4887Schin { 905*4887Schin buff[n] = 0; 906*4887Schin n = PATH_OFFSET; 907*4887Schin r = 0; 908*4887Schin if((v=strrchr(path,'/')) && *buff!='/') 909*4887Schin { 910*4887Schin if(buff[0]=='.' && buff[1]=='.' && (r = strlen(path) + 1) <= PATH_MAX) 911*4887Schin memcpy(save, path, r); 912*4887Schin else 913*4887Schin r = 0; 914*4887Schin n += (v+1-path); 915*4887Schin } 916*4887Schin stakseek(n); 917*4887Schin stakputs(buff); 918*4887Schin stakputc(0); 919*4887Schin path = stakptr(PATH_OFFSET); 920*4887Schin if(v && buff[0]=='.' && buff[1]=='.') 921*4887Schin { 922*4887Schin pathcanon(path, 0); 923*4887Schin if(r && access(path,X_OK)) 924*4887Schin { 925*4887Schin memcpy(path, save, r); 926*4887Schin break; 927*4887Schin } 928*4887Schin } 929*4887Schin if(libenv = path_lib(libpath,path)) 930*4887Schin break; 931*4887Schin } 932*4887Schin stakseek(0); 933*4887Schin } 934*4887Schin #endif 935*4887Schin if(libenv && (v = strchr(libenv,'='))) 936*4887Schin { 937*4887Schin n = v - libenv; 938*4887Schin *v = 0; 939*4887Schin np = nv_open(libenv,shp->var_tree,0); 940*4887Schin *v = '='; 941*4887Schin s = nv_getval(np); 942*4887Schin stakputs(libenv); 943*4887Schin if(s) 944*4887Schin { 945*4887Schin stakputc(':'); 946*4887Schin stakputs(s); 947*4887Schin } 948*4887Schin v = stakfreeze(1); 949*4887Schin r = 1; 950*4887Schin xp = envp + 2; 951*4887Schin while (s = *xp++) 952*4887Schin { 953*4887Schin if (strneq(s, v, n) && s[n] == '=') 954*4887Schin { 955*4887Schin xval = *--xp; 956*4887Schin *xp = v; 957*4887Schin r = 0; 958*4887Schin break; 959*4887Schin } 960*4887Schin } 961*4887Schin if (r) 962*4887Schin { 963*4887Schin *envp-- = v; 964*4887Schin xp = 0; 965*4887Schin } 966*4887Schin } 967*4887Schin if(!opath) 968*4887Schin opath = stakptr(PATH_OFFSET); 969*4887Schin envp[0] = (char*)opath-PATH_OFFSET; 970*4887Schin envp[0][0] = '_'; 971*4887Schin envp[0][1] = '='; 972*4887Schin sfsync(sfstderr); 973*4887Schin sh_sigcheck(); 974*4887Schin path = path_relative(opath); 975*4887Schin #ifdef SHELLMAGIC 976*4887Schin if(*path!='/' && path!=opath) 977*4887Schin { 978*4887Schin /* 979*4887Schin * The following code because execv(foo,) and execv(./foo,) 980*4887Schin * may not yield the same results 981*4887Schin */ 982*4887Schin char *sp = (char*)malloc(strlen(path)+3); 983*4887Schin sp[0] = '.'; 984*4887Schin sp[1] = '/'; 985*4887Schin strcpy(sp+2,path); 986*4887Schin path = sp; 987*4887Schin } 988*4887Schin #endif /* SHELLMAGIC */ 989*4887Schin if(sh_isoption(SH_RESTRICTED)) 990*4887Schin { 991*4887Schin int fd; 992*4887Schin if((fd = sh_open(opath,O_RDONLY,0)) >= 0) 993*4887Schin { 994*4887Schin char buff[PATH_MAX]; 995*4887Schin n = read(fd,buff,sizeof(buff)); 996*4887Schin close(fd); 997*4887Schin if(n>2 && buff[0]=='#' && buff[1]=='!') 998*4887Schin { 999*4887Schin for(s=buff; n>0 && *s!='\n'; n--,s++) 1000*4887Schin { 1001*4887Schin if(*s=='/') 1002*4887Schin errormsg(SH_DICT,ERROR_exit(1),e_restricted,opath); 1003*4887Schin } 1004*4887Schin } 1005*4887Schin } 1006*4887Schin } 1007*4887Schin if(spawn && !sh_isoption(SH_PFSH)) 1008*4887Schin pid = _spawnveg(opath, &argv[0],envp, spawn>>1); 1009*4887Schin else 1010*4887Schin path_pfexecve(opath, &argv[0] ,envp); 1011*4887Schin if(xp) 1012*4887Schin *xp = xval; 1013*4887Schin #ifdef SHELLMAGIC 1014*4887Schin if(*path=='.' && path!=opath) 1015*4887Schin { 1016*4887Schin free(path); 1017*4887Schin path = path_relative(opath); 1018*4887Schin } 1019*4887Schin #endif /* SHELLMAGIC */ 1020*4887Schin if(pid>0) 1021*4887Schin return(pid); 1022*4887Schin retry: 1023*4887Schin switch(sh.path_err = errno) 1024*4887Schin { 1025*4887Schin #ifdef apollo 1026*4887Schin /* 1027*4887Schin * On apollo's execve will fail with eacces when 1028*4887Schin * file has execute but not read permissions. So, 1029*4887Schin * for now we will pretend that EACCES and ENOEXEC 1030*4887Schin * mean the same thing. 1031*4887Schin */ 1032*4887Schin case EACCES: 1033*4887Schin #endif /* apollo */ 1034*4887Schin case ENOEXEC: 1035*4887Schin #if SHOPT_SUID_EXEC 1036*4887Schin case EPERM: 1037*4887Schin /* some systems return EPERM if setuid bit is on */ 1038*4887Schin #endif 1039*4887Schin errno = ENOEXEC; 1040*4887Schin if(spawn) 1041*4887Schin { 1042*4887Schin #ifdef _lib_fork 1043*4887Schin if(sh.subshell) 1044*4887Schin return(-1); 1045*4887Schin do 1046*4887Schin { 1047*4887Schin if((pid=fork())>0) 1048*4887Schin return(pid); 1049*4887Schin } 1050*4887Schin while(_sh_fork(pid,0,(int*)0) < 0); 1051*4887Schin #else 1052*4887Schin return(-1); 1053*4887Schin #endif 1054*4887Schin } 1055*4887Schin exscript(shp,path,argv,envp); 1056*4887Schin #ifndef apollo 1057*4887Schin case EACCES: 1058*4887Schin { 1059*4887Schin struct stat statb; 1060*4887Schin if(stat(path,&statb)>=0) 1061*4887Schin { 1062*4887Schin if(S_ISDIR(statb.st_mode)) 1063*4887Schin errno = EISDIR; 1064*4887Schin #ifdef S_ISSOCK 1065*4887Schin if(S_ISSOCK(statb.st_mode)) 1066*4887Schin exscript(shp,path,argv,envp); 1067*4887Schin #endif 1068*4887Schin } 1069*4887Schin } 1070*4887Schin /* FALL THROUGH */ 1071*4887Schin #endif /* !apollo */ 1072*4887Schin #ifdef ENAMETOOLONG 1073*4887Schin case ENAMETOOLONG: 1074*4887Schin #endif /* ENAMETOOLONG */ 1075*4887Schin #if !SHOPT_SUID_EXEC 1076*4887Schin case EPERM: 1077*4887Schin #endif 1078*4887Schin shp->path_err = errno; 1079*4887Schin return(-1); 1080*4887Schin case ENOTDIR: 1081*4887Schin case ENOENT: 1082*4887Schin case EINTR: 1083*4887Schin #ifdef EMLINK 1084*4887Schin case EMLINK: 1085*4887Schin #endif /* EMLINK */ 1086*4887Schin return(-1); 1087*4887Schin case E2BIG: 1088*4887Schin if(sh.xargmin) 1089*4887Schin { 1090*4887Schin pid = path_xargs(opath, &argv[0] ,envp,spawn); 1091*4887Schin if(pid<0) 1092*4887Schin goto retry; 1093*4887Schin return(pid); 1094*4887Schin } 1095*4887Schin default: 1096*4887Schin errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path); 1097*4887Schin } 1098*4887Schin return 0; 1099*4887Schin } 1100*4887Schin 1101*4887Schin /* 1102*4887Schin * File is executable but not machine code. 1103*4887Schin * Assume file is a Shell script and execute it. 1104*4887Schin */ 1105*4887Schin 1106*4887Schin static void exscript(Shell_t *shp,register char *path,register char *argv[],char **envp) 1107*4887Schin { 1108*4887Schin register Sfio_t *sp; 1109*4887Schin path = path_relative(path); 1110*4887Schin shp->comdiv=0; 1111*4887Schin shp->bckpid = 0; 1112*4887Schin shp->st.ioset=0; 1113*4887Schin /* clean up any cooperating processes */ 1114*4887Schin if(shp->cpipe[0]>0) 1115*4887Schin sh_pclose(shp->cpipe); 1116*4887Schin if(shp->cpid && shp->outpipe) 1117*4887Schin sh_close(*shp->outpipe); 1118*4887Schin shp->cpid = 0; 1119*4887Schin if(sp=fcfile()) 1120*4887Schin while(sfstack(sp,SF_POPSTACK)); 1121*4887Schin job_clear(); 1122*4887Schin if(shp->infd>0 && (shp->fdstatus[shp->infd]&IOCLEX)) 1123*4887Schin sh_close(shp->infd); 1124*4887Schin sh_setstate(sh_state(SH_FORKED)); 1125*4887Schin sfsync(sfstderr); 1126*4887Schin #if SHOPT_SUID_EXEC && !SHOPT_PFSH 1127*4887Schin /* check if file cannot open for read or script is setuid/setgid */ 1128*4887Schin { 1129*4887Schin static char name[] = "/tmp/euidXXXXXXXXXX"; 1130*4887Schin register int n; 1131*4887Schin register uid_t euserid; 1132*4887Schin char *savet=0; 1133*4887Schin struct stat statb; 1134*4887Schin if((n=sh_open(path,O_RDONLY,0)) >= 0) 1135*4887Schin { 1136*4887Schin /* move <n> if n=0,1,2 */ 1137*4887Schin n = sh_iomovefd(n); 1138*4887Schin if(fstat(n,&statb)>=0 && !(statb.st_mode&(S_ISUID|S_ISGID))) 1139*4887Schin goto openok; 1140*4887Schin sh_close(n); 1141*4887Schin } 1142*4887Schin if((euserid=geteuid()) != shp->userid) 1143*4887Schin { 1144*4887Schin strncpy(name+9,fmtbase((long)getpid(),10,0),sizeof(name)-10); 1145*4887Schin /* create a suid open file with owner equal effective uid */ 1146*4887Schin if((n=open(name,O_CREAT|O_TRUNC|O_WRONLY,S_ISUID|S_IXUSR)) < 0) 1147*4887Schin goto fail; 1148*4887Schin unlink(name); 1149*4887Schin /* make sure that file has right owner */ 1150*4887Schin if(fstat(n,&statb)<0 || statb.st_uid != euserid) 1151*4887Schin goto fail; 1152*4887Schin if(n!=10) 1153*4887Schin { 1154*4887Schin sh_close(10); 1155*4887Schin fcntl(n, F_DUPFD, 10); 1156*4887Schin sh_close(n); 1157*4887Schin n=10; 1158*4887Schin } 1159*4887Schin } 1160*4887Schin savet = *--argv; 1161*4887Schin *argv = path; 1162*4887Schin path_pfexecve(e_suidexec,argv,envp); 1163*4887Schin fail: 1164*4887Schin /* 1165*4887Schin * The following code is just for compatibility 1166*4887Schin */ 1167*4887Schin if((n=open(path,O_RDONLY,0)) < 0) 1168*4887Schin errormsg(SH_DICT,ERROR_system(1),e_open,path); 1169*4887Schin if(savet) 1170*4887Schin *argv++ = savet; 1171*4887Schin openok: 1172*4887Schin shp->infd = n; 1173*4887Schin } 1174*4887Schin #else 1175*4887Schin shp->infd = sh_chkopen(path); 1176*4887Schin #endif 1177*4887Schin shp->infd = sh_iomovefd(shp->infd); 1178*4887Schin #if SHOPT_ACCT 1179*4887Schin sh_accbegin(path) ; /* reset accounting */ 1180*4887Schin #endif /* SHOPT_ACCT */ 1181*4887Schin shp->arglist = sh_argcreate(argv); 1182*4887Schin shp->lastarg = strdup(path); 1183*4887Schin /* save name of calling command */ 1184*4887Schin shp->readscript = error_info.id; 1185*4887Schin /* close history file if name has changed */ 1186*4887Schin if(shp->hist_ptr && (path=nv_getval(HISTFILE)) && strcmp(path,shp->hist_ptr->histname)) 1187*4887Schin { 1188*4887Schin hist_close(shp->hist_ptr); 1189*4887Schin (HISTCUR)->nvalue.lp = 0; 1190*4887Schin } 1191*4887Schin sh_offstate(SH_FORKED); 1192*4887Schin siglongjmp(*shp->jmplist,SH_JMPSCRIPT); 1193*4887Schin } 1194*4887Schin 1195*4887Schin #if SHOPT_ACCT 1196*4887Schin # include <sys/acct.h> 1197*4887Schin # include "FEATURE/time" 1198*4887Schin 1199*4887Schin static struct acct sabuf; 1200*4887Schin static struct tms buffer; 1201*4887Schin static clock_t before; 1202*4887Schin static char *SHACCT; /* set to value of SHACCT environment variable */ 1203*4887Schin static shaccton; /* non-zero causes accounting record to be written */ 1204*4887Schin static int compress(time_t); 1205*4887Schin /* 1206*4887Schin * initialize accounting, i.e., see if SHACCT variable set 1207*4887Schin */ 1208*4887Schin void sh_accinit(void) 1209*4887Schin { 1210*4887Schin SHACCT = getenv("SHACCT"); 1211*4887Schin } 1212*4887Schin /* 1213*4887Schin * suspend accounting unitl turned on by sh_accbegin() 1214*4887Schin */ 1215*4887Schin void sh_accsusp(void) 1216*4887Schin { 1217*4887Schin shaccton=0; 1218*4887Schin #ifdef AEXPAND 1219*4887Schin sabuf.ac_flag |= AEXPND; 1220*4887Schin #endif /* AEXPAND */ 1221*4887Schin } 1222*4887Schin 1223*4887Schin /* 1224*4887Schin * begin an accounting record by recording start time 1225*4887Schin */ 1226*4887Schin void sh_accbegin(const char *cmdname) 1227*4887Schin { 1228*4887Schin if(SHACCT) 1229*4887Schin { 1230*4887Schin sabuf.ac_btime = time(NIL(time_t *)); 1231*4887Schin before = times(&buffer); 1232*4887Schin sabuf.ac_uid = getuid(); 1233*4887Schin sabuf.ac_gid = getgid(); 1234*4887Schin strncpy(sabuf.ac_comm, (char*)path_basename(cmdname), 1235*4887Schin sizeof(sabuf.ac_comm)); 1236*4887Schin shaccton = 1; 1237*4887Schin } 1238*4887Schin } 1239*4887Schin /* 1240*4887Schin * terminate an accounting record and append to accounting file 1241*4887Schin */ 1242*4887Schin void sh_accend(void) 1243*4887Schin { 1244*4887Schin int fd; 1245*4887Schin clock_t after; 1246*4887Schin 1247*4887Schin if(shaccton) 1248*4887Schin { 1249*4887Schin after = times(&buffer); 1250*4887Schin sabuf.ac_utime = compress(buffer.tms_utime + buffer.tms_cutime); 1251*4887Schin sabuf.ac_stime = compress(buffer.tms_stime + buffer.tms_cstime); 1252*4887Schin sabuf.ac_etime = compress( (time_t)(after-before)); 1253*4887Schin fd = open( SHACCT , O_WRONLY | O_APPEND | O_CREAT,RW_ALL); 1254*4887Schin write(fd, (const char*)&sabuf, sizeof( sabuf )); 1255*4887Schin close( fd); 1256*4887Schin } 1257*4887Schin } 1258*4887Schin 1259*4887Schin /* 1260*4887Schin * Produce a pseudo-floating point representation 1261*4887Schin * with 3 bits base-8 exponent, 13 bits fraction. 1262*4887Schin */ 1263*4887Schin static int compress(register time_t t) 1264*4887Schin { 1265*4887Schin register int exp = 0, rund = 0; 1266*4887Schin 1267*4887Schin while (t >= 8192) 1268*4887Schin { 1269*4887Schin exp++; 1270*4887Schin rund = t&04; 1271*4887Schin t >>= 3; 1272*4887Schin } 1273*4887Schin if (rund) 1274*4887Schin { 1275*4887Schin t++; 1276*4887Schin if (t >= 8192) 1277*4887Schin { 1278*4887Schin t >>= 3; 1279*4887Schin exp++; 1280*4887Schin } 1281*4887Schin } 1282*4887Schin return((exp<<13) + t); 1283*4887Schin } 1284*4887Schin #endif /* SHOPT_ACCT */ 1285*4887Schin 1286*4887Schin 1287*4887Schin 1288*4887Schin /* 1289*4887Schin * add a pathcomponent to the path search list and eliminate duplicates 1290*4887Schin * and non-existing absolute paths. 1291*4887Schin */ 1292*4887Schin static Pathcomp_t *path_addcomp(Pathcomp_t *first, Pathcomp_t *old,const char *name, int flag) 1293*4887Schin { 1294*4887Schin register Pathcomp_t *pp, *oldpp; 1295*4887Schin struct stat statb; 1296*4887Schin int len, offset=staktell(); 1297*4887Schin if(!(flag&PATH_BFPATH)) 1298*4887Schin { 1299*4887Schin register const char *cp = name; 1300*4887Schin while(*cp && *cp!=':') 1301*4887Schin stakputc(*cp++); 1302*4887Schin len = staktell()-offset; 1303*4887Schin stakputc(0); 1304*4887Schin stakseek(offset); 1305*4887Schin name = (const char*)stakptr(offset); 1306*4887Schin } 1307*4887Schin else 1308*4887Schin len = strlen(name); 1309*4887Schin for(pp=first; pp; pp=pp->next) 1310*4887Schin { 1311*4887Schin if(memcmp(name,pp->name,len)==0 && (pp->name[len]==':' || pp->name[len]==0)) 1312*4887Schin { 1313*4887Schin pp->flags |= flag; 1314*4887Schin return(first); 1315*4887Schin } 1316*4887Schin } 1317*4887Schin if(old && (old=path_dirfind(old,name,0))) 1318*4887Schin { 1319*4887Schin statb.st_ino = old->ino; 1320*4887Schin statb.st_dev = old->dev; 1321*4887Schin if(old->ino==0 && old->dev==0) 1322*4887Schin flag |= PATH_SKIP; 1323*4887Schin } 1324*4887Schin else if(stat(name,&statb)<0 || !S_ISDIR(statb.st_mode)) 1325*4887Schin { 1326*4887Schin if(*name=='/') 1327*4887Schin { 1328*4887Schin if(strcmp(name,SH_CMDLIB_DIR)) 1329*4887Schin return(first); 1330*4887Schin statb.st_dev = 1; 1331*4887Schin } 1332*4887Schin else 1333*4887Schin { 1334*4887Schin flag |= PATH_SKIP; 1335*4887Schin statb.st_dev = 0; 1336*4887Schin } 1337*4887Schin statb.st_ino = 0; 1338*4887Schin } 1339*4887Schin if(*name=='/' && onstdpath(name)) 1340*4887Schin flag |= PATH_STD_DIR; 1341*4887Schin for(pp=first, oldpp=0; pp; oldpp=pp, pp=pp->next) 1342*4887Schin { 1343*4887Schin if(pp->ino==statb.st_ino && pp->dev==statb.st_dev) 1344*4887Schin { 1345*4887Schin /* if both absolute paths, eliminate second */ 1346*4887Schin pp->flags |= flag; 1347*4887Schin if(*name=='/' && *pp->name=='/') 1348*4887Schin return(first); 1349*4887Schin /* keep the path but mark it as skip */ 1350*4887Schin flag |= PATH_SKIP; 1351*4887Schin } 1352*4887Schin } 1353*4887Schin pp = newof((Pathcomp_t*)0,Pathcomp_t,1,len+1); 1354*4887Schin pp->refcount = 1; 1355*4887Schin memcpy((char*)(pp+1),name,len+1); 1356*4887Schin pp->name = (char*)(pp+1); 1357*4887Schin pp->len = len; 1358*4887Schin pp->dev = statb.st_dev; 1359*4887Schin pp->ino = statb.st_ino; 1360*4887Schin if(oldpp) 1361*4887Schin oldpp->next = pp; 1362*4887Schin else 1363*4887Schin first = pp; 1364*4887Schin pp->flags = flag; 1365*4887Schin if(pp->ino==0 && pp->dev==1) 1366*4887Schin { 1367*4887Schin pp->flags |= PATH_BUILTIN_LIB; 1368*4887Schin pp->blib = malloc(4); 1369*4887Schin strcpy(pp->blib,LIBCMD); 1370*4887Schin return(first); 1371*4887Schin } 1372*4887Schin if((flag&(PATH_PATH|PATH_SKIP))==PATH_PATH) 1373*4887Schin path_chkpaths(first,old,pp,offset); 1374*4887Schin return(first); 1375*4887Schin } 1376*4887Schin 1377*4887Schin /* 1378*4887Schin * This function checks for the .paths file in directory in <pp> 1379*4887Schin * it assumes that the directory is on the stack at <offset> 1380*4887Schin */ 1381*4887Schin static int path_chkpaths(Pathcomp_t *first, Pathcomp_t* old,Pathcomp_t *pp, int offset) 1382*4887Schin { 1383*4887Schin struct stat statb; 1384*4887Schin int k,m,n,fd; 1385*4887Schin char *sp,*cp,*ep; 1386*4887Schin stakseek(offset+pp->len); 1387*4887Schin if(pp->len==1 && *stakptr(offset)=='/') 1388*4887Schin stakseek(offset); 1389*4887Schin stakputs("/.paths"); 1390*4887Schin if((fd=open(stakptr(offset),O_RDONLY))>=0) 1391*4887Schin { 1392*4887Schin fstat(fd,&statb); 1393*4887Schin n = statb.st_size; 1394*4887Schin stakseek(offset+pp->len+n+2); 1395*4887Schin sp = stakptr(offset+pp->len); 1396*4887Schin *sp++ = '/'; 1397*4887Schin n=read(fd,cp=sp,n); 1398*4887Schin sp[n] = 0; 1399*4887Schin close(fd); 1400*4887Schin for(ep=0; n--; cp++) 1401*4887Schin { 1402*4887Schin if(*cp=='=') 1403*4887Schin { 1404*4887Schin ep = cp+1; 1405*4887Schin continue; 1406*4887Schin } 1407*4887Schin else if(*cp!='\r' && *cp!='\n') 1408*4887Schin continue; 1409*4887Schin if(*sp=='#' || sp==cp) 1410*4887Schin { 1411*4887Schin sp = cp+1; 1412*4887Schin continue; 1413*4887Schin } 1414*4887Schin *cp = 0; 1415*4887Schin m = ep ? (ep-sp) : 0; 1416*4887Schin if(!m || m==6 && memcmp((void*)sp,(void*)"FPATH=",6)==0) 1417*4887Schin { 1418*4887Schin if(first) 1419*4887Schin { 1420*4887Schin char *ptr = stakptr(offset+pp->len+1); 1421*4887Schin if(ep) 1422*4887Schin strcpy(ptr,ep); 1423*4887Schin path_addcomp(first,old,stakptr(offset),PATH_FPATH|PATH_BFPATH); 1424*4887Schin } 1425*4887Schin } 1426*4887Schin else if(m==12 && memcmp((void*)sp,(void*)"BUILTIN_LIB=",12)==0) 1427*4887Schin { 1428*4887Schin if(!(pp->flags & PATH_BUILTIN_LIB)) 1429*4887Schin { 1430*4887Schin pp->flags |= PATH_BUILTIN_LIB; 1431*4887Schin if (*ep == '.' && !*(ep + 1)) 1432*4887Schin pp->flags |= PATH_STD_DIR; 1433*4887Schin else 1434*4887Schin { 1435*4887Schin k = strlen(ep)+1; 1436*4887Schin if (*ep != '/') 1437*4887Schin k += pp->len+1; 1438*4887Schin pp->blib = sp = malloc(k); 1439*4887Schin if (*ep != '/') 1440*4887Schin { 1441*4887Schin strcpy(pp->blib,pp->name); 1442*4887Schin sp += pp->len; 1443*4887Schin *sp++ = '/'; 1444*4887Schin } 1445*4887Schin strcpy(sp,ep); 1446*4887Schin } 1447*4887Schin } 1448*4887Schin } 1449*4887Schin else if(m) 1450*4887Schin { 1451*4887Schin pp->lib = (char*)malloc(cp-sp+pp->len+2); 1452*4887Schin memcpy((void*)pp->lib,(void*)sp,m); 1453*4887Schin memcpy((void*)&pp->lib[m],stakptr(offset),pp->len); 1454*4887Schin pp->lib[k=m+pp->len] = '/'; 1455*4887Schin strcpy((void*)&pp->lib[k+1],ep); 1456*4887Schin pathcanon(&pp->lib[m],0); 1457*4887Schin if(!first) 1458*4887Schin { 1459*4887Schin stakseek(0); 1460*4887Schin stakputs(pp->lib); 1461*4887Schin free((void*)pp->lib); 1462*4887Schin return(1); 1463*4887Schin } 1464*4887Schin } 1465*4887Schin sp = cp+1; 1466*4887Schin ep = 0; 1467*4887Schin } 1468*4887Schin } 1469*4887Schin return(0); 1470*4887Schin } 1471*4887Schin 1472*4887Schin 1473*4887Schin Pathcomp_t *path_addpath(Pathcomp_t *first, register const char *path,int type) 1474*4887Schin { 1475*4887Schin register const char *cp; 1476*4887Schin Pathcomp_t *old=0; 1477*4887Schin int offset = staktell(); 1478*4887Schin char *savptr; 1479*4887Schin 1480*4887Schin if(!path && type!=PATH_PATH) 1481*4887Schin return(first); 1482*4887Schin if(type!=PATH_FPATH) 1483*4887Schin { 1484*4887Schin old = first; 1485*4887Schin first = 0; 1486*4887Schin } 1487*4887Schin if(offset) 1488*4887Schin savptr = stakfreeze(0); 1489*4887Schin if(path) while(*(cp=path)) 1490*4887Schin { 1491*4887Schin if(*cp==':') 1492*4887Schin { 1493*4887Schin if(type!=PATH_FPATH) 1494*4887Schin first = path_addcomp(first,old,".",type); 1495*4887Schin while(*++path == ':'); 1496*4887Schin } 1497*4887Schin else 1498*4887Schin { 1499*4887Schin int c; 1500*4887Schin while(*path && *path!=':') 1501*4887Schin path++; 1502*4887Schin c = *path++; 1503*4887Schin first = path_addcomp(first,old,cp,type); 1504*4887Schin if(c==0) 1505*4887Schin break; 1506*4887Schin if(*path==0) 1507*4887Schin path--; 1508*4887Schin } 1509*4887Schin } 1510*4887Schin if(old) 1511*4887Schin { 1512*4887Schin if(!first && !path) 1513*4887Schin { 1514*4887Schin Pathcomp_t *pp = (Pathcomp_t*)old->shp->defpathlist; 1515*4887Schin if(!pp) 1516*4887Schin pp = defpath_init(old->shp); 1517*4887Schin first = path_dup(pp); 1518*4887Schin } 1519*4887Schin if(cp=(FPATHNOD)->nvalue.cp) 1520*4887Schin first = (void*)path_addpath((Pathcomp_t*)first,cp,PATH_FPATH); 1521*4887Schin path_delete(old); 1522*4887Schin } 1523*4887Schin if(offset) 1524*4887Schin stakset(savptr,offset); 1525*4887Schin else 1526*4887Schin stakseek(0); 1527*4887Schin return(first); 1528*4887Schin } 1529*4887Schin 1530*4887Schin /* 1531*4887Schin * duplicate the path give by <first> by incremented reference counts 1532*4887Schin */ 1533*4887Schin Pathcomp_t *path_dup(Pathcomp_t *first) 1534*4887Schin { 1535*4887Schin register Pathcomp_t *pp=first; 1536*4887Schin while(pp) 1537*4887Schin { 1538*4887Schin pp->refcount++; 1539*4887Schin pp = pp->next; 1540*4887Schin } 1541*4887Schin return(first); 1542*4887Schin } 1543*4887Schin 1544*4887Schin /* 1545*4887Schin * called whenever the directory is changed 1546*4887Schin */ 1547*4887Schin void path_newdir(Pathcomp_t *first) 1548*4887Schin { 1549*4887Schin register Pathcomp_t *pp=first, *next, *pq; 1550*4887Schin struct stat statb; 1551*4887Schin for(pp=first; pp; pp=pp->next) 1552*4887Schin { 1553*4887Schin pp->flags &= ~PATH_SKIP; 1554*4887Schin if(*pp->name=='/') 1555*4887Schin continue; 1556*4887Schin /* delete .paths component */ 1557*4887Schin if((next=pp->next) && (next->flags&PATH_BFPATH)) 1558*4887Schin { 1559*4887Schin pp->next = next->next; 1560*4887Schin if(--next->refcount<=0) 1561*4887Schin free((void*)next); 1562*4887Schin } 1563*4887Schin if(stat(pp->name,&statb)<0 || !S_ISDIR(statb.st_mode)) 1564*4887Schin { 1565*4887Schin pp->dev = 0; 1566*4887Schin pp->ino = 0; 1567*4887Schin continue; 1568*4887Schin } 1569*4887Schin pp->dev = statb.st_dev; 1570*4887Schin pp->ino = statb.st_ino; 1571*4887Schin for(pq=first;pq!=pp;pq=pq->next) 1572*4887Schin { 1573*4887Schin if(pp->ino==pq->ino && pp->dev==pq->dev) 1574*4887Schin pp->flags |= PATH_SKIP; 1575*4887Schin } 1576*4887Schin for(pq=pp;pq=pq->next;) 1577*4887Schin { 1578*4887Schin if(pp->ino==pq->ino && pp->dev==pq->dev) 1579*4887Schin pq->flags |= PATH_SKIP; 1580*4887Schin } 1581*4887Schin if((pp->flags&(PATH_PATH|PATH_SKIP))==PATH_PATH) 1582*4887Schin { 1583*4887Schin /* try to insert .paths component */ 1584*4887Schin int offset = staktell(); 1585*4887Schin stakputs(pp->name); 1586*4887Schin stakseek(offset); 1587*4887Schin next = pp->next; 1588*4887Schin pp->next = 0; 1589*4887Schin path_chkpaths(first,(Pathcomp_t*)0,pp,offset); 1590*4887Schin if(pp->next) 1591*4887Schin pp = pp->next; 1592*4887Schin pp->next = next; 1593*4887Schin } 1594*4887Schin } 1595*4887Schin #if 0 1596*4887Schin path_dump(first); 1597*4887Schin #endif 1598*4887Schin } 1599*4887Schin 1600*4887Schin Pathcomp_t *path_unsetfpath(Pathcomp_t *first) 1601*4887Schin { 1602*4887Schin register Pathcomp_t *pp=first, *old=0; 1603*4887Schin while(pp) 1604*4887Schin { 1605*4887Schin if((pp->flags&PATH_FPATH) && !(pp->flags&PATH_BFPATH)) 1606*4887Schin { 1607*4887Schin if(pp->flags&PATH_PATH) 1608*4887Schin pp->flags &= ~PATH_FPATH; 1609*4887Schin else 1610*4887Schin { 1611*4887Schin Pathcomp_t *ppsave=pp; 1612*4887Schin if(old) 1613*4887Schin old->next = pp->next; 1614*4887Schin else 1615*4887Schin first = pp->next; 1616*4887Schin pp = pp->next; 1617*4887Schin if(--ppsave->refcount<=0) 1618*4887Schin { 1619*4887Schin if(ppsave->lib) 1620*4887Schin free((void*)ppsave->lib); 1621*4887Schin free((void*)ppsave); 1622*4887Schin } 1623*4887Schin continue; 1624*4887Schin } 1625*4887Schin 1626*4887Schin } 1627*4887Schin old = pp; 1628*4887Schin pp = pp->next; 1629*4887Schin } 1630*4887Schin return(first); 1631*4887Schin } 1632*4887Schin 1633*4887Schin Pathcomp_t *path_dirfind(Pathcomp_t *first,const char *name,int c) 1634*4887Schin { 1635*4887Schin register Pathcomp_t *pp=first; 1636*4887Schin while(pp) 1637*4887Schin { 1638*4887Schin if(memcmp(name,pp->name,pp->len)==0 && name[pp->len]==c) 1639*4887Schin return(pp); 1640*4887Schin pp = pp->next; 1641*4887Schin } 1642*4887Schin return(0); 1643*4887Schin } 1644*4887Schin 1645*4887Schin /* 1646*4887Schin * get discipline for tracked alias 1647*4887Schin */ 1648*4887Schin static char *talias_get(Namval_t *np, Namfun_t *nvp) 1649*4887Schin { 1650*4887Schin Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp; 1651*4887Schin char *ptr; 1652*4887Schin if(!pp) 1653*4887Schin return(NULL); 1654*4887Schin path_nextcomp(pp,nv_name(np),pp); 1655*4887Schin ptr = stakfreeze(0); 1656*4887Schin return(ptr+PATH_OFFSET); 1657*4887Schin } 1658*4887Schin 1659*4887Schin static void talias_put(register Namval_t* np,const char *val,int flags,Namfun_t *fp) 1660*4887Schin { 1661*4887Schin if(!val && np->nvalue.cp) 1662*4887Schin { 1663*4887Schin Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp; 1664*4887Schin if(--pp->refcount<=0) 1665*4887Schin free((void*)pp); 1666*4887Schin } 1667*4887Schin nv_putv(np,val,flags,fp); 1668*4887Schin } 1669*4887Schin 1670*4887Schin static const Namdisc_t talias_disc = { 0, talias_put, talias_get }; 1671*4887Schin static Namfun_t talias_init = { &talias_disc, 1 }; 1672*4887Schin 1673*4887Schin /* 1674*4887Schin * set tracked alias node <np> to value <pp> 1675*4887Schin */ 1676*4887Schin void path_alias(register Namval_t *np,register Pathcomp_t *pp) 1677*4887Schin { 1678*4887Schin if(pp) 1679*4887Schin { 1680*4887Schin struct stat statb; 1681*4887Schin char *sp; 1682*4887Schin nv_offattr(np,NV_NOPRINT); 1683*4887Schin nv_stack(np,&talias_init); 1684*4887Schin np->nvalue.cp = (char*)pp; 1685*4887Schin pp->refcount++; 1686*4887Schin nv_setattr(np,NV_TAGGED|NV_NOFREE); 1687*4887Schin path_nextcomp(pp,nv_name(np),pp); 1688*4887Schin sp = stakptr(PATH_OFFSET); 1689*4887Schin if(sp && lstat(sp,&statb)>=0 && S_ISLNK(statb.st_mode)) 1690*4887Schin nv_setsize(np,statb.st_size+1); 1691*4887Schin else 1692*4887Schin nv_setsize(np,0); 1693*4887Schin } 1694*4887Schin else 1695*4887Schin nv_unset(np); 1696*4887Schin } 1697*4887Schin 1698