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