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