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 * 23*4887Schin * Shell initialization 24*4887Schin * 25*4887Schin * David Korn 26*4887Schin * AT&T Labs 27*4887Schin * 28*4887Schin */ 29*4887Schin 30*4887Schin #include "defs.h" 31*4887Schin #include <stak.h> 32*4887Schin #include <ctype.h> 33*4887Schin #include <ccode.h> 34*4887Schin #include <pwd.h> 35*4887Schin #include "variables.h" 36*4887Schin #include "path.h" 37*4887Schin #include "fault.h" 38*4887Schin #include "name.h" 39*4887Schin #include "edit.h" 40*4887Schin #include "jobs.h" 41*4887Schin #include "io.h" 42*4887Schin #include "shlex.h" 43*4887Schin #include "builtins.h" 44*4887Schin #include "FEATURE/time" 45*4887Schin #include "FEATURE/dynamic" 46*4887Schin #include "lexstates.h" 47*4887Schin #include "version.h" 48*4887Schin 49*4887Schin #if SHOPT_MULTIBYTE 50*4887Schin char e_version[] = "\n@(#)$Id: Version M "SH_RELEASE" $\0\n"; 51*4887Schin #else 52*4887Schin char e_version[] = "\n@(#)$Id: Version "SH_RELEASE" $\0\n"; 53*4887Schin #endif /* SHOPT_MULTIBYTE */ 54*4887Schin 55*4887Schin #if SHOPT_BASH 56*4887Schin extern void bash_init(int); 57*4887Schin #endif 58*4887Schin 59*4887Schin #define RANDMASK 0x7fff 60*4887Schin #ifndef CLK_TCK 61*4887Schin # define CLK_TCK 60 62*4887Schin #endif /* CLK_TCK */ 63*4887Schin 64*4887Schin #ifndef environ 65*4887Schin extern char **environ; 66*4887Schin #endif 67*4887Schin 68*4887Schin #undef getconf 69*4887Schin #define getconf(x) strtol(astconf(x,NiL,NiL),NiL,0) 70*4887Schin 71*4887Schin struct seconds 72*4887Schin { 73*4887Schin Namfun_t hdr; 74*4887Schin Shell_t *sh; 75*4887Schin }; 76*4887Schin 77*4887Schin struct rand 78*4887Schin { 79*4887Schin Namfun_t hdr; 80*4887Schin Shell_t *sh; 81*4887Schin int32_t rand_last; 82*4887Schin }; 83*4887Schin 84*4887Schin struct ifs 85*4887Schin { 86*4887Schin Namfun_t hdr; 87*4887Schin Shell_t *sh; 88*4887Schin Namval_t *ifsnp; 89*4887Schin }; 90*4887Schin 91*4887Schin struct shell 92*4887Schin { 93*4887Schin Namfun_t hdr; 94*4887Schin Shell_t *sh; 95*4887Schin }; 96*4887Schin 97*4887Schin struct match 98*4887Schin { 99*4887Schin Namfun_t hdr; 100*4887Schin char *val; 101*4887Schin char *rval; 102*4887Schin int vsize; 103*4887Schin int nmatch; 104*4887Schin int lastsub; 105*4887Schin int match[2*(MATCH_MAX+1)]; 106*4887Schin }; 107*4887Schin 108*4887Schin typedef struct _init_ 109*4887Schin { 110*4887Schin Shell_t *sh; 111*4887Schin #if SHOPT_FS_3D 112*4887Schin Namfun_t VPATH_init; 113*4887Schin #endif /* SHOPT_FS_3D */ 114*4887Schin struct ifs IFS_init; 115*4887Schin struct shell PATH_init; 116*4887Schin #ifdef PATH_BFPATH 117*4887Schin struct shell FPATH_init; 118*4887Schin struct shell CDPATH_init; 119*4887Schin #endif 120*4887Schin struct shell SHELL_init; 121*4887Schin struct shell ENV_init; 122*4887Schin struct shell VISUAL_init; 123*4887Schin struct shell EDITOR_init; 124*4887Schin struct shell OPTINDEX_init; 125*4887Schin struct seconds SECONDS_init; 126*4887Schin struct rand RAND_init; 127*4887Schin struct shell LINENO_init; 128*4887Schin struct shell L_ARG_init; 129*4887Schin struct match SH_MATCH_init; 130*4887Schin #ifdef _hdr_locale 131*4887Schin struct shell LC_TYPE_init; 132*4887Schin struct shell LC_NUM_init; 133*4887Schin struct shell LC_COLL_init; 134*4887Schin struct shell LC_MSG_init; 135*4887Schin struct shell LC_ALL_init; 136*4887Schin struct shell LANG_init; 137*4887Schin #endif /* _hdr_locale */ 138*4887Schin } Init_t; 139*4887Schin 140*4887Schin static void env_init(Shell_t*); 141*4887Schin static Init_t *nv_init(Shell_t*); 142*4887Schin static Dt_t *inittree(Shell_t*,const struct shtable2*); 143*4887Schin 144*4887Schin #ifdef _WINIX 145*4887Schin # define EXE "?(.exe)" 146*4887Schin #else 147*4887Schin # define EXE 148*4887Schin #endif 149*4887Schin 150*4887Schin static int rand_shift; 151*4887Schin 152*4887Schin 153*4887Schin /* 154*4887Schin * Invalidate all path name bindings 155*4887Schin */ 156*4887Schin static void rehash(register Namval_t *np,void *data) 157*4887Schin { 158*4887Schin NOT_USED(data); 159*4887Schin nv_onattr(np,NV_NOALIAS); 160*4887Schin } 161*4887Schin 162*4887Schin /* 163*4887Schin * out of memory routine for stak routines 164*4887Schin */ 165*4887Schin static char *nospace(int unused) 166*4887Schin { 167*4887Schin NOT_USED(unused); 168*4887Schin errormsg(SH_DICT,ERROR_exit(3),e_nospace); 169*4887Schin return(NIL(char*)); 170*4887Schin } 171*4887Schin 172*4887Schin /* Trap for VISUAL and EDITOR variables */ 173*4887Schin static void put_ed(register Namval_t* np,const char *val,int flags,Namfun_t *fp) 174*4887Schin { 175*4887Schin register const char *cp, *name=nv_name(np); 176*4887Schin if(*name=='E' && nv_getval(nv_scoped(VISINOD))) 177*4887Schin goto done; 178*4887Schin sh_offoption(SH_VI); 179*4887Schin sh_offoption(SH_EMACS); 180*4887Schin sh_offoption(SH_GMACS); 181*4887Schin if(!(cp=val) && (*name=='E' || !(cp=nv_getval(nv_scoped(EDITNOD))))) 182*4887Schin goto done; 183*4887Schin /* turn on vi or emacs option if editor name is either*/ 184*4887Schin cp = path_basename(cp); 185*4887Schin if(strmatch(cp,"*[Vv][Ii]*")) 186*4887Schin sh_onoption(SH_VI); 187*4887Schin else if(strmatch(cp,"*gmacs*")) 188*4887Schin sh_onoption(SH_GMACS); 189*4887Schin else if(strmatch(cp,"*macs*")) 190*4887Schin sh_onoption(SH_EMACS); 191*4887Schin done: 192*4887Schin nv_putv(np, val, flags, fp); 193*4887Schin } 194*4887Schin 195*4887Schin /* Trap for OPTINDEX */ 196*4887Schin static void put_optindex(Namval_t* np,const char *val,int flags,Namfun_t *fp) 197*4887Schin { 198*4887Schin Shell_t *shp = ((struct shell*)fp)->sh; 199*4887Schin shp->st.opterror = shp->st.optchar = 0; 200*4887Schin nv_putv(np, val, flags, fp); 201*4887Schin } 202*4887Schin 203*4887Schin static Sfdouble_t nget_optindex(register Namval_t* np, Namfun_t *fp) 204*4887Schin { 205*4887Schin return((Sfdouble_t)*np->nvalue.lp); 206*4887Schin } 207*4887Schin 208*4887Schin /* Trap for restricted variables FPATH, PATH, SHELL, ENV */ 209*4887Schin static void put_restricted(register Namval_t* np,const char *val,int flags,Namfun_t *fp) 210*4887Schin { 211*4887Schin Shell_t *shp = ((struct shell*)fp)->sh; 212*4887Schin int path_scoped = 0; 213*4887Schin #ifdef PATH_BFPATH 214*4887Schin Pathcomp_t *pp; 215*4887Schin char *name = nv_name(np); 216*4887Schin #endif 217*4887Schin if(!(flags&NV_RDONLY) && sh_isoption(SH_RESTRICTED)) 218*4887Schin errormsg(SH_DICT,ERROR_exit(1),e_restricted,nv_name(np)); 219*4887Schin if(np==PATHNOD || (path_scoped=(strcmp(name,PATHNOD->nvname)==0))) 220*4887Schin { 221*4887Schin #ifndef PATH_BFPATH 222*4887Schin shp->lastpath = 0; 223*4887Schin #endif 224*4887Schin nv_scan(shp->track_tree,rehash,(void*)0,NV_TAGGED,NV_TAGGED); 225*4887Schin if(path_scoped && !val) 226*4887Schin val = PATHNOD->nvalue.cp; 227*4887Schin } 228*4887Schin if(val && !(flags&NV_RDONLY) && np->nvalue.cp && strcmp(val,np->nvalue.cp)==0) 229*4887Schin return; 230*4887Schin #ifdef PATH_BFPATH 231*4887Schin if(shp->pathlist && np==FPATHNOD) 232*4887Schin shp->pathlist = (void*)path_unsetfpath((Pathcomp_t*)shp->pathlist); 233*4887Schin #endif 234*4887Schin nv_putv(np, val, flags, fp); 235*4887Schin #ifdef PATH_BFPATH 236*4887Schin if(shp->pathlist) 237*4887Schin { 238*4887Schin val = np->nvalue.cp; 239*4887Schin if(np==PATHNOD || path_scoped) 240*4887Schin pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_PATH); 241*4887Schin else if(val && np==FPATHNOD) 242*4887Schin pp = (void*)path_addpath((Pathcomp_t*)shp->pathlist,val,PATH_FPATH); 243*4887Schin else 244*4887Schin return; 245*4887Schin if(shp->pathlist = (void*)pp) 246*4887Schin pp->shp = shp; 247*4887Schin if(!val && (flags&NV_NOSCOPE)) 248*4887Schin { 249*4887Schin Namval_t *mp = dtsearch(shp->var_tree,np); 250*4887Schin if(mp && (val=nv_getval(mp))) 251*4887Schin nv_putval(mp,val,NV_RDONLY); 252*4887Schin } 253*4887Schin #if 0 254*4887Schin sfprintf(sfstderr,"%d: name=%s val=%s\n",getpid(),name,val); 255*4887Schin path_dump((Pathcomp_t*)shp->pathlist); 256*4887Schin #endif 257*4887Schin } 258*4887Schin #endif 259*4887Schin } 260*4887Schin 261*4887Schin #ifdef PATH_BFPATH 262*4887Schin static void put_cdpath(register Namval_t* np,const char *val,int flags,Namfun_t *fp) 263*4887Schin { 264*4887Schin Pathcomp_t *pp; 265*4887Schin Shell_t *shp = ((struct shell*)fp)->sh; 266*4887Schin nv_putv(np, val, flags, fp); 267*4887Schin if(!shp->cdpathlist) 268*4887Schin return; 269*4887Schin val = np->nvalue.cp; 270*4887Schin pp = (void*)path_addpath((Pathcomp_t*)shp->cdpathlist,val,PATH_CDPATH); 271*4887Schin if(shp->cdpathlist = (void*)pp) 272*4887Schin pp->shp = shp; 273*4887Schin } 274*4887Schin #endif 275*4887Schin 276*4887Schin #ifdef _hdr_locale 277*4887Schin /* 278*4887Schin * This function needs to be modified to handle international 279*4887Schin * error message translations 280*4887Schin */ 281*4887Schin #if ERROR_VERSION >= 20000101L 282*4887Schin static char* msg_translate(const char* catalog, const char* message) 283*4887Schin { 284*4887Schin NOT_USED(catalog); 285*4887Schin return((char*)message); 286*4887Schin } 287*4887Schin #else 288*4887Schin static char* msg_translate(const char* message, int type) 289*4887Schin { 290*4887Schin NOT_USED(type); 291*4887Schin return((char*)message); 292*4887Schin } 293*4887Schin #endif 294*4887Schin 295*4887Schin /* Trap for LC_ALL, LC_TYPE, LC_MESSAGES, LC_COLLATE and LANG */ 296*4887Schin static void put_lang(Namval_t* np,const char *val,int flags,Namfun_t *fp) 297*4887Schin { 298*4887Schin int type; 299*4887Schin char *lc_all = nv_getval(LCALLNOD); 300*4887Schin char *name = nv_name(np); 301*4887Schin if(name==(LCALLNOD)->nvname) 302*4887Schin type = LC_ALL; 303*4887Schin else if(name==(LCTYPENOD)->nvname) 304*4887Schin type = LC_CTYPE; 305*4887Schin else if(name==(LCMSGNOD)->nvname) 306*4887Schin type = LC_MESSAGES; 307*4887Schin else if(name==(LCCOLLNOD)->nvname) 308*4887Schin type = LC_COLLATE; 309*4887Schin else if(name==(LCNUMNOD)->nvname) 310*4887Schin type = LC_NUMERIC; 311*4887Schin else if(name==(LANGNOD)->nvname && (!lc_all || *lc_all==0)) 312*4887Schin type = LC_ALL; 313*4887Schin else 314*4887Schin type= -1; 315*4887Schin if(sh_isstate(SH_INIT) && type>=0 && type!=LC_ALL && lc_all && *lc_all) 316*4887Schin type= -1; 317*4887Schin if(type>=0) 318*4887Schin { 319*4887Schin if(!setlocale(type,val?val:"")) 320*4887Schin { 321*4887Schin if(!sh_isstate(SH_INIT) || sh.login_sh==0) 322*4887Schin errormsg(SH_DICT,0,e_badlocale,val); 323*4887Schin return; 324*4887Schin } 325*4887Schin } 326*4887Schin if(CC_NATIVE==CC_ASCII && (type==LC_ALL || type==LC_CTYPE)) 327*4887Schin { 328*4887Schin if(sh_lexstates[ST_BEGIN]!=sh_lexrstates[ST_BEGIN]) 329*4887Schin free((void*)sh_lexstates[ST_BEGIN]); 330*4887Schin if(ast.locale.set&(1<<AST_LC_CTYPE)) 331*4887Schin { 332*4887Schin register int c; 333*4887Schin char *state[4]; 334*4887Schin sh_lexstates[ST_BEGIN] = state[0] = (char*)malloc(4*(1<<CHAR_BIT)); 335*4887Schin memcpy(state[0],sh_lexrstates[ST_BEGIN],(1<<CHAR_BIT)); 336*4887Schin sh_lexstates[ST_NAME] = state[1] = state[0] + (1<<CHAR_BIT); 337*4887Schin memcpy(state[1],sh_lexrstates[ST_NAME],(1<<CHAR_BIT)); 338*4887Schin sh_lexstates[ST_DOL] = state[2] = state[1] + (1<<CHAR_BIT); 339*4887Schin memcpy(state[2],sh_lexrstates[ST_DOL],(1<<CHAR_BIT)); 340*4887Schin sh_lexstates[ST_BRACE] = state[3] = state[2] + (1<<CHAR_BIT); 341*4887Schin memcpy(state[3],sh_lexrstates[ST_BRACE],(1<<CHAR_BIT)); 342*4887Schin for(c=0; c<(1<<CHAR_BIT); c++) 343*4887Schin { 344*4887Schin if(state[0][c]!=S_REG) 345*4887Schin continue; 346*4887Schin if(state[2][c]!=S_ERR) 347*4887Schin continue; 348*4887Schin if(isblank(c)) 349*4887Schin { 350*4887Schin state[0][c]=0; 351*4887Schin state[1][c]=S_BREAK; 352*4887Schin state[2][c]=S_BREAK; 353*4887Schin continue; 354*4887Schin } 355*4887Schin if(!isalpha(c)) 356*4887Schin continue; 357*4887Schin state[0][c]=S_NAME; 358*4887Schin if(state[1][c]==S_REG) 359*4887Schin state[1][c]=0; 360*4887Schin state[2][c]=S_ALP; 361*4887Schin if(state[3][c]==S_ERR) 362*4887Schin state[3][c]=0; 363*4887Schin } 364*4887Schin } 365*4887Schin else 366*4887Schin { 367*4887Schin sh_lexstates[ST_BEGIN]=(char*)sh_lexrstates[ST_BEGIN]; 368*4887Schin sh_lexstates[ST_NAME]=(char*)sh_lexrstates[ST_NAME]; 369*4887Schin sh_lexstates[ST_DOL]=(char*)sh_lexrstates[ST_DOL]; 370*4887Schin sh_lexstates[ST_BRACE]=(char*)sh_lexrstates[ST_BRACE]; 371*4887Schin } 372*4887Schin } 373*4887Schin #if ERROR_VERSION < 20000101L 374*4887Schin if(type==LC_ALL || type==LC_MESSAGES) 375*4887Schin error_info.translate = msg_translate; 376*4887Schin #endif 377*4887Schin nv_putv(np, val, flags, fp); 378*4887Schin } 379*4887Schin #endif /* _hdr_locale */ 380*4887Schin 381*4887Schin /* Trap for IFS assignment and invalidates state table */ 382*4887Schin static void put_ifs(register Namval_t* np,const char *val,int flags,Namfun_t *fp) 383*4887Schin { 384*4887Schin register struct ifs *ip = (struct ifs*)fp; 385*4887Schin ip->ifsnp = 0; 386*4887Schin if(val != np->nvalue.cp) 387*4887Schin nv_putv(np, val, flags, fp); 388*4887Schin 389*4887Schin } 390*4887Schin 391*4887Schin /* 392*4887Schin * This is the lookup function for IFS 393*4887Schin * It keeps the sh.ifstable up to date 394*4887Schin */ 395*4887Schin static char* get_ifs(register Namval_t* np, Namfun_t *fp) 396*4887Schin { 397*4887Schin register struct ifs *ip = (struct ifs*)fp; 398*4887Schin register char *cp, *value; 399*4887Schin register int c,n; 400*4887Schin register Shell_t *shp = ip->sh; 401*4887Schin value = nv_getv(np,fp); 402*4887Schin if(np!=ip->ifsnp) 403*4887Schin { 404*4887Schin ip->ifsnp = np; 405*4887Schin memset(shp->ifstable,0,(1<<CHAR_BIT)); 406*4887Schin if(cp=value) 407*4887Schin { 408*4887Schin #if SHOPT_MULTIBYTE 409*4887Schin while(n=mbsize(cp),c= *(unsigned char*)cp) 410*4887Schin #else 411*4887Schin while(c= *(unsigned char*)cp++) 412*4887Schin #endif /* SHOPT_MULTIBYTE */ 413*4887Schin { 414*4887Schin #if SHOPT_MULTIBYTE 415*4887Schin cp++; 416*4887Schin if(n>1) 417*4887Schin { 418*4887Schin cp += (n-1); 419*4887Schin shp->ifstable[c] = S_MBYTE; 420*4887Schin continue; 421*4887Schin } 422*4887Schin #endif /* SHOPT_MULTIBYTE */ 423*4887Schin n = S_DELIM; 424*4887Schin if(c== *cp) 425*4887Schin cp++; 426*4887Schin else if(c=='\n') 427*4887Schin n = S_NL; 428*4887Schin else if(isspace(c)) 429*4887Schin n = S_SPACE; 430*4887Schin shp->ifstable[c] = n; 431*4887Schin } 432*4887Schin } 433*4887Schin else 434*4887Schin { 435*4887Schin shp->ifstable[' '] = shp->ifstable['\t'] = S_SPACE; 436*4887Schin shp->ifstable['\n'] = S_NL; 437*4887Schin } 438*4887Schin } 439*4887Schin return(value); 440*4887Schin } 441*4887Schin 442*4887Schin /* 443*4887Schin * these functions are used to get and set the SECONDS variable 444*4887Schin */ 445*4887Schin #ifdef timeofday 446*4887Schin # define dtime(tp) ((double)((tp)->tv_sec)+1e-6*((double)((tp)->tv_usec))) 447*4887Schin # define tms timeval 448*4887Schin #else 449*4887Schin # define dtime(tp) (((double)times(tp))/sh.lim.clk_tck) 450*4887Schin # define timeofday(a) 451*4887Schin #endif 452*4887Schin 453*4887Schin static void put_seconds(register Namval_t* np,const char *val,int flags,Namfun_t *fp) 454*4887Schin { 455*4887Schin double d; 456*4887Schin struct tms tp; 457*4887Schin if(!val) 458*4887Schin { 459*4887Schin nv_stack(np, NIL(Namfun_t*)); 460*4887Schin nv_unset(np); 461*4887Schin return; 462*4887Schin } 463*4887Schin if(!np->nvalue.dp) 464*4887Schin { 465*4887Schin nv_setsize(np,3); 466*4887Schin np->nvalue.dp = new_of(double,0); 467*4887Schin } 468*4887Schin nv_putv(np, val, flags, fp); 469*4887Schin d = *np->nvalue.dp; 470*4887Schin timeofday(&tp); 471*4887Schin *np->nvalue.dp = dtime(&tp)-d; 472*4887Schin } 473*4887Schin 474*4887Schin static char* get_seconds(register Namval_t* np, Namfun_t *fp) 475*4887Schin { 476*4887Schin register int places = nv_size(np); 477*4887Schin struct tms tp; 478*4887Schin double d, offset = (np->nvalue.dp?*np->nvalue.dp:0); 479*4887Schin NOT_USED(fp); 480*4887Schin timeofday(&tp); 481*4887Schin d = dtime(&tp)- offset; 482*4887Schin sfprintf(sh.strbuf,"%.*f",places,d); 483*4887Schin return(sfstruse(sh.strbuf)); 484*4887Schin } 485*4887Schin 486*4887Schin static Sfdouble_t nget_seconds(register Namval_t* np, Namfun_t *fp) 487*4887Schin { 488*4887Schin struct tms tp; 489*4887Schin double offset = (np->nvalue.dp?*np->nvalue.dp:0); 490*4887Schin NOT_USED(fp); 491*4887Schin timeofday(&tp); 492*4887Schin return(dtime(&tp)- offset); 493*4887Schin } 494*4887Schin 495*4887Schin /* 496*4887Schin * These three functions are used to get and set the RANDOM variable 497*4887Schin */ 498*4887Schin static void put_rand(register Namval_t* np,const char *val,int flags,Namfun_t *fp) 499*4887Schin { 500*4887Schin struct rand *rp = (struct rand*)fp; 501*4887Schin register long n; 502*4887Schin if(!val) 503*4887Schin { 504*4887Schin nv_stack(np, NIL(Namfun_t*)); 505*4887Schin nv_unset(np); 506*4887Schin return; 507*4887Schin } 508*4887Schin if(flags&NV_INTEGER) 509*4887Schin n = *(double*)val; 510*4887Schin else 511*4887Schin n = sh_arith(val); 512*4887Schin srand((int)(n&RANDMASK)); 513*4887Schin rp->rand_last = -1; 514*4887Schin if(!np->nvalue.lp) 515*4887Schin np->nvalue.lp = &rp->rand_last; 516*4887Schin } 517*4887Schin 518*4887Schin /* 519*4887Schin * get random number in range of 0 - 2**15 520*4887Schin * never pick same number twice in a row 521*4887Schin */ 522*4887Schin static Sfdouble_t nget_rand(register Namval_t* np, Namfun_t *fp) 523*4887Schin { 524*4887Schin register long cur, last= *np->nvalue.lp; 525*4887Schin NOT_USED(fp); 526*4887Schin do 527*4887Schin cur = (rand()>>rand_shift)&RANDMASK; 528*4887Schin while(cur==last); 529*4887Schin *np->nvalue.lp = cur; 530*4887Schin return((Sfdouble_t)cur); 531*4887Schin } 532*4887Schin 533*4887Schin static char* get_rand(register Namval_t* np, Namfun_t *fp) 534*4887Schin { 535*4887Schin register long n = nget_rand(np,fp); 536*4887Schin return(fmtbase(n, 10, 0)); 537*4887Schin } 538*4887Schin 539*4887Schin /* 540*4887Schin * These three routines are for LINENO 541*4887Schin */ 542*4887Schin static Sfdouble_t nget_lineno(Namval_t* np, Namfun_t *fp) 543*4887Schin { 544*4887Schin double d=1; 545*4887Schin if(error_info.line >0) 546*4887Schin d = error_info.line; 547*4887Schin else if(error_info.context && error_info.context->line>0) 548*4887Schin d = error_info.context->line; 549*4887Schin NOT_USED(np); 550*4887Schin NOT_USED(fp); 551*4887Schin return(d); 552*4887Schin } 553*4887Schin 554*4887Schin static void put_lineno(Namval_t* np,const char *val,int flags,Namfun_t *fp) 555*4887Schin { 556*4887Schin register long n; 557*4887Schin Shell_t *shp = ((struct shell*)fp)->sh; 558*4887Schin if(!val) 559*4887Schin { 560*4887Schin nv_stack(np, NIL(Namfun_t*)); 561*4887Schin nv_unset(np); 562*4887Schin return; 563*4887Schin } 564*4887Schin if(flags&NV_INTEGER) 565*4887Schin n = *(double*)val; 566*4887Schin else 567*4887Schin n = sh_arith(val); 568*4887Schin shp->st.firstline += nget_lineno(np,fp)+1-n; 569*4887Schin } 570*4887Schin 571*4887Schin static char* get_lineno(register Namval_t* np, Namfun_t *fp) 572*4887Schin { 573*4887Schin register long n = nget_lineno(np,fp); 574*4887Schin return(fmtbase(n, 10, 0)); 575*4887Schin } 576*4887Schin 577*4887Schin static char* get_lastarg(Namval_t* np, Namfun_t *fp) 578*4887Schin { 579*4887Schin NOT_USED(np); 580*4887Schin return(sh.lastarg); 581*4887Schin } 582*4887Schin 583*4887Schin static void put_lastarg(Namval_t* np,const char *val,int flags,Namfun_t *fp) 584*4887Schin { 585*4887Schin if(flags&NV_INTEGER) 586*4887Schin { 587*4887Schin sfprintf(sh.strbuf,"%.*g",12,*((double*)val)); 588*4887Schin val = sfstruse(sh.strbuf); 589*4887Schin } 590*4887Schin if(sh.lastarg && !nv_isattr(np,NV_NOFREE)) 591*4887Schin free((void*)sh.lastarg); 592*4887Schin else 593*4887Schin nv_offattr(np,NV_NOFREE); 594*4887Schin if(val) 595*4887Schin sh.lastarg = strdup(val); 596*4887Schin else 597*4887Schin sh.lastarg = 0; 598*4887Schin } 599*4887Schin 600*4887Schin static int hasgetdisc(register Namfun_t *fp) 601*4887Schin { 602*4887Schin while(fp && !fp->disc->getnum && !fp->disc->getval) 603*4887Schin fp = fp->next; 604*4887Schin return(fp!=0); 605*4887Schin } 606*4887Schin 607*4887Schin /* 608*4887Schin * store the most recent value for use in .sh.match 609*4887Schin */ 610*4887Schin void sh_setmatch(const char *v, int vsize, int nmatch, int match[]) 611*4887Schin { 612*4887Schin struct match *mp = (struct match*)(SH_MATCHNOD->nvfun); 613*4887Schin register int i,n; 614*4887Schin if(mp->nmatch = nmatch) 615*4887Schin { 616*4887Schin memcpy(mp->match,match,nmatch*2*sizeof(match[0])); 617*4887Schin for(n=match[0],i=1; i < 2*nmatch; i++) 618*4887Schin { 619*4887Schin if(mp->match[i] < n) 620*4887Schin n = mp->match[i]; 621*4887Schin } 622*4887Schin for(vsize=0,i=0; i < 2*nmatch; i++) 623*4887Schin { 624*4887Schin if((mp->match[i] -= n) > vsize) 625*4887Schin vsize = mp->match[i]; 626*4887Schin } 627*4887Schin v += n; 628*4887Schin if(vsize >= mp->vsize) 629*4887Schin { 630*4887Schin if(mp->vsize) 631*4887Schin mp->val = (char*)realloc(mp->val,vsize+1); 632*4887Schin else 633*4887Schin mp->val = (char*)malloc(vsize+1); 634*4887Schin mp->vsize = vsize; 635*4887Schin } 636*4887Schin memcpy(mp->val,v,vsize); 637*4887Schin mp->val[vsize] = 0; 638*4887Schin nv_putsub(SH_MATCHNOD, NIL(char*), nmatch|ARRAY_FILL); 639*4887Schin mp->lastsub = -1; 640*4887Schin } 641*4887Schin } 642*4887Schin 643*4887Schin #define array_scan(np) ((nv_arrayptr(np)->nelem&ARRAY_SCAN)) 644*4887Schin 645*4887Schin static char* get_match(register Namval_t* np, Namfun_t *fp) 646*4887Schin { 647*4887Schin struct match *mp = (struct match*)fp; 648*4887Schin int sub,n; 649*4887Schin char *val; 650*4887Schin sub = nv_aindex(np); 651*4887Schin if(sub>=mp->nmatch) 652*4887Schin return(0); 653*4887Schin if(sub==mp->lastsub) 654*4887Schin return(mp->rval); 655*4887Schin if(mp->rval) 656*4887Schin { 657*4887Schin free((void*)mp->rval); 658*4887Schin mp->rval = 0; 659*4887Schin } 660*4887Schin n = mp->match[2*sub+1]-mp->match[2*sub]; 661*4887Schin if(n<=0) 662*4887Schin return(""); 663*4887Schin val = mp->val+mp->match[2*sub]; 664*4887Schin if(mp->val[mp->match[2*sub+1]]==0) 665*4887Schin return(val); 666*4887Schin mp->rval = (char*)malloc(n+1); 667*4887Schin mp->lastsub = sub; 668*4887Schin memcpy(mp->rval,val,n); 669*4887Schin mp->rval[n] = 0; 670*4887Schin return(mp->rval); 671*4887Schin } 672*4887Schin 673*4887Schin static const Namdisc_t SH_MATCH_disc = { sizeof(struct match), 0, get_match }; 674*4887Schin 675*4887Schin #if SHOPT_FS_3D 676*4887Schin /* 677*4887Schin * set or unset the mappings given a colon separated list of directories 678*4887Schin */ 679*4887Schin static void vpath_set(char *str, int mode) 680*4887Schin { 681*4887Schin register char *lastp, *oldp=str, *newp=strchr(oldp,':'); 682*4887Schin if(!sh.lim.fs3d) 683*4887Schin return; 684*4887Schin while(newp) 685*4887Schin { 686*4887Schin *newp++ = 0; 687*4887Schin if(lastp=strchr(newp,':')) 688*4887Schin *lastp = 0; 689*4887Schin mount((mode?newp:""),oldp,FS3D_VIEW,0); 690*4887Schin newp[-1] = ':'; 691*4887Schin oldp = newp; 692*4887Schin newp=lastp; 693*4887Schin } 694*4887Schin } 695*4887Schin 696*4887Schin /* catch vpath assignments */ 697*4887Schin static void put_vpath(register Namval_t* np,const char *val,int flags,Namfun_t *fp) 698*4887Schin { 699*4887Schin register char *cp; 700*4887Schin if(cp = nv_getval(np)) 701*4887Schin vpath_set(cp,0); 702*4887Schin if(val) 703*4887Schin vpath_set((char*)val,1); 704*4887Schin nv_putv(np,val,flags,fp); 705*4887Schin } 706*4887Schin static const Namdisc_t VPATH_disc = { 0, put_vpath }; 707*4887Schin static Namfun_t VPATH_init = { &VPATH_disc, 1 }; 708*4887Schin #endif /* SHOPT_FS_3D */ 709*4887Schin 710*4887Schin 711*4887Schin static const Namdisc_t IFS_disc = { sizeof(struct ifs), put_ifs, get_ifs }; 712*4887Schin const Namdisc_t RESTRICTED_disc = { sizeof(struct shell), put_restricted }; 713*4887Schin #ifdef PATH_BFPATH 714*4887Schin static const Namdisc_t CDPATH_disc = { sizeof(struct shell), put_cdpath }; 715*4887Schin #endif 716*4887Schin static const Namdisc_t EDITOR_disc = { sizeof(struct shell), put_ed }; 717*4887Schin static const Namdisc_t OPTINDEX_disc = { sizeof(struct shell), put_optindex, 0, nget_optindex }; 718*4887Schin static const Namdisc_t SECONDS_disc = { sizeof(struct seconds), put_seconds, get_seconds, nget_seconds }; 719*4887Schin static const Namdisc_t RAND_disc = { sizeof(struct rand), put_rand, get_rand, nget_rand }; 720*4887Schin static const Namdisc_t LINENO_disc = { sizeof(struct shell), put_lineno, get_lineno, nget_lineno }; 721*4887Schin static const Namdisc_t L_ARG_disc = { sizeof(struct shell), put_lastarg, get_lastarg }; 722*4887Schin 723*4887Schin #if SHOPT_NAMESPACE 724*4887Schin static char* get_nspace(Namval_t* np, Namfun_t *fp) 725*4887Schin { 726*4887Schin if(sh.namespace) 727*4887Schin return(nv_name(sh.namespace)); 728*4887Schin return((char*)np->nvalue.cp); 729*4887Schin } 730*4887Schin static const Namdisc_t NSPACE_disc = { 0, 0, get_nspace }; 731*4887Schin static Namfun_t NSPACE_init = { &NSPACE_disc, 1}; 732*4887Schin #endif /* SHOPT_NAMESPACE */ 733*4887Schin 734*4887Schin #ifdef _hdr_locale 735*4887Schin static const Namdisc_t LC_disc = { sizeof(struct shell), put_lang }; 736*4887Schin #endif /* _hdr_locale */ 737*4887Schin 738*4887Schin /* 739*4887Schin * This function will get called whenever a configuration parameter changes 740*4887Schin */ 741*4887Schin static int newconf(const char *name, const char *path, const char *value) 742*4887Schin { 743*4887Schin register char *arg; 744*4887Schin if(!name) 745*4887Schin setenviron(value); 746*4887Schin else if(strcmp(name,"UNIVERSE")==0 && strcmp(astconf(name,0,0),value)) 747*4887Schin { 748*4887Schin sh.universe = 0; 749*4887Schin /* set directory in new universe */ 750*4887Schin if(*(arg = path_pwd(0))=='/') 751*4887Schin chdir(arg); 752*4887Schin /* clear out old tracked alias */ 753*4887Schin stakseek(0); 754*4887Schin stakputs(nv_getval(PATHNOD)); 755*4887Schin stakputc(0); 756*4887Schin nv_putval(PATHNOD,stakseek(0),NV_RDONLY); 757*4887Schin } 758*4887Schin return(1); 759*4887Schin } 760*4887Schin 761*4887Schin #if (CC_NATIVE != CC_ASCII) 762*4887Schin static void a2e(char *d, const char *s) 763*4887Schin { 764*4887Schin register const unsigned char *t; 765*4887Schin register int i; 766*4887Schin t = CCMAP(CC_ASCII, CC_NATIVE); 767*4887Schin for(i=0; i<(1<<CHAR_BIT); i++) 768*4887Schin d[t[i]] = s[i]; 769*4887Schin } 770*4887Schin 771*4887Schin static void init_ebcdic(void) 772*4887Schin { 773*4887Schin int i; 774*4887Schin char *cp = (char*)malloc(ST_NONE*(1<<CHAR_BIT)); 775*4887Schin for(i=0; i < ST_NONE; i++) 776*4887Schin { 777*4887Schin a2e(cp,sh_lexrstates[i]); 778*4887Schin sh_lexstates[i] = cp; 779*4887Schin cp += (1<<CHAR_BIT); 780*4887Schin } 781*4887Schin } 782*4887Schin #endif 783*4887Schin 784*4887Schin /* 785*4887Schin * return SH_TYPE_* bitmask for path 786*4887Schin * 0 for "not a shell" 787*4887Schin */ 788*4887Schin int sh_type(register const char *path) 789*4887Schin { 790*4887Schin register const char* s; 791*4887Schin register int t = 0; 792*4887Schin 793*4887Schin if (s = (const char*)strrchr(path, '/')) 794*4887Schin { 795*4887Schin if (*path == '-') 796*4887Schin t |= SH_TYPE_LOGIN; 797*4887Schin s++; 798*4887Schin } 799*4887Schin else 800*4887Schin s = path; 801*4887Schin if (*s == '-') 802*4887Schin { 803*4887Schin s++; 804*4887Schin t |= SH_TYPE_LOGIN; 805*4887Schin } 806*4887Schin for (;;) 807*4887Schin { 808*4887Schin if (!(t & (SH_TYPE_KSH|SH_TYPE_BASH))) 809*4887Schin { 810*4887Schin if (*s == 'k') 811*4887Schin { 812*4887Schin s++; 813*4887Schin t |= SH_TYPE_KSH; 814*4887Schin continue; 815*4887Schin } 816*4887Schin #if SHOPT_BASH 817*4887Schin if (*s == 'b' && *(s+1) == 'a') 818*4887Schin { 819*4887Schin s += 2; 820*4887Schin t |= SH_TYPE_BASH; 821*4887Schin continue; 822*4887Schin } 823*4887Schin #endif 824*4887Schin } 825*4887Schin if (!(t & (SH_TYPE_PROFILE|SH_TYPE_RESTRICTED))) 826*4887Schin { 827*4887Schin #if SHOPT_PFSH 828*4887Schin if (*s == 'p' && *(s+1) == 'f') 829*4887Schin { 830*4887Schin s += 2; 831*4887Schin t |= SH_TYPE_PROFILE; 832*4887Schin continue; 833*4887Schin } 834*4887Schin #endif 835*4887Schin if (*s == 'r') 836*4887Schin { 837*4887Schin s++; 838*4887Schin t |= SH_TYPE_RESTRICTED; 839*4887Schin continue; 840*4887Schin } 841*4887Schin } 842*4887Schin break; 843*4887Schin } 844*4887Schin if (*s++ != 's' || *s++ != 'h') 845*4887Schin return 0; 846*4887Schin t |= SH_TYPE_SH; 847*4887Schin if ((t & SH_TYPE_KSH) && *s == '9' && *(s+1) == '3') 848*4887Schin s += 2; 849*4887Schin #if _WINIX 850*4887Schin if (*s == '.' && *(s+1) == 'e' && *(s+2) == 'x' && *(s+3) == 'e') 851*4887Schin s += 4; 852*4887Schin #endif 853*4887Schin if (*s) 854*4887Schin t &= ~(SH_TYPE_PROFILE|SH_TYPE_RESTRICTED); 855*4887Schin return t; 856*4887Schin } 857*4887Schin 858*4887Schin /* 859*4887Schin * initialize the shell 860*4887Schin */ 861*4887Schin Shell_t *sh_init(register int argc,register char *argv[], void(*userinit)(int)) 862*4887Schin { 863*4887Schin register int n; 864*4887Schin int type; 865*4887Schin static char *login_files[3]; 866*4887Schin n = strlen(e_version); 867*4887Schin if(e_version[n-1]=='$' && e_version[n-2]==' ') 868*4887Schin e_version[n-2]=0; 869*4887Schin #if (CC_NATIVE == CC_ASCII) 870*4887Schin memcpy(sh_lexstates,sh_lexrstates,ST_NONE*sizeof(char*)); 871*4887Schin #else 872*4887Schin init_ebcdic(); 873*4887Schin #endif 874*4887Schin umask(umask(0)); 875*4887Schin sh.mac_context = sh_macopen(&sh); 876*4887Schin sh.arg_context = sh_argopen(&sh); 877*4887Schin sh.lex_context = (void*)sh_lexopen(0,&sh,1); 878*4887Schin sh.ed_context = (void*)ed_open(&sh); 879*4887Schin sh.strbuf = sfstropen(); 880*4887Schin sfsetbuf(sh.strbuf,(char*)0,64); 881*4887Schin sh_onstate(SH_INIT); 882*4887Schin error_info.exit = sh_exit; 883*4887Schin error_info.id = path_basename(argv[0]); 884*4887Schin #if ERROR_VERSION >= 20000102L 885*4887Schin error_info.catalog = e_dict; 886*4887Schin #endif 887*4887Schin sh.cpipe[0] = -1; 888*4887Schin sh.coutpipe = -1; 889*4887Schin sh.userid=getuid(); 890*4887Schin sh.euserid=geteuid(); 891*4887Schin sh.groupid=getgid(); 892*4887Schin sh.egroupid=getegid(); 893*4887Schin for(n=0;n < 10; n++) 894*4887Schin { 895*4887Schin /* don't use lower bits when rand() generates large numbers */ 896*4887Schin if(rand() > RANDMASK) 897*4887Schin { 898*4887Schin rand_shift = 3; 899*4887Schin break; 900*4887Schin } 901*4887Schin } 902*4887Schin sh.lim.clk_tck = getconf("CLK_TCK"); 903*4887Schin sh.lim.arg_max = getconf("ARG_MAX"); 904*4887Schin sh.lim.open_max = getconf("OPEN_MAX"); 905*4887Schin sh.lim.child_max = getconf("CHILD_MAX"); 906*4887Schin sh.lim.ngroups_max = getconf("NGROUPS_MAX"); 907*4887Schin sh.lim.posix_version = getconf("VERSION"); 908*4887Schin sh.lim.posix_jobcontrol = getconf("JOB_CONTROL"); 909*4887Schin if(sh.lim.arg_max <=0) 910*4887Schin sh.lim.arg_max = ARG_MAX; 911*4887Schin if(sh.lim.child_max <=0) 912*4887Schin sh.lim.child_max = CHILD_MAX; 913*4887Schin if(sh.lim.open_max <0) 914*4887Schin sh.lim.open_max = OPEN_MAX; 915*4887Schin if(sh.lim.open_max > (SHRT_MAX-2)) 916*4887Schin sh.lim.open_max = SHRT_MAX-2; 917*4887Schin if(sh.lim.clk_tck <=0) 918*4887Schin sh.lim.clk_tck = CLK_TCK; 919*4887Schin #if SHOPT_FS_3D 920*4887Schin if(fs3d(FS3D_TEST)) 921*4887Schin sh.lim.fs3d = 1; 922*4887Schin #endif /* SHOPT_FS_3D */ 923*4887Schin sh_ioinit(); 924*4887Schin /* initialize signal handling */ 925*4887Schin sh_siginit(); 926*4887Schin stakinstall(NIL(Stak_t*),nospace); 927*4887Schin /* set up memory for name-value pairs */ 928*4887Schin sh.init_context = nv_init(&sh); 929*4887Schin /* read the environment */ 930*4887Schin if(argc>0) 931*4887Schin { 932*4887Schin type = sh_type(*argv); 933*4887Schin if(type&SH_TYPE_LOGIN) 934*4887Schin sh.login_sh = 2; 935*4887Schin } 936*4887Schin env_init(&sh); 937*4887Schin #if SHOPT_SPAWN 938*4887Schin { 939*4887Schin /* 940*4887Schin * try to find the pathname for this interpreter 941*4887Schin * try using environment variable _ or argv[0] 942*4887Schin */ 943*4887Schin char *last, *cp=nv_getval(L_ARGNOD); 944*4887Schin char buff[PATH_MAX+1]; 945*4887Schin sh.shpath = 0; 946*4887Schin sfprintf(sh.strbuf,"/proc/%d/exe",getpid()); 947*4887Schin if((n=readlink(sfstruse(sh.strbuf),buff,sizeof(buff)-1))>0) 948*4887Schin { 949*4887Schin buff[n] = 0; 950*4887Schin sh.shpath = strdup(buff); 951*4887Schin } 952*4887Schin else if((cp && (sh_type(cp)&SH_TYPE_SH)) || (argc>0 && strchr(cp= *argv,'/'))) 953*4887Schin { 954*4887Schin if(*cp=='/') 955*4887Schin sh.shpath = strdup(cp); 956*4887Schin else if(cp = nv_getval(PWDNOD)) 957*4887Schin { 958*4887Schin int offset = staktell(); 959*4887Schin stakputs(cp); 960*4887Schin stakputc('/'); 961*4887Schin stakputs(argv[0]); 962*4887Schin pathcanon(stakptr(offset),PATH_DOTDOT); 963*4887Schin sh.shpath = strdup(stakptr(offset)); 964*4887Schin stakseek(offset); 965*4887Schin } 966*4887Schin } 967*4887Schin } 968*4887Schin #endif 969*4887Schin nv_putval(IFSNOD,(char*)e_sptbnl,NV_RDONLY); 970*4887Schin #if SHOPT_FS_3D 971*4887Schin nv_stack(VPATHNOD, &VPATH_init); 972*4887Schin #endif /* SHOPT_FS_3D */ 973*4887Schin astconfdisc(newconf); 974*4887Schin #if SHOPT_TIMEOUT 975*4887Schin sh.st.tmout = SHOPT_TIMEOUT; 976*4887Schin #endif /* SHOPT_TIMEOUT */ 977*4887Schin /* initialize jobs table */ 978*4887Schin job_clear(); 979*4887Schin if(argc>0) 980*4887Schin { 981*4887Schin /* check for restricted shell */ 982*4887Schin if(type&SH_TYPE_RESTRICTED) 983*4887Schin sh_onoption(SH_RESTRICTED); 984*4887Schin #if SHOPT_PFSH 985*4887Schin /* check for profile shell */ 986*4887Schin else if(type&SH_TYPE_PROFILE) 987*4887Schin sh_onoption(SH_PFSH); 988*4887Schin #endif 989*4887Schin #if SHOPT_BASH 990*4887Schin /* check for invocation as bash */ 991*4887Schin if(type&SH_TYPE_BASH) 992*4887Schin { 993*4887Schin sh.userinit = userinit = bash_init; 994*4887Schin sh_onoption(SH_BASH); 995*4887Schin sh_onstate(SH_PREINIT); 996*4887Schin (*userinit)(0); 997*4887Schin sh_offstate(SH_PREINIT); 998*4887Schin } 999*4887Schin #endif 1000*4887Schin /* look for options */ 1001*4887Schin /* sh.st.dolc is $# */ 1002*4887Schin if((sh.st.dolc = sh_argopts(-argc,argv)) < 0) 1003*4887Schin { 1004*4887Schin sh.exitval = 2; 1005*4887Schin sh_done(0); 1006*4887Schin } 1007*4887Schin opt_info.disc = 0; 1008*4887Schin sh.st.dolv=argv+(argc-1)-sh.st.dolc; 1009*4887Schin sh.st.dolv[0] = argv[0]; 1010*4887Schin if(sh.st.dolc < 1) 1011*4887Schin sh_onoption(SH_SFLAG); 1012*4887Schin if(!sh_isoption(SH_SFLAG)) 1013*4887Schin { 1014*4887Schin sh.st.dolc--; 1015*4887Schin sh.st.dolv++; 1016*4887Schin #if _WINIX 1017*4887Schin { 1018*4887Schin char* name; 1019*4887Schin name = sh.st.dolv[0]; 1020*4887Schin if(name[1]==':' && (name[2]=='/' || name[2]=='\\')) 1021*4887Schin { 1022*4887Schin #if _lib_pathposix 1023*4887Schin char* p; 1024*4887Schin 1025*4887Schin if((n = pathposix(name, NIL(char*), 0)) > 0 && (p = (char*)malloc(++n))) 1026*4887Schin { 1027*4887Schin pathposix(name, p, n); 1028*4887Schin name = p; 1029*4887Schin } 1030*4887Schin else 1031*4887Schin #endif 1032*4887Schin { 1033*4887Schin name[1] = name[0]; 1034*4887Schin name[0] = name[2] = '/'; 1035*4887Schin } 1036*4887Schin } 1037*4887Schin } 1038*4887Schin #endif /* _WINIX */ 1039*4887Schin } 1040*4887Schin } 1041*4887Schin #if SHOPT_PFSH 1042*4887Schin if (sh_isoption(SH_PFSH)) 1043*4887Schin { 1044*4887Schin struct passwd *pw = getpwuid(sh.userid); 1045*4887Schin if(pw) 1046*4887Schin sh.user = strdup(pw->pw_name); 1047*4887Schin 1048*4887Schin } 1049*4887Schin #endif 1050*4887Schin /* set[ug]id scripts require the -p flag */ 1051*4887Schin if(sh.userid!=sh.euserid || sh.groupid!=sh.egroupid) 1052*4887Schin { 1053*4887Schin #if SHOPT_P_SUID 1054*4887Schin /* require sh -p to run setuid and/or setgid */ 1055*4887Schin if(!sh_isoption(SH_PRIVILEGED) && sh.euserid < SHOPT_P_SUID) 1056*4887Schin { 1057*4887Schin setuid(sh.euserid=sh.userid); 1058*4887Schin setgid(sh.egroupid=sh.groupid); 1059*4887Schin } 1060*4887Schin else 1061*4887Schin #else 1062*4887Schin sh_onoption(SH_PRIVILEGED); 1063*4887Schin #endif /* SHOPT_P_SUID */ 1064*4887Schin #ifdef SHELLMAGIC 1065*4887Schin /* careful of #! setuid scripts with name beginning with - */ 1066*4887Schin if(sh.login_sh && argv[1] && strcmp(argv[0],argv[1])==0) 1067*4887Schin errormsg(SH_DICT,ERROR_exit(1),e_prohibited); 1068*4887Schin #endif /*SHELLMAGIC*/ 1069*4887Schin } 1070*4887Schin else 1071*4887Schin sh_offoption(SH_PRIVILEGED); 1072*4887Schin /* shname for $0 in profiles and . scripts */ 1073*4887Schin if(strmatch(argv[1],e_devfdNN)) 1074*4887Schin sh.shname = strdup(argv[0]); 1075*4887Schin else 1076*4887Schin sh.shname = strdup(sh.st.dolv[0]); 1077*4887Schin /* 1078*4887Schin * return here for shell script execution 1079*4887Schin * but not for parenthesis subshells 1080*4887Schin */ 1081*4887Schin error_info.id = strdup(sh.st.dolv[0]); /* error_info.id is $0 */ 1082*4887Schin sh.jmpbuffer = (void*)&sh.checkbase; 1083*4887Schin sh_pushcontext(&sh.checkbase,SH_JMPSCRIPT); 1084*4887Schin sh.st.self = &sh.global; 1085*4887Schin sh.topscope = (Shscope_t*)sh.st.self; 1086*4887Schin sh_offstate(SH_INIT); 1087*4887Schin login_files[0] = (char*)e_profile; 1088*4887Schin login_files[1] = ".profile"; 1089*4887Schin sh.login_files = login_files; 1090*4887Schin if(sh.userinit=userinit) 1091*4887Schin (*userinit)(0); 1092*4887Schin return(&sh); 1093*4887Schin } 1094*4887Schin 1095*4887Schin Shell_t *sh_getinterp(void) 1096*4887Schin { 1097*4887Schin return(&sh); 1098*4887Schin } 1099*4887Schin 1100*4887Schin /* 1101*4887Schin * reinitialize before executing a script 1102*4887Schin */ 1103*4887Schin int sh_reinit(char *argv[]) 1104*4887Schin { 1105*4887Schin Shopt_t opt; 1106*4887Schin dtclear(sh.fun_tree); 1107*4887Schin dtclose(sh.alias_tree); 1108*4887Schin sh.alias_tree = inittree(&sh,shtab_aliases); 1109*4887Schin sh.namespace = 0; 1110*4887Schin sh.inuse_bits = 0; 1111*4887Schin if(sh.userinit) 1112*4887Schin (*sh.userinit)(1); 1113*4887Schin if(sh.heredocs) 1114*4887Schin { 1115*4887Schin sfclose(sh.heredocs); 1116*4887Schin sh.heredocs = 0; 1117*4887Schin } 1118*4887Schin /* remove locals */ 1119*4887Schin sh_onstate(SH_INIT); 1120*4887Schin nv_scan(sh.var_tree,sh_envnolocal,(void*)0,NV_EXPORT,0); 1121*4887Schin nv_scan(sh.var_tree,sh_envnolocal,(void*)0,NV_ARRAY,NV_ARRAY); 1122*4887Schin sh_offstate(SH_INIT); 1123*4887Schin memset(sh.st.trapcom,0,(sh.st.trapmax+1)*sizeof(char*)); 1124*4887Schin memset((void*)&opt,0,sizeof(opt)); 1125*4887Schin if(sh_isoption(SH_TRACKALL)) 1126*4887Schin on_option(&opt,SH_TRACKALL); 1127*4887Schin if(sh_isoption(SH_EMACS)) 1128*4887Schin on_option(&opt,SH_EMACS); 1129*4887Schin if(sh_isoption(SH_GMACS)) 1130*4887Schin on_option(&opt,SH_GMACS); 1131*4887Schin if(sh_isoption(SH_VI)) 1132*4887Schin on_option(&opt,SH_VI); 1133*4887Schin if(sh_isoption(SH_VIRAW)) 1134*4887Schin on_option(&opt,SH_VIRAW); 1135*4887Schin sh.options = opt; 1136*4887Schin /* set up new args */ 1137*4887Schin if(argv) 1138*4887Schin sh.arglist = sh_argcreate(argv); 1139*4887Schin if(sh.arglist) 1140*4887Schin sh_argreset(sh.arglist,NIL(struct dolnod*)); 1141*4887Schin sh.envlist=0; 1142*4887Schin sh.curenv = 0; 1143*4887Schin sh.shname = error_info.id = strdup(sh.st.dolv[0]); 1144*4887Schin sh_offstate(SH_FORKED); 1145*4887Schin sh.fn_depth = sh.dot_depth = 0; 1146*4887Schin sh_sigreset(0); 1147*4887Schin return(1); 1148*4887Schin } 1149*4887Schin 1150*4887Schin /* 1151*4887Schin * set when creating a local variable of this name 1152*4887Schin */ 1153*4887Schin Namfun_t *nv_cover(register Namval_t *np) 1154*4887Schin { 1155*4887Schin #ifdef PATH_BFPATH 1156*4887Schin if(np==IFSNOD || np==PATHNOD || np==SHELLNOD || np==FPATHNOD || np==CDPNOD || np==SECONDS) 1157*4887Schin #else 1158*4887Schin if(np==IFSNOD || np==PATHNOD || np==SHELLNOD || np==SECONDS) 1159*4887Schin #endif 1160*4887Schin return(np->nvfun); 1161*4887Schin #ifdef _hdr_locale 1162*4887Schin if(np==LCALLNOD || np==LCTYPENOD || np==LCMSGNOD || np==LCCOLLNOD || np==LCNUMNOD || np==LANGNOD) 1163*4887Schin return(np->nvfun); 1164*4887Schin #endif 1165*4887Schin return(0); 1166*4887Schin } 1167*4887Schin 1168*4887Schin static Namtype_t typeset; 1169*4887Schin static const char *shdiscnames[] = { "tilde", 0}; 1170*4887Schin 1171*4887Schin /* 1172*4887Schin * Initialize the shell name and alias table 1173*4887Schin */ 1174*4887Schin static Init_t *nv_init(Shell_t *shp) 1175*4887Schin { 1176*4887Schin Namval_t *np; 1177*4887Schin register Init_t *ip; 1178*4887Schin double d=0; 1179*4887Schin ip = newof(0,Init_t,1,0); 1180*4887Schin if(!ip) 1181*4887Schin return(0); 1182*4887Schin ip->sh = shp; 1183*4887Schin shp->var_base = shp->var_tree = inittree(shp,shtab_variables); 1184*4887Schin ip->IFS_init.hdr.disc = &IFS_disc; 1185*4887Schin ip->IFS_init.hdr.nofree = 1; 1186*4887Schin ip->IFS_init.sh = shp; 1187*4887Schin ip->PATH_init.hdr.disc = &RESTRICTED_disc; 1188*4887Schin ip->PATH_init.hdr.nofree = 1; 1189*4887Schin ip->PATH_init.sh = shp; 1190*4887Schin #ifdef PATH_BFPATH 1191*4887Schin ip->FPATH_init.hdr.disc = &RESTRICTED_disc; 1192*4887Schin ip->FPATH_init.hdr.nofree = 1; 1193*4887Schin ip->FPATH_init.sh = shp; 1194*4887Schin ip->CDPATH_init.hdr.disc = &CDPATH_disc; 1195*4887Schin ip->CDPATH_init.hdr.nofree = 1; 1196*4887Schin ip->CDPATH_init.sh = shp; 1197*4887Schin #endif 1198*4887Schin ip->SHELL_init.hdr.disc = &RESTRICTED_disc; 1199*4887Schin ip->SHELL_init.sh = shp; 1200*4887Schin ip->SHELL_init.hdr.nofree = 1; 1201*4887Schin ip->ENV_init.hdr.disc = &RESTRICTED_disc; 1202*4887Schin ip->ENV_init.hdr.nofree = 1; 1203*4887Schin ip->ENV_init.sh = shp; 1204*4887Schin ip->VISUAL_init.hdr.disc = &EDITOR_disc; 1205*4887Schin ip->VISUAL_init.hdr.nofree = 1; 1206*4887Schin ip->VISUAL_init.sh = shp; 1207*4887Schin ip->EDITOR_init.hdr.disc = &EDITOR_disc; 1208*4887Schin ip->EDITOR_init.hdr.nofree = 1; 1209*4887Schin ip->EDITOR_init.sh = shp; 1210*4887Schin ip->OPTINDEX_init.hdr.disc = &OPTINDEX_disc; 1211*4887Schin ip->OPTINDEX_init.hdr.nofree = 1; 1212*4887Schin ip->OPTINDEX_init.sh = shp; 1213*4887Schin ip->SECONDS_init.hdr.disc = &SECONDS_disc; 1214*4887Schin ip->SECONDS_init.hdr.nofree = 1; 1215*4887Schin ip->SECONDS_init.sh = shp; 1216*4887Schin ip->RAND_init.hdr.disc = &RAND_disc; 1217*4887Schin ip->RAND_init.hdr.nofree = 1; 1218*4887Schin ip->SH_MATCH_init.hdr.disc = &SH_MATCH_disc; 1219*4887Schin ip->SH_MATCH_init.hdr.nofree = 1; 1220*4887Schin ip->LINENO_init.hdr.disc = &LINENO_disc; 1221*4887Schin ip->LINENO_init.hdr.nofree = 1; 1222*4887Schin ip->LINENO_init.sh = shp; 1223*4887Schin ip->L_ARG_init.hdr.disc = &L_ARG_disc; 1224*4887Schin ip->L_ARG_init.hdr.nofree = 1; 1225*4887Schin #ifdef _hdr_locale 1226*4887Schin ip->LC_TYPE_init.hdr.disc = &LC_disc; 1227*4887Schin ip->LC_TYPE_init.hdr.nofree = 1; 1228*4887Schin ip->LC_NUM_init.hdr.disc = &LC_disc; 1229*4887Schin ip->LC_NUM_init.hdr.nofree = 1; 1230*4887Schin ip->LC_COLL_init.hdr.disc = &LC_disc; 1231*4887Schin ip->LC_COLL_init.hdr.nofree = 1; 1232*4887Schin ip->LC_MSG_init.hdr.disc = &LC_disc; 1233*4887Schin ip->LC_MSG_init.hdr.nofree = 1; 1234*4887Schin ip->LC_ALL_init.hdr.disc = &LC_disc; 1235*4887Schin ip->LC_ALL_init.hdr.nofree = 1; 1236*4887Schin ip->LANG_init.hdr.disc = &LC_disc; 1237*4887Schin ip->LANG_init.hdr.nofree = 1; 1238*4887Schin ip->LC_TYPE_init.sh = shp; 1239*4887Schin ip->LC_NUM_init.sh = shp; 1240*4887Schin ip->LC_COLL_init.sh = shp; 1241*4887Schin ip->LC_MSG_init.sh = shp; 1242*4887Schin ip->LANG_init.sh = shp; 1243*4887Schin #endif /* _hdr_locale */ 1244*4887Schin nv_stack(IFSNOD, &ip->IFS_init.hdr); 1245*4887Schin nv_stack(PATHNOD, &ip->PATH_init.hdr); 1246*4887Schin #ifdef PATH_BFPATH 1247*4887Schin nv_stack(FPATHNOD, &ip->FPATH_init.hdr); 1248*4887Schin nv_stack(CDPNOD, &ip->CDPATH_init.hdr); 1249*4887Schin #endif 1250*4887Schin nv_stack(SHELLNOD, &ip->SHELL_init.hdr); 1251*4887Schin nv_stack(ENVNOD, &ip->ENV_init.hdr); 1252*4887Schin nv_stack(VISINOD, &ip->VISUAL_init.hdr); 1253*4887Schin nv_stack(EDITNOD, &ip->EDITOR_init.hdr); 1254*4887Schin nv_stack(OPTINDNOD, &ip->OPTINDEX_init.hdr); 1255*4887Schin nv_stack(SECONDS, &ip->SECONDS_init.hdr); 1256*4887Schin nv_stack(L_ARGNOD, &ip->L_ARG_init.hdr); 1257*4887Schin nv_putval(SECONDS, (char*)&d, NV_INTEGER|NV_DOUBLE); 1258*4887Schin nv_stack(RANDNOD, &ip->RAND_init.hdr); 1259*4887Schin d = (shp->pid&RANDMASK); 1260*4887Schin nv_putval(RANDNOD, (char*)&d, NV_INTEGER|NV_DOUBLE); 1261*4887Schin nv_stack(LINENO, &ip->LINENO_init.hdr); 1262*4887Schin nv_putsub(SH_MATCHNOD,(char*)0,10); 1263*4887Schin nv_onattr(SH_MATCHNOD,NV_RDONLY); 1264*4887Schin nv_stack(SH_MATCHNOD, &ip->SH_MATCH_init.hdr); 1265*4887Schin #ifdef _hdr_locale 1266*4887Schin nv_stack(LCTYPENOD, &ip->LC_TYPE_init.hdr); 1267*4887Schin nv_stack(LCALLNOD, &ip->LC_ALL_init.hdr); 1268*4887Schin nv_stack(LCMSGNOD, &ip->LC_MSG_init.hdr); 1269*4887Schin nv_stack(LCCOLLNOD, &ip->LC_COLL_init.hdr); 1270*4887Schin nv_stack(LCNUMNOD, &ip->LC_NUM_init.hdr); 1271*4887Schin nv_stack(LANGNOD, &ip->LANG_init.hdr); 1272*4887Schin #endif /* _hdr_locale */ 1273*4887Schin (PPIDNOD)->nvalue.lp = (&shp->ppid); 1274*4887Schin (TMOUTNOD)->nvalue.lp = (&shp->st.tmout); 1275*4887Schin (MCHKNOD)->nvalue.lp = (&sh_mailchk); 1276*4887Schin (OPTINDNOD)->nvalue.lp = (&shp->st.optindex); 1277*4887Schin /* set up the seconds clock */ 1278*4887Schin shp->alias_tree = inittree(shp,shtab_aliases); 1279*4887Schin shp->track_tree = dtopen(&_Nvdisc,Dtset); 1280*4887Schin shp->bltin_tree = inittree(shp,(const struct shtable2*)shtab_builtins); 1281*4887Schin typeset.shp = shp; 1282*4887Schin typeset.optstring = sh_opttypeset; 1283*4887Schin nv_search("typeset",shp->bltin_tree,0)->nvfun = (void*)&typeset; 1284*4887Schin #if SHOPT_BASH 1285*4887Schin nv_search("local",shp->bltin_tree,0)->nvfun = (void*)&typeset; 1286*4887Schin #endif 1287*4887Schin shp->fun_tree = dtopen(&_Nvdisc,Dtoset); 1288*4887Schin dtview(shp->fun_tree,shp->bltin_tree); 1289*4887Schin #if SHOPT_NAMESPACE 1290*4887Schin if(np = nv_mount(DOTSHNOD, "global", shp->var_tree)) 1291*4887Schin nv_onattr(np,NV_RDONLY); 1292*4887Schin np = nv_search("namespace",nv_dict(DOTSHNOD),NV_ADD); 1293*4887Schin nv_putval(np,".sh.global",NV_RDONLY|NV_NOFREE); 1294*4887Schin nv_stack(np, &NSPACE_init); 1295*4887Schin #endif /* SHOPT_NAMESPACE */ 1296*4887Schin np = nv_mount(DOTSHNOD, "type", dtopen(&_Nvdisc,Dtoset)); 1297*4887Schin nv_adddisc(DOTSHNOD, shdiscnames, (Namval_t**)0); 1298*4887Schin return(ip); 1299*4887Schin } 1300*4887Schin 1301*4887Schin /* 1302*4887Schin * initialize name-value pairs 1303*4887Schin */ 1304*4887Schin 1305*4887Schin static Dt_t *inittree(Shell_t *shp,const struct shtable2 *name_vals) 1306*4887Schin { 1307*4887Schin register Namval_t *np; 1308*4887Schin register const struct shtable2 *tp; 1309*4887Schin register unsigned n = 0; 1310*4887Schin register Dt_t *treep; 1311*4887Schin Dt_t *base_treep, *dict; 1312*4887Schin for(tp=name_vals;*tp->sh_name;tp++) 1313*4887Schin n++; 1314*4887Schin np = (Namval_t*)calloc(n,sizeof(Namval_t)); 1315*4887Schin if(!shp->bltin_nodes) 1316*4887Schin shp->bltin_nodes = np; 1317*4887Schin else if(name_vals==(const struct shtable2*)shtab_builtins) 1318*4887Schin shp->bltin_cmds = np; 1319*4887Schin base_treep = treep = dtopen(&_Nvdisc,Dtoset); 1320*4887Schin for(tp=name_vals;*tp->sh_name;tp++,np++) 1321*4887Schin { 1322*4887Schin if((np->nvname = strrchr(tp->sh_name,'.')) && np->nvname!=((char*)tp->sh_name)) 1323*4887Schin np->nvname++; 1324*4887Schin else 1325*4887Schin { 1326*4887Schin np->nvname = (char*)tp->sh_name; 1327*4887Schin treep = base_treep; 1328*4887Schin } 1329*4887Schin np->nvenv = 0; 1330*4887Schin if(name_vals==(const struct shtable2*)shtab_builtins) 1331*4887Schin np->nvalue.bfp = ((struct shtable3*)tp)->sh_value; 1332*4887Schin else 1333*4887Schin np->nvalue.cp = (char*)tp->sh_value; 1334*4887Schin nv_setattr(np,tp->sh_number); 1335*4887Schin if(nv_istable(np)) 1336*4887Schin nv_mount(np,(const char*)0,dict=dtopen(&_Nvdisc,Dtoset)); 1337*4887Schin if(nv_isattr(np,NV_INTEGER)) 1338*4887Schin nv_setsize(np,10); 1339*4887Schin else 1340*4887Schin nv_setsize(np,0); 1341*4887Schin dtinsert(treep,np); 1342*4887Schin if(nv_istable(np)) 1343*4887Schin treep = dict; 1344*4887Schin } 1345*4887Schin return(treep); 1346*4887Schin } 1347*4887Schin 1348*4887Schin /* 1349*4887Schin * read in the process environment and set up name-value pairs 1350*4887Schin * skip over items that are not name-value pairs 1351*4887Schin */ 1352*4887Schin 1353*4887Schin static void env_init(Shell_t *shp) 1354*4887Schin { 1355*4887Schin register char *cp; 1356*4887Schin register Namval_t *np; 1357*4887Schin register char **ep=environ; 1358*4887Schin register char *next=0; 1359*4887Schin #ifdef _ENV_H 1360*4887Schin shp->env = env_open(environ,3); 1361*4887Schin env_delete(shp->env,"_"); 1362*4887Schin #endif 1363*4887Schin if(ep) 1364*4887Schin { 1365*4887Schin while(cp= *ep++) 1366*4887Schin { 1367*4887Schin if(*cp=='A' && cp[1]=='_' && cp[2]=='_' && cp[3]=='z' && cp[4]=='=') 1368*4887Schin next = cp+4; 1369*4887Schin else if(np=nv_open(cp,shp->var_tree,(NV_EXPORT|NV_IDENT|NV_ASSIGN|NV_NOFAIL))) 1370*4887Schin { 1371*4887Schin nv_onattr(np,NV_IMPORT); 1372*4887Schin np->nvenv = cp; 1373*4887Schin nv_close(np); 1374*4887Schin } 1375*4887Schin } 1376*4887Schin while(cp=next) 1377*4887Schin { 1378*4887Schin if(next = strchr(++cp,'=')) 1379*4887Schin *next = 0; 1380*4887Schin np = nv_search(cp+2,shp->var_tree,NV_ADD); 1381*4887Schin if(nv_isattr(np,NV_IMPORT|NV_EXPORT)) 1382*4887Schin { 1383*4887Schin int flag = *(unsigned char*)cp-' '; 1384*4887Schin int size = *(unsigned char*)(cp+1)-' '; 1385*4887Schin if((flag&NV_INTEGER) && size==0) 1386*4887Schin { 1387*4887Schin /* check for floating*/ 1388*4887Schin char *ep,*val = nv_getval(np); 1389*4887Schin strtol(val,&ep,10); 1390*4887Schin if(*ep=='.' || *ep=='e' || *ep=='E') 1391*4887Schin { 1392*4887Schin char *lp; 1393*4887Schin flag |= NV_DOUBLE; 1394*4887Schin if(*ep=='.') 1395*4887Schin { 1396*4887Schin strtol(ep+1,&lp,10); 1397*4887Schin if(*lp) 1398*4887Schin ep = lp; 1399*4887Schin } 1400*4887Schin if(*ep && *ep!='.') 1401*4887Schin { 1402*4887Schin flag |= NV_EXPNOTE; 1403*4887Schin size = ep-val; 1404*4887Schin } 1405*4887Schin else 1406*4887Schin size = strlen(ep); 1407*4887Schin size--; 1408*4887Schin } 1409*4887Schin } 1410*4887Schin nv_newattr(np,flag|NV_IMPORT|NV_EXPORT,size); 1411*4887Schin } 1412*4887Schin } 1413*4887Schin } 1414*4887Schin #ifdef _ENV_H 1415*4887Schin env_delete(sh.env,e_envmarker); 1416*4887Schin #endif 1417*4887Schin if(nv_isnull(PWDNOD) || nv_isattr(PWDNOD,NV_TAGGED)) 1418*4887Schin { 1419*4887Schin nv_offattr(PWDNOD,NV_TAGGED); 1420*4887Schin path_pwd(0); 1421*4887Schin } 1422*4887Schin if((cp = nv_getval(SHELLNOD)) && (sh_type(cp)&SH_TYPE_RESTRICTED)) 1423*4887Schin sh_onoption(SH_RESTRICTED); /* restricted shell */ 1424*4887Schin return; 1425*4887Schin } 1426*4887Schin 1427*4887Schin /* 1428*4887Schin * terminate shell and free up the space 1429*4887Schin */ 1430*4887Schin int sh_term(void) 1431*4887Schin { 1432*4887Schin sfdisc(sfstdin,SF_POPDISC); 1433*4887Schin free((char*)sh.outbuff); 1434*4887Schin stakset(NIL(char*),0); 1435*4887Schin return(0); 1436*4887Schin } 1437*4887Schin 1438*4887Schin /* function versions of these */ 1439*4887Schin 1440*4887Schin #define DISABLE /* proto workaround */ 1441*4887Schin 1442*4887Schin unsigned long sh_isoption DISABLE (int opt) 1443*4887Schin { 1444*4887Schin return(sh_isoption(opt)); 1445*4887Schin } 1446*4887Schin 1447*4887Schin unsigned long sh_onoption DISABLE (int opt) 1448*4887Schin { 1449*4887Schin return(sh_onoption(opt)); 1450*4887Schin } 1451*4887Schin 1452*4887Schin unsigned long sh_offoption DISABLE (int opt) 1453*4887Schin { 1454*4887Schin return(sh_offoption(opt)); 1455*4887Schin } 1456*4887Schin 1457*4887Schin void sh_sigcheck DISABLE (void) 1458*4887Schin { 1459*4887Schin sh_sigcheck(); 1460*4887Schin } 1461*4887Schin 1462*4887Schin Dt_t* sh_bltin_tree DISABLE (void) 1463*4887Schin { 1464*4887Schin return(sh.bltin_tree); 1465*4887Schin } 1466