1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2012 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Eclipse Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 8 * * 9 * A copy of the License is available at * 10 * http://www.eclipse.org/org/documents/epl-v10.html * 11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) * 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 <ccode.h> 33 #include <pwd.h> 34 #include <tmx.h> 35 #include <regex.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 "FEATURE/externs" 48 #include "lexstates.h" 49 #include "version.h" 50 51 #if _hdr_wctype 52 #include <ast_wchar.h> 53 #include <wctype.h> 54 #endif 55 #if !_typ_wctrans_t 56 #undef wctrans_t 57 #define wctrans_t sh_wctrans_t 58 typedef long wctrans_t; 59 #endif 60 #if !_lib_wctrans 61 #undef wctrans 62 #define wctrans sh_wctrans 63 static wctrans_t wctrans(const char *name) 64 { 65 if(strcmp(name,e_tolower)==0) 66 return(1); 67 else if(strcmp(name,e_toupper)==0) 68 return(2); 69 return(0); 70 } 71 #endif 72 #if !_lib_towctrans 73 #undef towctrans 74 #define towctrans sh_towctrans 75 static int towctrans(int c, wctrans_t t) 76 { 77 if(t==1 && isupper(c)) 78 c = tolower(c); 79 else if(t==2 && islower(c)) 80 c = toupper(c); 81 return(c); 82 } 83 #endif 84 85 char e_version[] = "\n@(#)$Id: Version " 86 #if SHOPT_AUDIT 87 #define ATTRS 1 88 "A" 89 #endif 90 #if SHOPT_BASH 91 #define ATTRS 1 92 "B" 93 #endif 94 #if SHOPT_COSHELL 95 #define ATTRS 1 96 "J" 97 #else 98 #if SHOPT_BGX 99 #define ATTRS 1 100 "j" 101 #endif 102 #endif 103 #if SHOPT_ACCT 104 #define ATTRS 1 105 "L" 106 #endif 107 #if SHOPT_MULTIBYTE 108 #define ATTRS 1 109 "M" 110 #endif 111 #if SHOPT_PFSH && _hdr_exec_attr 112 #define ATTRS 1 113 "P" 114 #endif 115 #if SHOPT_REGRESS 116 #define ATTRS 1 117 "R" 118 #endif 119 #if ATTRS 120 " " 121 #endif 122 SH_RELEASE " $\0\n"; 123 124 #if SHOPT_BASH 125 extern void bash_init(Shell_t*,int); 126 #endif 127 128 #define RANDMASK 0x7fff 129 130 #ifndef ARG_MAX 131 # define ARG_MAX (1*1024*1024) 132 #endif 133 #ifndef CHILD_MAX 134 # define CHILD_MAX (1*1024) 135 #endif 136 #ifndef CLK_TCK 137 # define CLK_TCK 60 138 #endif /* CLK_TCK */ 139 140 #ifndef environ 141 extern char **environ; 142 #endif 143 144 #undef getconf 145 #define getconf(x) strtol(astconf(x,NiL,NiL),NiL,0) 146 147 struct seconds 148 { 149 Namfun_t hdr; 150 Shell_t *sh; 151 }; 152 153 struct rand 154 { 155 Namfun_t hdr; 156 Shell_t *sh; 157 int32_t rand_last; 158 }; 159 160 struct ifs 161 { 162 Namfun_t hdr; 163 Namval_t *ifsnp; 164 }; 165 166 struct match 167 { 168 Namfun_t hdr; 169 const char *v; 170 char *val; 171 char *rval[2]; 172 regoff_t *match; 173 char node[NV_MINSZ+sizeof(char*)]; 174 regoff_t first; 175 int vsize; 176 int nmatch; 177 int index; 178 int lastsub[2]; 179 }; 180 181 typedef struct _init_ 182 { 183 Shell_t *sh; 184 #if SHOPT_FS_3D 185 Namfun_t VPATH_init; 186 #endif /* SHOPT_FS_3D */ 187 struct ifs IFS_init; 188 Namfun_t PATH_init; 189 Namfun_t FPATH_init; 190 Namfun_t CDPATH_init; 191 Namfun_t SHELL_init; 192 Namfun_t ENV_init; 193 Namfun_t VISUAL_init; 194 Namfun_t EDITOR_init; 195 Namfun_t HISTFILE_init; 196 Namfun_t HISTSIZE_init; 197 Namfun_t OPTINDEX_init; 198 struct seconds SECONDS_init; 199 struct rand RAND_init; 200 Namfun_t LINENO_init; 201 Namfun_t L_ARG_init; 202 Namfun_t SH_VERSION_init; 203 struct match SH_MATCH_init; 204 Namfun_t SH_MATH_init; 205 #if SHOPT_COSHELL 206 Namfun_t SH_JOBPOOL_init; 207 #endif /* SHOPT_COSHELL */ 208 #ifdef _hdr_locale 209 Namfun_t LC_TYPE_init; 210 Namfun_t LC_NUM_init; 211 Namfun_t LC_COLL_init; 212 Namfun_t LC_MSG_init; 213 Namfun_t LC_ALL_init; 214 Namfun_t LANG_init; 215 #endif /* _hdr_locale */ 216 } Init_t; 217 218 static Init_t *ip; 219 static int lctype; 220 static int nbltins; 221 static void env_init(Shell_t*); 222 static Init_t *nv_init(Shell_t*); 223 static Dt_t *inittree(Shell_t*,const struct shtable2*); 224 static int shlvl; 225 226 #ifdef _WINIX 227 # define EXE "?(.exe)" 228 #else 229 # define EXE 230 #endif 231 232 static int rand_shift; 233 234 235 /* 236 * Invalidate all path name bindings 237 */ 238 static void rehash(register Namval_t *np,void *data) 239 { 240 NOT_USED(data); 241 nv_onattr(np,NV_NOALIAS); 242 } 243 244 /* 245 * out of memory routine for stak routines 246 */ 247 static char *nospace(int unused) 248 { 249 NOT_USED(unused); 250 errormsg(SH_DICT,ERROR_exit(3),e_nospace); 251 return(NIL(char*)); 252 } 253 254 /* Trap for VISUAL and EDITOR variables */ 255 static void put_ed(register Namval_t* np,const char *val,int flags,Namfun_t *fp) 256 { 257 register const char *cp, *name=nv_name(np); 258 register int newopt=0; 259 Shell_t *shp = nv_shell(np); 260 if(*name=='E' && nv_getval(sh_scoped(shp,VISINOD))) 261 goto done; 262 if(!(cp=val) && (*name=='E' || !(cp=nv_getval(sh_scoped(shp,EDITNOD))))) 263 goto done; 264 /* turn on vi or emacs option if editor name is either*/ 265 cp = path_basename(cp); 266 if(strmatch(cp,"*[Vv][Ii]*")) 267 newopt=SH_VI; 268 else if(strmatch(cp,"*gmacs*")) 269 newopt=SH_GMACS; 270 else if(strmatch(cp,"*macs*")) 271 newopt=SH_EMACS; 272 if(newopt) 273 { 274 sh_offoption(SH_VI); 275 sh_offoption(SH_EMACS); 276 sh_offoption(SH_GMACS); 277 sh_onoption(newopt); 278 } 279 done: 280 nv_putv(np, val, flags, fp); 281 } 282 283 /* Trap for HISTFILE and HISTSIZE variables */ 284 static void put_history(register Namval_t* np,const char *val,int flags,Namfun_t *fp) 285 { 286 Shell_t *shp = nv_shell(np); 287 void *histopen = NULL; 288 char *cp; 289 if( shp ) { 290 histopen = shp->gd->hist_ptr; 291 } 292 if(val && histopen) 293 { 294 if(np==HISTFILE && (cp=nv_getval(np)) && strcmp(val,cp)==0) 295 return; 296 if(np==HISTSIZE && sh_arith(shp,val)==nv_getnum(HISTSIZE)) 297 return; 298 hist_close(shp->gd->hist_ptr); 299 } 300 nv_putv(np, val, flags, fp); 301 if(histopen) 302 { 303 if(val) 304 sh_histinit(shp); 305 else 306 hist_close(histopen); 307 } 308 } 309 310 /* Trap for OPTINDEX */ 311 static void put_optindex(Namval_t* np,const char *val,int flags,Namfun_t *fp) 312 { 313 Shell_t *shp = nv_shell(np); 314 shp->st.opterror = shp->st.optchar = 0; 315 nv_putv(np, val, flags, fp); 316 if(!val) 317 nv_disc(np,fp,NV_POP); 318 } 319 320 static Sfdouble_t nget_optindex(register Namval_t* np, Namfun_t *fp) 321 { 322 return((Sfdouble_t)*np->nvalue.lp); 323 } 324 325 static Namfun_t *clone_optindex(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp) 326 { 327 Namfun_t *dp = (Namfun_t*)malloc(sizeof(Namfun_t)); 328 memcpy((void*)dp,(void*)fp,sizeof(Namfun_t)); 329 mp->nvalue.lp = np->nvalue.lp; 330 dp->nofree = 0; 331 return(dp); 332 } 333 334 335 /* Trap for restricted variables FPATH, PATH, SHELL, ENV */ 336 static void put_restricted(register Namval_t* np,const char *val,int flags,Namfun_t *fp) 337 { 338 Shell_t *shp = nv_shell(np); 339 int path_scoped = 0, fpath_scoped=0; 340 Pathcomp_t *pp; 341 char *name = nv_name(np); 342 if(!(flags&NV_RDONLY) && sh_isoption(SH_RESTRICTED)) 343 errormsg(SH_DICT,ERROR_exit(1),e_restricted,nv_name(np)); 344 if(np==PATHNOD || (path_scoped=(strcmp(name,PATHNOD->nvname)==0))) 345 { 346 nv_scan(shp->track_tree,rehash,(void*)0,NV_TAGGED,NV_TAGGED); 347 if(path_scoped && !val) 348 val = PATHNOD->nvalue.cp; 349 } 350 if(val && !(flags&NV_RDONLY) && np->nvalue.cp && strcmp(val,np->nvalue.cp)==0) 351 return; 352 if(np==FPATHNOD || (fpath_scoped=(strcmp(name,FPATHNOD->nvname)==0))) 353 shp->pathlist = (void*)path_unsetfpath(shp); 354 nv_putv(np, val, flags, fp); 355 shp->universe = 0; 356 if(shp->pathlist) 357 { 358 val = np->nvalue.cp; 359 if(np==PATHNOD || path_scoped) 360 pp = (void*)path_addpath(shp,(Pathcomp_t*)shp->pathlist,val,PATH_PATH); 361 else if(val && (np==FPATHNOD || fpath_scoped)) 362 pp = (void*)path_addpath(shp,(Pathcomp_t*)shp->pathlist,val,PATH_FPATH); 363 else 364 return; 365 if(shp->pathlist = (void*)pp) 366 pp->shp = shp; 367 if(!val && (flags&NV_NOSCOPE)) 368 { 369 Namval_t *mp = dtsearch(shp->var_tree,np); 370 if(mp && (val=nv_getval(mp))) 371 nv_putval(mp,val,NV_RDONLY); 372 } 373 #if 0 374 sfprintf(sfstderr,"%d: name=%s val=%s\n",getpid(),name,val); 375 path_dump((Pathcomp_t*)shp->pathlist); 376 #endif 377 } 378 } 379 380 static void put_cdpath(register Namval_t* np,const char *val,int flags,Namfun_t *fp) 381 { 382 Pathcomp_t *pp; 383 Shell_t *shp = nv_shell(np); 384 nv_putv(np, val, flags, fp); 385 if(!shp->cdpathlist) 386 return; 387 val = np->nvalue.cp; 388 pp = (void*)path_addpath(shp,(Pathcomp_t*)shp->cdpathlist,val,PATH_CDPATH); 389 if(shp->cdpathlist = (void*)pp) 390 pp->shp = shp; 391 } 392 393 #ifdef _hdr_locale 394 /* 395 * This function needs to be modified to handle international 396 * error message translations 397 */ 398 #if ERROR_VERSION >= 20000101L 399 static char* msg_translate(const char* catalog, const char* message) 400 { 401 NOT_USED(catalog); 402 return((char*)message); 403 } 404 #else 405 static char* msg_translate(const char* message, int type) 406 { 407 NOT_USED(type); 408 return((char*)message); 409 } 410 #endif 411 412 /* Trap for LC_ALL, LC_CTYPE, LC_MESSAGES, LC_COLLATE and LANG */ 413 static void put_lang(Namval_t* np,const char *val,int flags,Namfun_t *fp) 414 { 415 Shell_t *shp = nv_shell(np); 416 int type; 417 char *name = nv_name(np); 418 if(name==(LCALLNOD)->nvname) 419 type = LC_ALL; 420 else if(name==(LCTYPENOD)->nvname) 421 type = LC_CTYPE; 422 else if(name==(LCMSGNOD)->nvname) 423 type = LC_MESSAGES; 424 else if(name==(LCCOLLNOD)->nvname) 425 type = LC_COLLATE; 426 else if(name==(LCNUMNOD)->nvname) 427 type = LC_NUMERIC; 428 #ifdef LC_LANG 429 else if(name==(LANGNOD)->nvname) 430 type = LC_LANG; 431 #else 432 #define LC_LANG LC_ALL 433 else if(name==(LANGNOD)->nvname && (!(name=nv_getval(LCALLNOD)) || !*name)) 434 type = LC_LANG; 435 #endif 436 else 437 type= -1; 438 if(!sh_isstate(SH_INIT) && (type>=0 || type==LC_ALL || type==LC_LANG)) 439 { 440 char* r; 441 #ifdef AST_LC_setenv 442 ast.locale.set |= AST_LC_setenv; 443 #endif 444 r = setlocale(type,val?val:""); 445 #ifdef AST_LC_setenv 446 ast.locale.set ^= AST_LC_setenv; 447 #endif 448 if(!r && val) 449 { 450 if(!sh_isstate(SH_INIT) || shp->login_sh==0) 451 errormsg(SH_DICT,0,e_badlocale,val); 452 return; 453 } 454 } 455 nv_putv(np, val, flags, fp); 456 if(CC_NATIVE!=CC_ASCII && (type==LC_ALL || type==LC_LANG || type==LC_CTYPE)) 457 { 458 if(sh_lexstates[ST_BEGIN]!=sh_lexrstates[ST_BEGIN]) 459 free((void*)sh_lexstates[ST_BEGIN]); 460 lctype++; 461 if(ast.locale.set&(1<<AST_LC_CTYPE)) 462 { 463 register int c; 464 char *state[4]; 465 sh_lexstates[ST_BEGIN] = state[0] = (char*)malloc(4*(1<<CHAR_BIT)); 466 memcpy(state[0],sh_lexrstates[ST_BEGIN],(1<<CHAR_BIT)); 467 sh_lexstates[ST_NAME] = state[1] = state[0] + (1<<CHAR_BIT); 468 memcpy(state[1],sh_lexrstates[ST_NAME],(1<<CHAR_BIT)); 469 sh_lexstates[ST_DOL] = state[2] = state[1] + (1<<CHAR_BIT); 470 memcpy(state[2],sh_lexrstates[ST_DOL],(1<<CHAR_BIT)); 471 sh_lexstates[ST_BRACE] = state[3] = state[2] + (1<<CHAR_BIT); 472 memcpy(state[3],sh_lexrstates[ST_BRACE],(1<<CHAR_BIT)); 473 for(c=0; c<(1<<CHAR_BIT); c++) 474 { 475 if(state[0][c]!=S_REG) 476 continue; 477 if(state[2][c]!=S_ERR) 478 continue; 479 if(isblank(c)) 480 { 481 state[0][c]=0; 482 state[1][c]=S_BREAK; 483 state[2][c]=S_BREAK; 484 continue; 485 } 486 if(!isalpha(c)) 487 continue; 488 state[0][c]=S_NAME; 489 if(state[1][c]==S_REG) 490 state[1][c]=0; 491 state[2][c]=S_ALP; 492 if(state[3][c]==S_ERR) 493 state[3][c]=0; 494 } 495 } 496 else 497 { 498 sh_lexstates[ST_BEGIN]=(char*)sh_lexrstates[ST_BEGIN]; 499 sh_lexstates[ST_NAME]=(char*)sh_lexrstates[ST_NAME]; 500 sh_lexstates[ST_DOL]=(char*)sh_lexrstates[ST_DOL]; 501 sh_lexstates[ST_BRACE]=(char*)sh_lexrstates[ST_BRACE]; 502 } 503 } 504 #if ERROR_VERSION < 20000101L 505 if(type==LC_ALL || type==LC_MESSAGES) 506 error_info.translate = msg_translate; 507 #endif 508 } 509 #endif /* _hdr_locale */ 510 511 /* Trap for IFS assignment and invalidates state table */ 512 static void put_ifs(register Namval_t* np,const char *val,int flags,Namfun_t *fp) 513 { 514 register struct ifs *ip = (struct ifs*)fp; 515 ip->ifsnp = 0; 516 if(!val) 517 { 518 fp = nv_stack(np, NIL(Namfun_t*)); 519 if(fp && !fp->nofree) 520 { 521 free((void*)fp); 522 fp = 0; 523 } 524 } 525 if(val != np->nvalue.cp) 526 nv_putv(np, val, flags, fp); 527 if(!val) 528 { 529 if(fp) 530 fp->next = np->nvfun; 531 np->nvfun = fp; 532 } 533 } 534 535 /* 536 * This is the lookup function for IFS 537 * It keeps the sh.ifstable up to date 538 */ 539 static char* get_ifs(register Namval_t* np, Namfun_t *fp) 540 { 541 register struct ifs *ip = (struct ifs*)fp; 542 register char *cp, *value; 543 register int c,n; 544 register Shell_t *shp = nv_shell(np); 545 value = nv_getv(np,fp); 546 if(np!=ip->ifsnp) 547 { 548 ip->ifsnp = np; 549 memset(shp->ifstable,0,(1<<CHAR_BIT)); 550 if(cp=value) 551 { 552 #if SHOPT_MULTIBYTE 553 while(n=mbsize(cp),c= *(unsigned char*)cp) 554 #else 555 while(c= *(unsigned char*)cp++) 556 #endif /* SHOPT_MULTIBYTE */ 557 { 558 #if SHOPT_MULTIBYTE 559 cp++; 560 if(n>1) 561 { 562 cp += (n-1); 563 shp->ifstable[c] = S_MBYTE; 564 continue; 565 } 566 #endif /* SHOPT_MULTIBYTE */ 567 n = S_DELIM; 568 if(c== *cp) 569 cp++; 570 else if(c=='\n') 571 n = S_NL; 572 else if(isspace(c)) 573 n = S_SPACE; 574 shp->ifstable[c] = n; 575 } 576 } 577 else 578 { 579 shp->ifstable[' '] = shp->ifstable['\t'] = S_SPACE; 580 shp->ifstable['\n'] = S_NL; 581 } 582 } 583 return(value); 584 } 585 586 /* 587 * these functions are used to get and set the SECONDS variable 588 */ 589 #ifdef timeofday 590 # define dtime(tp) ((double)((tp)->tv_sec)+1e-6*((double)((tp)->tv_usec))) 591 # define tms timeval 592 #else 593 # define dtime(tp) (((double)times(tp))/shgd->lim.clk_tck) 594 # define timeofday(a) 595 #endif 596 597 static void put_seconds(register Namval_t* np,const char *val,int flags,Namfun_t *fp) 598 { 599 double d; 600 struct tms tp; 601 if(!val) 602 { 603 nv_putv(np, val, flags, fp); 604 fp = nv_stack(np, NIL(Namfun_t*)); 605 if(fp && !fp->nofree) 606 free((void*)fp); 607 return; 608 } 609 if(!np->nvalue.dp) 610 { 611 nv_setsize(np,3); 612 nv_onattr(np,NV_DOUBLE); 613 np->nvalue.dp = new_of(double,0); 614 } 615 nv_putv(np, val, flags, fp); 616 d = *np->nvalue.dp; 617 timeofday(&tp); 618 *np->nvalue.dp = dtime(&tp)-d; 619 } 620 621 static char* get_seconds(register Namval_t* np, Namfun_t *fp) 622 { 623 Shell_t *shp = nv_shell(np); 624 register int places = nv_size(np); 625 struct tms tp; 626 double d, offset = (np->nvalue.dp?*np->nvalue.dp:0); 627 NOT_USED(fp); 628 timeofday(&tp); 629 d = dtime(&tp)- offset; 630 sfprintf(shp->strbuf,"%.*f",places,d); 631 return(sfstruse(shp->strbuf)); 632 } 633 634 static Sfdouble_t nget_seconds(register Namval_t* np, Namfun_t *fp) 635 { 636 struct tms tp; 637 double offset = (np->nvalue.dp?*np->nvalue.dp:0); 638 NOT_USED(fp); 639 timeofday(&tp); 640 return(dtime(&tp)- offset); 641 } 642 643 /* 644 * These three functions are used to get and set the RANDOM variable 645 */ 646 static void put_rand(register Namval_t* np,const char *val,int flags,Namfun_t *fp) 647 { 648 struct rand *rp = (struct rand*)fp; 649 register long n; 650 if(!val) 651 { 652 fp = nv_stack(np, NIL(Namfun_t*)); 653 if(fp && !fp->nofree) 654 free((void*)fp); 655 _nv_unset(np,0); 656 return; 657 } 658 if(flags&NV_INTEGER) 659 n = *(double*)val; 660 else 661 n = sh_arith(rp->sh,val); 662 srand((int)(n&RANDMASK)); 663 rp->rand_last = -1; 664 if(!np->nvalue.lp) 665 np->nvalue.lp = &rp->rand_last; 666 } 667 668 /* 669 * get random number in range of 0 - 2**15 670 * never pick same number twice in a row 671 */ 672 static Sfdouble_t nget_rand(register Namval_t* np, Namfun_t *fp) 673 { 674 register long cur, last= *np->nvalue.lp; 675 NOT_USED(fp); 676 do 677 cur = (rand()>>rand_shift)&RANDMASK; 678 while(cur==last); 679 *np->nvalue.lp = cur; 680 return((Sfdouble_t)cur); 681 } 682 683 static char* get_rand(register Namval_t* np, Namfun_t *fp) 684 { 685 register long n = nget_rand(np,fp); 686 return(fmtbase(n, 10, 0)); 687 } 688 689 /* 690 * These three routines are for LINENO 691 */ 692 static Sfdouble_t nget_lineno(Namval_t* np, Namfun_t *fp) 693 { 694 double d=1; 695 if(error_info.line >0) 696 d = error_info.line; 697 else if(error_info.context && error_info.context->line>0) 698 d = error_info.context->line; 699 NOT_USED(np); 700 NOT_USED(fp); 701 return(d); 702 } 703 704 static void put_lineno(Namval_t* np,const char *val,int flags,Namfun_t *fp) 705 { 706 register long n; 707 Shell_t *shp = nv_shell(np); 708 if(!val) 709 { 710 fp = nv_stack(np, NIL(Namfun_t*)); 711 if(fp && !fp->nofree) 712 free((void*)fp); 713 _nv_unset(np,0); 714 return; 715 } 716 if(flags&NV_INTEGER) 717 n = *(double*)val; 718 else 719 n = sh_arith(shp,val); 720 shp->st.firstline += nget_lineno(np,fp)+1-n; 721 } 722 723 static char* get_lineno(register Namval_t* np, Namfun_t *fp) 724 { 725 register long n = nget_lineno(np,fp); 726 return(fmtbase(n, 10, 0)); 727 } 728 729 static char* get_lastarg(Namval_t* np, Namfun_t *fp) 730 { 731 Shell_t *shp = nv_shell(np); 732 char *cp; 733 int pid; 734 if(sh_isstate(SH_INIT) && (cp=shp->lastarg) && *cp=='*' && (pid=strtol(cp+1,&cp,10)) && *cp=='*') 735 nv_putval(np,cp+1,0); 736 return(shp->lastarg); 737 } 738 739 static void put_lastarg(Namval_t* np,const char *val,int flags,Namfun_t *fp) 740 { 741 Shell_t *shp = nv_shell(np); 742 if(flags&NV_INTEGER) 743 { 744 sfprintf(shp->strbuf,"%.*g",12,*((double*)val)); 745 val = sfstruse(shp->strbuf); 746 } 747 if(val) 748 val = strdup(val); 749 if(shp->lastarg && !nv_isattr(np,NV_NOFREE)) 750 free((void*)shp->lastarg); 751 else 752 nv_offattr(np,NV_NOFREE); 753 shp->lastarg = (char*)val; 754 nv_offattr(np,NV_EXPORT); 755 np->nvenv = 0; 756 } 757 758 static int hasgetdisc(register Namfun_t *fp) 759 { 760 while(fp && !fp->disc->getnum && !fp->disc->getval) 761 fp = fp->next; 762 return(fp!=0); 763 } 764 765 /* 766 * store the most recent value for use in .sh.match 767 * treat .sh.match as a two dimensional array 768 */ 769 void sh_setmatch(Shell_t *shp,const char *v, int vsize, int nmatch, regoff_t match[],int index) 770 { 771 struct match *mp = &ip->SH_MATCH_init; 772 Namval_t *np = nv_namptr(mp->node,0); 773 register int i,n,x, savesub=shp->subshell; 774 Namarr_t *ap = nv_arrayptr(SH_MATCHNOD); 775 shp->subshell = 0; 776 #ifndef SHOPT_2DMATCH 777 index = 0; 778 #else 779 if(index==0) 780 #endif /* SHOPT_2DMATCH */ 781 { 782 if(ap->hdr.next != &mp->hdr) 783 { 784 free((void*)ap); 785 ap = nv_arrayptr(np); 786 SH_MATCHNOD->nvfun = &ap->hdr; 787 } 788 if(ap) 789 { 790 ap->nelem &= ~ARRAY_SCAN; 791 i = array_elem(ap); 792 ap->nelem++; 793 while(--i>= 0) 794 { 795 nv_putsub(SH_MATCHNOD, (char*)0,i); 796 _nv_unset(SH_MATCHNOD,NV_RDONLY); 797 } 798 ap->nelem--; 799 } 800 if(!nv_hasdisc(SH_MATCHNOD,mp->hdr.disc)) 801 nv_disc(SH_MATCHNOD,&mp->hdr,NV_LAST); 802 if(nmatch) 803 nv_putsub(SH_MATCHNOD, NIL(char*), (nmatch-1)|ARRAY_FILL|ARRAY_SETSUB); 804 ap = nv_arrayptr(SH_MATCHNOD); 805 ap->nelem = mp->nmatch = nmatch; 806 mp->v = v; 807 mp->first = match[0]; 808 } 809 #ifdef SHOPT_2DMATCH 810 else 811 { 812 if(index==1) 813 { 814 np->nvalue.cp = Empty; 815 np->nvfun = SH_MATCHNOD->nvfun; 816 nv_onattr(np,NV_NOFREE|NV_ARRAY); 817 SH_MATCHNOD->nvfun = 0; 818 for(i=0; i < mp->nmatch; i++) 819 { 820 nv_putsub(SH_MATCHNOD, (char*)0, i); 821 nv_arraychild(SH_MATCHNOD, np,0); 822 } 823 if(ap = nv_arrayptr(SH_MATCHNOD)) 824 ap->nelem = mp->nmatch; 825 } 826 ap = nv_arrayptr(np); 827 nv_putsub(np, NIL(char*), index|ARRAY_FILL|ARRAY_SETSUB); 828 } 829 #endif /* SHOPT_2DMATCH */ 830 shp->subshell = savesub; 831 index *= 2*mp->nmatch; 832 if(mp->nmatch) 833 { 834 for(n=mp->first+(mp->v-v),vsize=0,i=0; i < 2*nmatch; i++) 835 { 836 if(match[i]>=0 && (match[i] - n) > vsize) 837 vsize = match[i] -n; 838 } 839 i = (index+2*mp->nmatch)*sizeof(match[0]); 840 if((i+vsize) >= mp->vsize) 841 { 842 if(mp->vsize) 843 mp->match = (int*)realloc(mp->match,i+vsize+1); 844 else 845 mp->match = (int*)malloc(i+vsize+1); 846 mp->vsize = i+vsize+1; 847 } 848 mp->val = ((char*)mp->match)+i; 849 memcpy(mp->match+index,match,nmatch*2*sizeof(match[0])); 850 for(x=0,i=0; i < 2*nmatch; i++) 851 { 852 if(match[i]>=0) 853 mp->match[index+i] -= n; 854 else 855 x=1; 856 857 } 858 ap->nelem -= x; 859 while(i < 2*mp->nmatch) 860 mp->match[index+i++] = -1; 861 memcpy(mp->val,v+n,vsize); 862 mp->val[vsize] = 0; 863 mp->lastsub[0] = mp->lastsub[1] = -1; 864 } 865 } 866 867 #define array_scan(np) ((nv_arrayptr(np)->nelem&ARRAY_SCAN)) 868 869 static char* get_match(register Namval_t* np, Namfun_t *fp) 870 { 871 struct match *mp = (struct match*)fp; 872 int sub,sub2=0,n,i =!mp->index; 873 char *val; 874 sub = nv_aindex(SH_MATCHNOD); 875 if(np!=SH_MATCHNOD) 876 sub2 = nv_aindex(np); 877 if(sub>=mp->nmatch) 878 return(0); 879 if(sub2>0) 880 sub += sub2*mp->nmatch; 881 if(sub==mp->lastsub[!i]) 882 return(mp->rval[!i]); 883 else if(sub==mp->lastsub[i]) 884 return(mp->rval[i]); 885 n = mp->match[2*sub+1]-mp->match[2*sub]; 886 if(n<=0) 887 return(mp->match[2*sub]<0?Empty:""); 888 val = mp->val+mp->match[2*sub]; 889 if(mp->val[mp->match[2*sub+1]]==0) 890 return(val); 891 mp->index = i; 892 if(mp->rval[i]) 893 { 894 free((void*)mp->rval[i]); 895 mp->rval[i] = 0; 896 } 897 mp->rval[i] = (char*)malloc(n+1); 898 mp->lastsub[i] = sub; 899 memcpy(mp->rval[i],val,n); 900 mp->rval[i][n] = 0; 901 return(mp->rval[i]); 902 } 903 904 static const Namdisc_t SH_MATCH_disc = { sizeof(struct match), 0, get_match }; 905 906 static char* get_version(register Namval_t* np, Namfun_t *fp) 907 { 908 return(nv_getv(np,fp)); 909 } 910 911 static Sfdouble_t nget_version(register Namval_t* np, Namfun_t *fp) 912 { 913 register const char *cp = e_version + strlen(e_version)-10; 914 register int c; 915 Sflong_t t = 0; 916 NOT_USED(fp); 917 918 while (c = *cp++) 919 if (c >= '0' && c <= '9') 920 { 921 t *= 10; 922 t += c - '0'; 923 } 924 return((Sfdouble_t)t); 925 } 926 927 static const Namdisc_t SH_VERSION_disc = { 0, 0, get_version, nget_version }; 928 929 #if SHOPT_FS_3D 930 /* 931 * set or unset the mappings given a colon separated list of directories 932 */ 933 static void vpath_set(char *str, int mode) 934 { 935 register char *lastp, *oldp=str, *newp=strchr(oldp,':'); 936 if(!shgd->lim.fs3d) 937 return; 938 while(newp) 939 { 940 *newp++ = 0; 941 if(lastp=strchr(newp,':')) 942 *lastp = 0; 943 mount((mode?newp:""),oldp,FS3D_VIEW,0); 944 newp[-1] = ':'; 945 oldp = newp; 946 newp=lastp; 947 } 948 } 949 950 /* catch vpath assignments */ 951 static void put_vpath(register Namval_t* np,const char *val,int flags,Namfun_t *fp) 952 { 953 register char *cp; 954 if(cp = nv_getval(np)) 955 vpath_set(cp,0); 956 if(val) 957 vpath_set((char*)val,1); 958 nv_putv(np,val,flags,fp); 959 } 960 static const Namdisc_t VPATH_disc = { 0, put_vpath }; 961 static Namfun_t VPATH_init = { &VPATH_disc, 1 }; 962 #endif /* SHOPT_FS_3D */ 963 964 965 static const Namdisc_t IFS_disc = { sizeof(struct ifs), put_ifs, get_ifs }; 966 const Namdisc_t RESTRICTED_disc = { sizeof(Namfun_t), put_restricted }; 967 static const Namdisc_t CDPATH_disc = { sizeof(Namfun_t), put_cdpath }; 968 static const Namdisc_t EDITOR_disc = { sizeof(Namfun_t), put_ed }; 969 static const Namdisc_t HISTFILE_disc = { sizeof(Namfun_t), put_history }; 970 static const Namdisc_t OPTINDEX_disc = { sizeof(Namfun_t), put_optindex, 0, nget_optindex, 0, 0, clone_optindex }; 971 static const Namdisc_t SECONDS_disc = { sizeof(struct seconds), put_seconds, get_seconds, nget_seconds }; 972 static const Namdisc_t RAND_disc = { sizeof(struct rand), put_rand, get_rand, nget_rand }; 973 static const Namdisc_t LINENO_disc = { sizeof(Namfun_t), put_lineno, get_lineno, nget_lineno }; 974 static const Namdisc_t L_ARG_disc = { sizeof(Namfun_t), put_lastarg, get_lastarg }; 975 976 977 #define MAX_MATH_ARGS 3 978 979 static char *name_math(Namval_t *np, Namfun_t *fp) 980 { 981 Shell_t *shp = sh_getinterp(); 982 sfprintf(shp->strbuf,".sh.math.%s",np->nvname); 983 return(sfstruse(shp->strbuf)); 984 } 985 986 static const Namdisc_t math_child_disc = 987 { 988 0,0,0,0,0,0,0, 989 name_math 990 }; 991 992 static Namfun_t math_child_fun = 993 { 994 &math_child_disc, 1, 0, sizeof(Namfun_t) 995 }; 996 997 static void math_init(Shell_t *shp) 998 { 999 Namval_t *np; 1000 char *name; 1001 int i; 1002 shp->mathnodes = (char*)calloc(1,MAX_MATH_ARGS*(NV_MINSZ+5)); 1003 name = shp->mathnodes+MAX_MATH_ARGS*NV_MINSZ; 1004 for(i=0; i < MAX_MATH_ARGS; i++) 1005 { 1006 np = nv_namptr(shp->mathnodes,i); 1007 np->nvfun = &math_child_fun; 1008 memcpy(name,"arg",3); 1009 name[3] = '1'+i; 1010 np->nvname = name; 1011 name+=5; 1012 nv_onattr(np,NV_MINIMAL|NV_NOFREE|NV_LDOUBLE|NV_RDONLY); 1013 } 1014 } 1015 1016 static Namval_t *create_math(Namval_t *np,const char *name,int flag,Namfun_t *fp) 1017 { 1018 Shell_t *shp = nv_shell(np); 1019 if(!name) 1020 return(SH_MATHNOD); 1021 if(name[0]!='a' || name[1]!='r' || name[2]!='g' || name[4] || !isdigit(name[3]) || (name[3]=='0' || (name[3]-'0')>MAX_MATH_ARGS)) 1022 return(0); 1023 fp->last = (char*)&name[4]; 1024 return(nv_namptr(shp->mathnodes,name[3]-'1')); 1025 } 1026 1027 static char* get_math(register Namval_t* np, Namfun_t *fp) 1028 { 1029 Shell_t *shp = nv_shell(np); 1030 Namval_t *mp,fake; 1031 char *val; 1032 int first=0; 1033 fake.nvname = ".sh.math."; 1034 mp = (Namval_t*)dtprev(shp->fun_tree,&fake); 1035 while(mp=(Namval_t*)dtnext(shp->fun_tree,mp)) 1036 { 1037 if(memcmp(mp->nvname,".sh.math.",9)) 1038 break; 1039 if(first++) 1040 sfputc(shp->strbuf,' '); 1041 sfputr(shp->strbuf,mp->nvname+9,-1); 1042 } 1043 val = sfstruse(shp->strbuf); 1044 return(val); 1045 1046 } 1047 1048 static char *setdisc_any(Namval_t *np, const char *event, Namval_t *action, Namfun_t *fp) 1049 { 1050 Shell_t *shp=nv_shell(np); 1051 Namval_t *mp,fake; 1052 char *name; 1053 int getname=0, off=staktell(); 1054 fake.nvname = nv_name(np); 1055 if(!event) 1056 { 1057 if(!action) 1058 { 1059 mp = (Namval_t*)dtprev(shp->fun_tree,&fake); 1060 return((char*)dtnext(shp->fun_tree,mp)); 1061 } 1062 getname = 1; 1063 } 1064 stakputs(fake.nvname); 1065 stakputc('.'); 1066 stakputs(event); 1067 stakputc(0); 1068 name = stakptr(off); 1069 mp = nv_search(name, shp->fun_tree, action?NV_ADD:0); 1070 stakseek(off); 1071 if(getname) 1072 return(mp?(char*)dtnext(shp->fun_tree,mp):0); 1073 if(action==np) 1074 action = mp; 1075 return(action?(char*)action:""); 1076 } 1077 1078 static const Namdisc_t SH_MATH_disc = { 0, 0, get_math, 0, setdisc_any, create_math, }; 1079 1080 #if SHOPT_COSHELL 1081 static const Namdisc_t SH_JOBPOOL_disc = { 0, 0, 0, 0, setdisc_any, 0, }; 1082 #endif /* SHOPT_COSHELL */ 1083 1084 #if SHOPT_NAMESPACE 1085 static char* get_nspace(Namval_t* np, Namfun_t *fp) 1086 { 1087 if(sh.namespace) 1088 return(nv_name(sh.namespace)); 1089 return((char*)np->nvalue.cp); 1090 } 1091 static const Namdisc_t NSPACE_disc = { 0, 0, get_nspace }; 1092 static Namfun_t NSPACE_init = { &NSPACE_disc, 1}; 1093 #endif /* SHOPT_NAMESPACE */ 1094 1095 #ifdef _hdr_locale 1096 static const Namdisc_t LC_disc = { sizeof(Namfun_t), put_lang }; 1097 #endif /* _hdr_locale */ 1098 1099 /* 1100 * This function will get called whenever a configuration parameter changes 1101 */ 1102 static int newconf(const char *name, const char *path, const char *value) 1103 { 1104 Shell_t *shp = sh_getinterp(); 1105 register char *arg; 1106 if(!name) 1107 setenviron(value); 1108 else if(strcmp(name,"UNIVERSE")==0 && strcmp(astconf(name,0,0),value)) 1109 { 1110 shp->universe = 0; 1111 /* set directory in new universe */ 1112 if(*(arg = path_pwd(shp,0))=='/') 1113 chdir(arg); 1114 /* clear out old tracked alias */ 1115 stakseek(0); 1116 stakputs(nv_getval(PATHNOD)); 1117 stakputc(0); 1118 nv_putval(PATHNOD,stakseek(0),NV_RDONLY); 1119 } 1120 return(1); 1121 } 1122 1123 #if (CC_NATIVE != CC_ASCII) 1124 static void a2e(char *d, const char *s) 1125 { 1126 register const unsigned char *t; 1127 register int i; 1128 t = CCMAP(CC_ASCII, CC_NATIVE); 1129 for(i=0; i<(1<<CHAR_BIT); i++) 1130 d[t[i]] = s[i]; 1131 } 1132 1133 static void init_ebcdic(void) 1134 { 1135 int i; 1136 char *cp = (char*)malloc(ST_NONE*(1<<CHAR_BIT)); 1137 for(i=0; i < ST_NONE; i++) 1138 { 1139 a2e(cp,sh_lexrstates[i]); 1140 sh_lexstates[i] = cp; 1141 cp += (1<<CHAR_BIT); 1142 } 1143 } 1144 #endif 1145 1146 /* 1147 * return SH_TYPE_* bitmask for path 1148 * 0 for "not a shell" 1149 */ 1150 int sh_type(register const char *path) 1151 { 1152 register const char* s; 1153 register int t = 0; 1154 1155 if (s = (const char*)strrchr(path, '/')) 1156 { 1157 if (*path == '-') 1158 t |= SH_TYPE_LOGIN; 1159 s++; 1160 } 1161 else 1162 s = path; 1163 if (*s == '-') 1164 { 1165 s++; 1166 t |= SH_TYPE_LOGIN; 1167 } 1168 for (;;) 1169 { 1170 if (!(t & (SH_TYPE_KSH|SH_TYPE_BASH))) 1171 { 1172 if (*s == 'k') 1173 { 1174 s++; 1175 t |= SH_TYPE_KSH; 1176 continue; 1177 } 1178 #if SHOPT_BASH 1179 if (*s == 'b' && *(s+1) == 'a') 1180 { 1181 s += 2; 1182 t |= SH_TYPE_BASH; 1183 continue; 1184 } 1185 #endif 1186 } 1187 if (!(t & (SH_TYPE_PROFILE|SH_TYPE_RESTRICTED))) 1188 { 1189 #if SHOPT_PFSH 1190 if (*s == 'p' && *(s+1) == 'f') 1191 { 1192 s += 2; 1193 t |= SH_TYPE_PROFILE; 1194 continue; 1195 } 1196 #endif 1197 if (*s == 'r') 1198 { 1199 s++; 1200 t |= SH_TYPE_RESTRICTED; 1201 continue; 1202 } 1203 } 1204 break; 1205 } 1206 if (*s++ == 's' && (*s == 'h' || *s == 'u')) 1207 { 1208 s++; 1209 t |= SH_TYPE_SH; 1210 if ((t & SH_TYPE_KSH) && *s == '9' && *(s+1) == '3') 1211 s += 2; 1212 #if _WINIX 1213 if (*s == '.' && *(s+1) == 'e' && *(s+2) == 'x' && *(s+3) == 'e') 1214 s += 4; 1215 #endif 1216 if (!isalnum(*s)) 1217 return t; 1218 } 1219 return t & ~(SH_TYPE_BASH|SH_TYPE_KSH|SH_TYPE_PROFILE|SH_TYPE_RESTRICTED); 1220 } 1221 1222 1223 static char *get_mode(Namval_t* np, Namfun_t* nfp) 1224 { 1225 mode_t mode = nv_getn(np,nfp); 1226 return(fmtperm(mode)); 1227 } 1228 1229 static void put_mode(Namval_t* np, const char* val, int flag, Namfun_t* nfp) 1230 { 1231 if(val) 1232 { 1233 mode_t mode; 1234 char *last=0; 1235 if(flag&NV_INTEGER) 1236 { 1237 if(flag&NV_LONG) 1238 mode = *(Sfdouble_t*)val; 1239 else 1240 mode = *(double*)val; 1241 } 1242 else 1243 mode = strperm(val, &last,0); 1244 if(*last) 1245 errormsg(SH_DICT,ERROR_exit(1),"%s: invalid mode string",val); 1246 nv_putv(np,(char*)&mode,NV_INTEGER,nfp); 1247 } 1248 else 1249 nv_putv(np,val,flag,nfp); 1250 } 1251 1252 static const Namdisc_t modedisc = 1253 { 1254 0, 1255 put_mode, 1256 get_mode, 1257 }; 1258 1259 1260 /* 1261 * initialize the shell 1262 */ 1263 Shell_t *sh_init(register int argc,register char *argv[], Shinit_f userinit) 1264 { 1265 static int beenhere; 1266 Shell_t *shp; 1267 register int n; 1268 int type; 1269 static char *login_files[3]; 1270 memfatal(); 1271 n = strlen(e_version); 1272 if(e_version[n-1]=='$' && e_version[n-2]==' ') 1273 e_version[n-2]=0; 1274 #if (CC_NATIVE == CC_ASCII) 1275 memcpy(sh_lexstates,sh_lexrstates,ST_NONE*sizeof(char*)); 1276 #else 1277 init_ebcdic(); 1278 #endif 1279 if(!beenhere) 1280 { 1281 beenhere = 1; 1282 shp = &sh; 1283 shgd = newof(0,struct shared,1,0); 1284 shgd->pid = getpid(); 1285 shgd->ppid = getppid(); 1286 shgd->userid=getuid(); 1287 shgd->euserid=geteuid(); 1288 shgd->groupid=getgid(); 1289 shgd->egroupid=getegid(); 1290 shgd->lim.clk_tck = getconf("CLK_TCK"); 1291 shgd->lim.arg_max = getconf("ARG_MAX"); 1292 shgd->lim.child_max = getconf("CHILD_MAX"); 1293 shgd->lim.ngroups_max = getconf("NGROUPS_MAX"); 1294 shgd->lim.posix_version = getconf("VERSION"); 1295 shgd->lim.posix_jobcontrol = getconf("JOB_CONTROL"); 1296 if(shgd->lim.arg_max <=0) 1297 shgd->lim.arg_max = ARG_MAX; 1298 if(shgd->lim.child_max <=0) 1299 shgd->lim.child_max = CHILD_MAX; 1300 if(shgd->lim.clk_tck <=0) 1301 shgd->lim.clk_tck = CLK_TCK; 1302 #if SHOPT_FS_3D 1303 if(fs3d(FS3D_TEST)) 1304 shgd->lim.fs3d = 1; 1305 #endif /* SHOPT_FS_3D */ 1306 shgd->ed_context = (void*)ed_open(shp); 1307 error_info.exit = sh_exit; 1308 error_info.id = path_basename(argv[0]); 1309 } 1310 else 1311 shp = newof(0,Shell_t,1,0); 1312 umask(shp->mask=umask(0)); 1313 shp->gd = shgd; 1314 shp->mac_context = sh_macopen(shp); 1315 shp->arg_context = sh_argopen(shp); 1316 shp->lex_context = (void*)sh_lexopen(0,shp,1); 1317 shp->strbuf = sfstropen(); 1318 shp->stk = stkstd; 1319 sfsetbuf(shp->strbuf,(char*)0,64); 1320 sh_onstate(SH_INIT); 1321 #if ERROR_VERSION >= 20000102L 1322 error_info.catalog = e_dict; 1323 #endif 1324 #if SHOPT_REGRESS 1325 { 1326 Opt_t* nopt; 1327 Opt_t* oopt; 1328 char* a; 1329 char** av = argv; 1330 char* regress[3]; 1331 1332 sh_regress_init(shp); 1333 regress[0] = "__regress__"; 1334 regress[2] = 0; 1335 /* NOTE: only shp is used by __regress__ at this point */ 1336 shp->bltindata.shp = shp; 1337 while ((a = *++av) && a[0] == '-' && (a[1] == 'I' || a[1] == '-' && a[2] == 'r')) 1338 { 1339 if (a[1] == 'I') 1340 { 1341 if (a[2]) 1342 regress[1] = a + 2; 1343 else if (!(regress[1] = *++av)) 1344 break; 1345 } 1346 else if (strncmp(a+2, "regress", 7)) 1347 break; 1348 else if (a[9] == '=') 1349 regress[1] = a + 10; 1350 else if (!(regress[1] = *++av)) 1351 break; 1352 nopt = optctx(0, 0); 1353 oopt = optctx(nopt, 0); 1354 b___regress__(2, regress, &shp->bltindata); 1355 optctx(oopt, nopt); 1356 } 1357 } 1358 #endif 1359 shp->cpipe[0] = -1; 1360 shp->coutpipe = -1; 1361 for(n=0;n < 10; n++) 1362 { 1363 /* don't use lower bits when rand() generates large numbers */ 1364 if(rand() > RANDMASK) 1365 { 1366 rand_shift = 3; 1367 break; 1368 } 1369 } 1370 sh_ioinit(shp); 1371 /* initialize signal handling */ 1372 sh_siginit(shp); 1373 stakinstall(NIL(Stak_t*),nospace); 1374 /* set up memory for name-value pairs */ 1375 shp->init_context = nv_init(shp); 1376 /* read the environment */ 1377 if(argc>0) 1378 { 1379 type = sh_type(*argv); 1380 if(type&SH_TYPE_LOGIN) 1381 shp->login_sh = 2; 1382 } 1383 env_init(shp); 1384 if(!ENVNOD->nvalue.cp) 1385 { 1386 sfprintf(shp->strbuf,"%s/.kshrc",nv_getval(HOME)); 1387 nv_putval(ENVNOD,sfstruse(shp->strbuf),NV_RDONLY); 1388 } 1389 *SHLVL->nvalue.ip +=1; 1390 nv_offattr(SHLVL,NV_IMPORT); 1391 #if SHOPT_SPAWN 1392 { 1393 /* 1394 * try to find the pathname for this interpreter 1395 * try using environment variable _ or argv[0] 1396 */ 1397 char *cp=nv_getval(L_ARGNOD); 1398 char buff[PATH_MAX+1]; 1399 shp->gd->shpath = 0; 1400 #if _AST_VERSION >= 20090202L 1401 if((n = pathprog(NiL, buff, sizeof(buff))) > 0 && n <= sizeof(buff)) 1402 shp->gd->shpath = strdup(buff); 1403 #else 1404 sfprintf(shp->strbuf,"/proc/%d/exe",getpid()); 1405 if((n=readlink(sfstruse(shp->strbuf),buff,sizeof(buff)-1))>0) 1406 { 1407 buff[n] = 0; 1408 shp->gd->shpath = strdup(buff); 1409 } 1410 #endif 1411 else if((cp && (sh_type(cp)&SH_TYPE_SH)) || (argc>0 && strchr(cp= *argv,'/'))) 1412 { 1413 if(*cp=='/') 1414 shp->gd->shpath = strdup(cp); 1415 else if(cp = nv_getval(PWDNOD)) 1416 { 1417 int offset = staktell(); 1418 stakputs(cp); 1419 stakputc('/'); 1420 stakputs(argv[0]); 1421 pathcanon(stakptr(offset),PATH_DOTDOT); 1422 shp->gd->shpath = strdup(stakptr(offset)); 1423 stakseek(offset); 1424 } 1425 } 1426 } 1427 #endif 1428 nv_putval(IFSNOD,(char*)e_sptbnl,NV_RDONLY); 1429 #if SHOPT_FS_3D 1430 nv_stack(VPATHNOD, &VPATH_init); 1431 #endif /* SHOPT_FS_3D */ 1432 astconfdisc(newconf); 1433 #if SHOPT_TIMEOUT 1434 shp->st.tmout = SHOPT_TIMEOUT; 1435 #endif /* SHOPT_TIMEOUT */ 1436 /* initialize jobs table */ 1437 job_clear(); 1438 sh_onoption(SH_MULTILINE); 1439 if(argc>0) 1440 { 1441 int dolv_index = -1; 1442 /* check for restricted shell */ 1443 if(type&SH_TYPE_RESTRICTED) 1444 sh_onoption(SH_RESTRICTED); 1445 #if SHOPT_PFSH 1446 /* check for profile shell */ 1447 else if(type&SH_TYPE_PROFILE) 1448 sh_onoption(SH_PFSH); 1449 #endif 1450 #if SHOPT_BASH 1451 /* check for invocation as bash */ 1452 if(type&SH_TYPE_BASH) 1453 { 1454 shp>userinit = userinit = bash_init; 1455 sh_onoption(SH_BASH); 1456 sh_onstate(SH_PREINIT); 1457 (*userinit)(shp, 0); 1458 sh_offstate(SH_PREINIT); 1459 } 1460 #endif 1461 /* look for options */ 1462 /* shp->st.dolc is $# */ 1463 if((shp->st.dolc = sh_argopts(-argc,argv,shp)) < 0) 1464 { 1465 shp->exitval = 2; 1466 sh_done(shp,0); 1467 } 1468 opt_info.disc = 0; 1469 dolv_index = (argc-1)-shp->st.dolc; 1470 shp->st.dolv=argv+dolv_index; 1471 shp->st.repl_index = dolv_index; 1472 shp->st.repl_arg = argv[dolv_index]; 1473 shp->st.dolv[0] = argv[0]; 1474 if(shp->st.dolc < 1) 1475 sh_onoption(SH_SFLAG); 1476 if(!sh_isoption(SH_SFLAG)) 1477 { 1478 shp->st.dolc--; 1479 shp->st.dolv++; 1480 #if _WINIX 1481 { 1482 char* name; 1483 name = shp->st.dolv[0]; 1484 if(name[1]==':' && (name[2]=='/' || name[2]=='\\')) 1485 { 1486 #if _lib_pathposix 1487 char* p; 1488 1489 if((n = pathposix(name, NIL(char*), 0)) > 0 && (p = (char*)malloc(++n))) 1490 { 1491 pathposix(name, p, n); 1492 name = p; 1493 } 1494 else 1495 #endif 1496 { 1497 name[1] = name[0]; 1498 name[0] = name[2] = '/'; 1499 } 1500 } 1501 } 1502 #endif /* _WINIX */ 1503 } 1504 if(beenhere==1) 1505 { 1506 struct lconv* lc; 1507 shp->decomma = (lc=localeconv()) && lc->decimal_point && *lc->decimal_point==','; 1508 beenhere = 2; 1509 } 1510 } 1511 #if SHOPT_PFSH 1512 if (sh_isoption(SH_PFSH)) 1513 { 1514 struct passwd *pw = getpwuid(shp->gd->userid); 1515 if(pw) 1516 shp->gd->user = strdup(pw->pw_name); 1517 1518 } 1519 #endif 1520 /* set[ug]id scripts require the -p flag */ 1521 if(shp->gd->userid!=shp->gd->euserid || shp->gd->groupid!=shp->gd->egroupid) 1522 { 1523 #ifdef SHOPT_P_SUID 1524 /* require sh -p to run setuid and/or setgid */ 1525 if(!sh_isoption(SH_PRIVILEGED) && shp->gd->userid >= SHOPT_P_SUID) 1526 { 1527 setuid(shp->gd->euserid=shp->gd->userid); 1528 setgid(shp->gd->egroupid=shp->gd->groupid); 1529 } 1530 else 1531 #endif /* SHOPT_P_SUID */ 1532 sh_onoption(SH_PRIVILEGED); 1533 #ifdef SHELLMAGIC 1534 /* careful of #! setuid scripts with name beginning with - */ 1535 if(shp->login_sh && argv[1] && strcmp(argv[0],argv[1])==0) 1536 errormsg(SH_DICT,ERROR_exit(1),e_prohibited); 1537 #endif /*SHELLMAGIC*/ 1538 } 1539 else 1540 sh_offoption(SH_PRIVILEGED); 1541 /* shname for $0 in profiles and . scripts */ 1542 if(sh_isdevfd(argv[1])) 1543 shp->shname = strdup(argv[0]); 1544 else 1545 shp->shname = strdup(shp->st.dolv[0]); 1546 /* 1547 * return here for shell script execution 1548 * but not for parenthesis subshells 1549 */ 1550 error_info.id = strdup(shp->st.dolv[0]); /* error_info.id is $0 */ 1551 shp->jmpbuffer = (void*)&shp->checkbase; 1552 sh_pushcontext(shp,&shp->checkbase,SH_JMPSCRIPT); 1553 shp->st.self = &shp->global; 1554 shp->topscope = (Shscope_t*)shp->st.self; 1555 sh_offstate(SH_INIT); 1556 login_files[0] = (char*)e_profile; 1557 login_files[1] = ".profile"; 1558 shp->gd->login_files = login_files; 1559 shp->bltindata.version = SH_VERSION; 1560 shp->bltindata.shp = shp; 1561 shp->bltindata.shrun = sh_run; 1562 shp->bltindata.shtrap = sh_trap; 1563 shp->bltindata.shexit = sh_exit; 1564 shp->bltindata.shbltin = sh_addbuiltin; 1565 #if _AST_VERSION >= 20080617L 1566 shp->bltindata.shgetenv = sh_getenv; 1567 shp->bltindata.shsetenv = sh_setenviron; 1568 astintercept(&shp->bltindata,1); 1569 #endif 1570 #if 0 1571 #define NV_MKINTTYPE(x,y,z) nv_mkinttype(#x,sizeof(x),(x)-1<0,(y),(Namdisc_t*)z); 1572 NV_MKINTTYPE(pid_t,"process id",0); 1573 NV_MKINTTYPE(gid_t,"group id",0); 1574 NV_MKINTTYPE(uid_t,"user id",0); 1575 NV_MKINTTYPE(size_t,(const char*)0,0); 1576 NV_MKINTTYPE(ssize_t,(const char*)0,0); 1577 NV_MKINTTYPE(off_t,"offset in bytes",0); 1578 NV_MKINTTYPE(ino_t,"\ai-\anode number",0); 1579 NV_MKINTTYPE(mode_t,(const char*)0,&modedisc); 1580 NV_MKINTTYPE(dev_t,"device id",0); 1581 NV_MKINTTYPE(nlink_t,"hard link count",0); 1582 NV_MKINTTYPE(blkcnt_t,"block count",0); 1583 NV_MKINTTYPE(time_t,"seconds since the epoch",0); 1584 nv_mkstat(); 1585 #endif 1586 if(shp->userinit=userinit) 1587 (*userinit)(shp, 0); 1588 shp->exittrap = 0; 1589 shp->errtrap = 0; 1590 shp->end_fn = 0; 1591 return(shp); 1592 } 1593 1594 Shell_t *sh_getinterp(void) 1595 { 1596 return(&sh); 1597 } 1598 1599 /* 1600 * reinitialize before executing a script 1601 */ 1602 int sh_reinit(char *argv[]) 1603 { 1604 Shell_t *shp = sh_getinterp(); 1605 Shopt_t opt; 1606 Namval_t *np,*npnext; 1607 Dt_t *dp; 1608 struct adata 1609 { 1610 Shell_t *sh; 1611 void *extra[2]; 1612 } data; 1613 for(np=dtfirst(shp->fun_tree);np;np=npnext) 1614 { 1615 if((dp=shp->fun_tree)->walk) 1616 dp = dp->walk; 1617 npnext = (Namval_t*)dtnext(shp->fun_tree,np); 1618 if(np>= shgd->bltin_cmds && np < &shgd->bltin_cmds[nbltins]) 1619 continue; 1620 if(is_abuiltin(np) && nv_isattr(np,NV_EXPORT)) 1621 continue; 1622 if(*np->nvname=='/') 1623 continue; 1624 nv_delete(np,dp,NV_NOFREE); 1625 } 1626 dtclose(shp->alias_tree); 1627 shp->alias_tree = inittree(shp,shtab_aliases); 1628 shp->last_root = shp->var_tree; 1629 shp->inuse_bits = 0; 1630 if(shp->userinit) 1631 (*shp->userinit)(shp, 1); 1632 if(shp->heredocs) 1633 { 1634 sfclose(shp->heredocs); 1635 shp->heredocs = 0; 1636 } 1637 /* remove locals */ 1638 sh_onstate(SH_INIT); 1639 memset(&data,0,sizeof(data)); 1640 data.sh = shp; 1641 nv_scan(shp->var_tree,sh_envnolocal,(void*)&data,NV_EXPORT,0); 1642 nv_scan(shp->var_tree,sh_envnolocal,(void*)&data,NV_ARRAY,NV_ARRAY); 1643 sh_offstate(SH_INIT); 1644 memset(shp->st.trapcom,0,(shp->st.trapmax+1)*sizeof(char*)); 1645 memset((void*)&opt,0,sizeof(opt)); 1646 #if SHOPT_NAMESPACE 1647 if(shp->namespace) 1648 { 1649 dp=nv_dict(shp->namespace); 1650 if(dp==shp->var_tree) 1651 shp->var_tree = dtview(dp,0); 1652 _nv_unset(shp->namespace,NV_RDONLY); 1653 shp->namespace = 0; 1654 } 1655 #endif /* SHOPT_NAMESPACE */ 1656 if(sh_isoption(SH_TRACKALL)) 1657 on_option(&opt,SH_TRACKALL); 1658 if(sh_isoption(SH_EMACS)) 1659 on_option(&opt,SH_EMACS); 1660 if(sh_isoption(SH_GMACS)) 1661 on_option(&opt,SH_GMACS); 1662 if(sh_isoption(SH_VI)) 1663 on_option(&opt,SH_VI); 1664 if(sh_isoption(SH_VIRAW)) 1665 on_option(&opt,SH_VIRAW); 1666 shp->options = opt; 1667 /* set up new args */ 1668 if(argv) 1669 shp->arglist = sh_argcreate(argv); 1670 if(shp->arglist) 1671 sh_argreset(shp,shp->arglist,NIL(struct dolnod*)); 1672 shp->envlist=0; 1673 shp->curenv = 0; 1674 shp->shname = error_info.id = strdup(shp->st.dolv[0]); 1675 sh_offstate(SH_FORKED); 1676 shp->fn_depth = shp->dot_depth = 0; 1677 sh_sigreset(0); 1678 if(!(SHLVL->nvalue.ip)) 1679 { 1680 shlvl = 0; 1681 SHLVL->nvalue.ip = &shlvl; 1682 nv_onattr(SHLVL,NV_INTEGER|NV_EXPORT|NV_NOFREE); 1683 } 1684 *SHLVL->nvalue.ip +=1; 1685 nv_offattr(SHLVL,NV_IMPORT); 1686 shp->st.filename = strdup(shp->lastarg); 1687 nv_delete((Namval_t*)0, (Dt_t*)0, 0); 1688 job.exitval = 0; 1689 shp->inpipe = shp->outpipe = 0; 1690 job_clear(); 1691 job.in_critical = 0; 1692 shp->exittrap = 0; 1693 shp->errtrap = 0; 1694 shp->end_fn = 0; 1695 return(1); 1696 } 1697 1698 /* 1699 * set when creating a local variable of this name 1700 */ 1701 Namfun_t *nv_cover(register Namval_t *np) 1702 { 1703 if(np==IFSNOD || np==PATHNOD || np==SHELLNOD || np==FPATHNOD || np==CDPNOD || np==SECONDS || np==ENVNOD || np==LINENO) 1704 return(np->nvfun); 1705 #ifdef _hdr_locale 1706 if(np==LCALLNOD || np==LCTYPENOD || np==LCMSGNOD || np==LCCOLLNOD || np==LCNUMNOD || np==LANGNOD) 1707 return(np->nvfun); 1708 #endif 1709 return(0); 1710 } 1711 1712 static const char *shdiscnames[] = { "tilde", 0}; 1713 1714 #ifdef SHOPT_STATS 1715 struct Stats 1716 { 1717 Namfun_t hdr; 1718 Shell_t *sh; 1719 char *nodes; 1720 int numnodes; 1721 int current; 1722 }; 1723 1724 static Namval_t *next_stat(register Namval_t* np, Dt_t *root,Namfun_t *fp) 1725 { 1726 struct Stats *sp = (struct Stats*)fp; 1727 if(!root) 1728 sp->current = 0; 1729 else if(++sp->current>=sp->numnodes) 1730 return(0); 1731 return(nv_namptr(sp->nodes,sp->current)); 1732 } 1733 1734 static Namval_t *create_stat(Namval_t *np,const char *name,int flag,Namfun_t *fp) 1735 { 1736 struct Stats *sp = (struct Stats*)fp; 1737 register const char *cp=name; 1738 register int i=0,n; 1739 Namval_t *nq=0; 1740 Shell_t *shp = sp->sh; 1741 if(!name) 1742 return(SH_STATS); 1743 while((i=*cp++) && i != '=' && i != '+' && i!='['); 1744 n = (cp-1) -name; 1745 for(i=0; i < sp->numnodes; i++) 1746 { 1747 nq = nv_namptr(sp->nodes,i); 1748 if((n==0||memcmp(name,nq->nvname,n)==0) && nq->nvname[n]==0) 1749 goto found; 1750 } 1751 nq = 0; 1752 found: 1753 if(nq) 1754 { 1755 fp->last = (char*)&name[n]; 1756 shp->last_table = SH_STATS; 1757 } 1758 else 1759 errormsg(SH_DICT,ERROR_exit(1),e_notelem,n,name,nv_name(np)); 1760 return(nq); 1761 } 1762 1763 static const Namdisc_t stat_disc = 1764 { 1765 0, 0, 0, 0, 0, 1766 create_stat, 1767 0, 0, 1768 next_stat 1769 }; 1770 1771 static char *name_stat(Namval_t *np, Namfun_t *fp) 1772 { 1773 Shell_t *shp = sh_getinterp(); 1774 sfprintf(shp->strbuf,".sh.stats.%s",np->nvname); 1775 return(sfstruse(shp->strbuf)); 1776 } 1777 1778 static const Namdisc_t stat_child_disc = 1779 { 1780 0,0,0,0,0,0,0, 1781 name_stat 1782 }; 1783 1784 static Namfun_t stat_child_fun = 1785 { 1786 &stat_child_disc, 1, 0, sizeof(Namfun_t) 1787 }; 1788 1789 static void stat_init(Shell_t *shp) 1790 { 1791 int i,nstat = STAT_SUBSHELL+1; 1792 struct Stats *sp = newof(0,struct Stats,1,nstat*NV_MINSZ); 1793 Namval_t *np; 1794 sp->numnodes = nstat; 1795 sp->nodes = (char*)(sp+1); 1796 shgd->stats = (int*)calloc(sizeof(int),nstat); 1797 sp->sh = shp; 1798 for(i=0; i < nstat; i++) 1799 { 1800 np = nv_namptr(sp->nodes,i); 1801 np->nvfun = &stat_child_fun; 1802 np->nvname = (char*)shtab_stats[i].sh_name; 1803 nv_onattr(np,NV_RDONLY|NV_MINIMAL|NV_NOFREE|NV_INTEGER); 1804 nv_setsize(np,10); 1805 np->nvalue.ip = &shgd->stats[i]; 1806 } 1807 sp->hdr.dsize = sizeof(struct Stats) + nstat*(sizeof(int)+NV_MINSZ); 1808 sp->hdr.disc = &stat_disc; 1809 nv_stack(SH_STATS,&sp->hdr); 1810 sp->hdr.nofree = 1; 1811 nv_setvtree(SH_STATS); 1812 } 1813 #else 1814 # define stat_init(x) 1815 #endif /* SHOPT_STATS */ 1816 1817 /* 1818 * Initialize the shell name and alias table 1819 */ 1820 static Init_t *nv_init(Shell_t *shp) 1821 { 1822 double d=0; 1823 ip = newof(0,Init_t,1,0); 1824 if(!ip) 1825 return(0); 1826 shp->nvfun.last = (char*)shp; 1827 shp->nvfun.nofree = 1; 1828 ip->sh = shp; 1829 shp->var_base = shp->var_tree = inittree(shp,shtab_variables); 1830 SHLVL->nvalue.ip = &shlvl; 1831 ip->IFS_init.hdr.disc = &IFS_disc; 1832 ip->PATH_init.disc = &RESTRICTED_disc; 1833 ip->PATH_init.nofree = 1; 1834 ip->FPATH_init.disc = &RESTRICTED_disc; 1835 ip->FPATH_init.nofree = 1; 1836 ip->CDPATH_init.disc = &CDPATH_disc; 1837 ip->CDPATH_init.nofree = 1; 1838 ip->SHELL_init.disc = &RESTRICTED_disc; 1839 ip->SHELL_init.nofree = 1; 1840 ip->ENV_init.disc = &RESTRICTED_disc; 1841 ip->ENV_init.nofree = 1; 1842 ip->VISUAL_init.disc = &EDITOR_disc; 1843 ip->VISUAL_init.nofree = 1; 1844 ip->EDITOR_init.disc = &EDITOR_disc; 1845 ip->EDITOR_init.nofree = 1; 1846 ip->HISTFILE_init.disc = &HISTFILE_disc; 1847 ip->HISTFILE_init.nofree = 1; 1848 ip->HISTSIZE_init.disc = &HISTFILE_disc; 1849 ip->HISTSIZE_init.nofree = 1; 1850 ip->OPTINDEX_init.disc = &OPTINDEX_disc; 1851 ip->OPTINDEX_init.nofree = 1; 1852 ip->SECONDS_init.hdr.disc = &SECONDS_disc; 1853 ip->SECONDS_init.hdr.nofree = 1; 1854 ip->RAND_init.hdr.disc = &RAND_disc; 1855 ip->RAND_init.hdr.nofree = 1; 1856 ip->RAND_init.sh = shp; 1857 ip->SH_MATCH_init.hdr.disc = &SH_MATCH_disc; 1858 ip->SH_MATCH_init.hdr.nofree = 1; 1859 ip->SH_MATH_init.disc = &SH_MATH_disc; 1860 ip->SH_MATH_init.nofree = 1; 1861 #if SHOPT_COSHELL 1862 ip->SH_JOBPOOL_init.disc = &SH_JOBPOOL_disc; 1863 ip->SH_JOBPOOL_init.nofree = 1; 1864 nv_stack(SH_JOBPOOL, &ip->SH_JOBPOOL_init); 1865 #endif /* SHOPT_COSHELL */ 1866 ip->SH_VERSION_init.disc = &SH_VERSION_disc; 1867 ip->SH_VERSION_init.nofree = 1; 1868 ip->LINENO_init.disc = &LINENO_disc; 1869 ip->LINENO_init.nofree = 1; 1870 ip->L_ARG_init.disc = &L_ARG_disc; 1871 ip->L_ARG_init.nofree = 1; 1872 #ifdef _hdr_locale 1873 ip->LC_TYPE_init.disc = &LC_disc; 1874 ip->LC_TYPE_init.nofree = 1; 1875 ip->LC_NUM_init.disc = &LC_disc; 1876 ip->LC_NUM_init.nofree = 1; 1877 ip->LC_COLL_init.disc = &LC_disc; 1878 ip->LC_COLL_init.nofree = 1; 1879 ip->LC_MSG_init.disc = &LC_disc; 1880 ip->LC_MSG_init.nofree = 1; 1881 ip->LC_ALL_init.disc = &LC_disc; 1882 ip->LC_ALL_init.nofree = 1; 1883 ip->LANG_init.disc = &LC_disc; 1884 ip->LANG_init.nofree = 1; 1885 #endif /* _hdr_locale */ 1886 nv_stack(IFSNOD, &ip->IFS_init.hdr); 1887 ip->IFS_init.hdr.nofree = 1; 1888 nv_stack(PATHNOD, &ip->PATH_init); 1889 nv_stack(FPATHNOD, &ip->FPATH_init); 1890 nv_stack(CDPNOD, &ip->CDPATH_init); 1891 nv_stack(SHELLNOD, &ip->SHELL_init); 1892 nv_stack(ENVNOD, &ip->ENV_init); 1893 nv_stack(VISINOD, &ip->VISUAL_init); 1894 nv_stack(EDITNOD, &ip->EDITOR_init); 1895 nv_stack(HISTFILE, &ip->HISTFILE_init); 1896 nv_stack(HISTSIZE, &ip->HISTSIZE_init); 1897 nv_stack(OPTINDNOD, &ip->OPTINDEX_init); 1898 nv_stack(SECONDS, &ip->SECONDS_init.hdr); 1899 nv_stack(L_ARGNOD, &ip->L_ARG_init); 1900 nv_putval(SECONDS, (char*)&d, NV_DOUBLE); 1901 nv_stack(RANDNOD, &ip->RAND_init.hdr); 1902 d = (shp->gd->pid&RANDMASK); 1903 nv_putval(RANDNOD, (char*)&d, NV_DOUBLE); 1904 nv_stack(LINENO, &ip->LINENO_init); 1905 SH_MATCHNOD->nvfun = &ip->SH_MATCH_init.hdr; 1906 nv_putsub(SH_MATCHNOD,(char*)0,10); 1907 nv_stack(SH_MATHNOD, &ip->SH_MATH_init); 1908 nv_stack(SH_VERSIONNOD, &ip->SH_VERSION_init); 1909 #ifdef _hdr_locale 1910 nv_stack(LCTYPENOD, &ip->LC_TYPE_init); 1911 nv_stack(LCALLNOD, &ip->LC_ALL_init); 1912 nv_stack(LCMSGNOD, &ip->LC_MSG_init); 1913 nv_stack(LCCOLLNOD, &ip->LC_COLL_init); 1914 nv_stack(LCNUMNOD, &ip->LC_NUM_init); 1915 nv_stack(LANGNOD, &ip->LANG_init); 1916 #endif /* _hdr_locale */ 1917 (PPIDNOD)->nvalue.lp = (&shp->gd->ppid); 1918 (TMOUTNOD)->nvalue.lp = (&shp->st.tmout); 1919 (MCHKNOD)->nvalue.lp = (&sh_mailchk); 1920 (OPTINDNOD)->nvalue.lp = (&shp->st.optindex); 1921 /* set up the seconds clock */ 1922 shp->alias_tree = inittree(shp,shtab_aliases); 1923 shp->track_tree = dtopen(&_Nvdisc,Dtset); 1924 shp->bltin_tree = inittree(shp,(const struct shtable2*)shtab_builtins); 1925 shp->fun_tree = dtopen(&_Nvdisc,Dtoset); 1926 dtview(shp->fun_tree,shp->bltin_tree); 1927 nv_mount(DOTSHNOD, "type", shp->typedict=dtopen(&_Nvdisc,Dtoset)); 1928 nv_adddisc(DOTSHNOD, shdiscnames, (Namval_t**)0); 1929 DOTSHNOD->nvalue.cp = Empty; 1930 nv_onattr(DOTSHNOD,NV_RDONLY); 1931 SH_LINENO->nvalue.ip = &shp->st.lineno; 1932 VERSIONNOD->nvalue.nrp = newof(0,struct Namref,1,0); 1933 VERSIONNOD->nvalue.nrp->np = SH_VERSIONNOD; 1934 VERSIONNOD->nvalue.nrp->root = nv_dict(DOTSHNOD); 1935 VERSIONNOD->nvalue.nrp->table = DOTSHNOD; 1936 nv_onattr(VERSIONNOD,NV_REF); 1937 math_init(shp); 1938 if(!shgd->stats) 1939 stat_init(shp); 1940 return(ip); 1941 } 1942 1943 /* 1944 * initialize name-value pairs 1945 */ 1946 1947 static Dt_t *inittree(Shell_t *shp,const struct shtable2 *name_vals) 1948 { 1949 register Namval_t *np; 1950 register const struct shtable2 *tp; 1951 register unsigned n = 0; 1952 register Dt_t *treep; 1953 Dt_t *base_treep, *dict; 1954 for(tp=name_vals;*tp->sh_name;tp++) 1955 n++; 1956 np = (Namval_t*)calloc(n,sizeof(Namval_t)); 1957 if(!shgd->bltin_nodes) 1958 { 1959 shgd->bltin_nodes = np; 1960 shgd->bltin_nnodes = n; 1961 } 1962 else if(name_vals==(const struct shtable2*)shtab_builtins) 1963 { 1964 shgd->bltin_cmds = np; 1965 nbltins = n; 1966 } 1967 base_treep = treep = dtopen(&_Nvdisc,Dtoset); 1968 treep->user = (void*)shp; 1969 for(tp=name_vals;*tp->sh_name;tp++,np++) 1970 { 1971 if((np->nvname = strrchr(tp->sh_name,'.')) && np->nvname!=((char*)tp->sh_name)) 1972 np->nvname++; 1973 else 1974 { 1975 np->nvname = (char*)tp->sh_name; 1976 treep = base_treep; 1977 } 1978 np->nvenv = 0; 1979 if(name_vals==(const struct shtable2*)shtab_builtins) 1980 np->nvalue.bfp = (Nambfp_f)((struct shtable3*)tp)->sh_value; 1981 else 1982 { 1983 if(name_vals == shtab_variables) 1984 np->nvfun = &shp->nvfun; 1985 np->nvalue.cp = (char*)tp->sh_value; 1986 } 1987 nv_setattr(np,tp->sh_number); 1988 if(nv_isattr(np,NV_TABLE)) 1989 nv_mount(np,(const char*)0,dict=dtopen(&_Nvdisc,Dtoset)); 1990 if(nv_isattr(np,NV_INTEGER)) 1991 nv_setsize(np,10); 1992 else 1993 nv_setsize(np,0); 1994 dtinsert(treep,np); 1995 if(nv_istable(np)) 1996 treep = dict; 1997 } 1998 return(treep); 1999 } 2000 2001 /* 2002 * read in the process environment and set up name-value pairs 2003 * skip over items that are not name-value pairs 2004 */ 2005 2006 static void env_init(Shell_t *shp) 2007 { 2008 register char *cp; 2009 register Namval_t *np,*mp; 2010 register char **ep=environ; 2011 char *dp,*next=0; 2012 int nenv=0,k=0,size=0; 2013 Namval_t *np0; 2014 #ifdef _ENV_H 2015 shp->env = env_open(environ,3); 2016 env_delete(shp->env,"_"); 2017 #endif 2018 if(!ep) 2019 goto skip; 2020 while(*ep++) 2021 nenv++; 2022 np = newof(0,Namval_t,nenv,0); 2023 for(np0=np,ep=environ;cp= *ep; ep++) 2024 { 2025 dp = strchr(cp,'='); 2026 if(!dp) 2027 continue; 2028 *dp++ = 0; 2029 if(mp = dtmatch(shp->var_base,cp)) 2030 { 2031 if(strcmp(cp,VERSIONNOD->nvname)==0) 2032 { 2033 dp[-1] = '='; 2034 continue; 2035 } 2036 mp->nvenv = (char*)cp; 2037 dp[-1] = '='; 2038 } 2039 else if(*cp=='A' && cp[1]=='_' && cp[2]=='_' && cp[3]=='z' && cp[4]==0) 2040 { 2041 dp[-1] = '='; 2042 next = cp+4; 2043 continue; 2044 } 2045 else 2046 { 2047 k++; 2048 mp = np++; 2049 mp->nvname = cp; 2050 size += strlen(cp); 2051 } 2052 nv_onattr(mp,NV_IMPORT); 2053 if(mp->nvfun || nv_isattr(mp,NV_INTEGER)) 2054 nv_putval(mp,dp,0); 2055 else 2056 { 2057 mp->nvalue.cp = dp; 2058 nv_onattr(mp,NV_NOFREE); 2059 } 2060 nv_onattr(mp,NV_EXPORT|NV_IMPORT); 2061 } 2062 np = (Namval_t*)realloc((void*)np0,k*sizeof(Namval_t)); 2063 dp = (char*)malloc(size+k); 2064 while(k-->0) 2065 { 2066 size = strlen(np->nvname); 2067 memcpy(dp,np->nvname,size+1); 2068 np->nvname[size] = '='; 2069 np->nvenv = np->nvname; 2070 np->nvname = dp; 2071 dp += size+1; 2072 dtinsert(shp->var_base,np++); 2073 } 2074 while(cp=next) 2075 { 2076 if(next = strchr(++cp,'=')) 2077 *next = 0; 2078 np = nv_search(cp+2,shp->var_tree,NV_ADD); 2079 if(np!=SHLVL && nv_isattr(np,NV_IMPORT|NV_EXPORT)) 2080 { 2081 int flag = *(unsigned char*)cp-' '; 2082 int size = *(unsigned char*)(cp+1)-' '; 2083 if((flag&NV_INTEGER) && size==0) 2084 { 2085 /* check for floating*/ 2086 char *val = nv_getval(np); 2087 strtol(val,&dp,10); 2088 if(*dp=='.' || *dp=='e' || *dp=='E') 2089 { 2090 char *lp; 2091 flag |= NV_DOUBLE; 2092 if(*dp=='.') 2093 { 2094 strtol(dp+1,&lp,10); 2095 if(*lp) 2096 dp = lp; 2097 } 2098 if(*dp && *dp!='.') 2099 { 2100 flag |= NV_EXPNOTE; 2101 size = dp-val; 2102 } 2103 else 2104 size = strlen(dp); 2105 size--; 2106 } 2107 } 2108 nv_newattr(np,flag|NV_IMPORT|NV_EXPORT,size); 2109 if((flag&(NV_INTEGER|NV_UTOL|NV_LTOU))==(NV_UTOL|NV_LTOU)) 2110 nv_mapchar(np,(flag&NV_UTOL)?e_tolower:e_toupper); 2111 } 2112 else 2113 cp += 2; 2114 } 2115 skip: 2116 #ifdef _ENV_H 2117 env_delete(shp->env,e_envmarker); 2118 #endif 2119 if(nv_isnull(PWDNOD) || nv_isattr(PWDNOD,NV_TAGGED)) 2120 { 2121 nv_offattr(PWDNOD,NV_TAGGED); 2122 path_pwd(shp,0); 2123 } 2124 if((cp = nv_getval(SHELLNOD)) && (sh_type(cp)&SH_TYPE_RESTRICTED)) 2125 sh_onoption(SH_RESTRICTED); /* restricted shell */ 2126 return; 2127 } 2128 2129 /* 2130 * terminate shell and free up the space 2131 */ 2132 int sh_term(void) 2133 { 2134 sfdisc(sfstdin,SF_POPDISC); 2135 free((char*)sh.outbuff); 2136 stakset(NIL(char*),0); 2137 return(0); 2138 } 2139 2140 /* function versions of these */ 2141 2142 #define DISABLE /* proto workaround */ 2143 2144 unsigned long sh_isoption DISABLE (int opt) 2145 { 2146 return(sh_isoption(opt)); 2147 } 2148 2149 unsigned long sh_onoption DISABLE (int opt) 2150 { 2151 return(sh_onoption(opt)); 2152 } 2153 2154 unsigned long sh_offoption DISABLE (int opt) 2155 { 2156 return(sh_offoption(opt)); 2157 } 2158 2159 void sh_sigcheck DISABLE (Shell_t *shp) 2160 { 2161 if(!shp) 2162 shp = sh_getinterp(); 2163 sh_sigcheck(shp); 2164 } 2165 2166 Dt_t* sh_bltin_tree DISABLE (void) 2167 { 2168 return(sh.bltin_tree); 2169 } 2170 2171 /* 2172 * This code is for character mapped variables with wctrans() 2173 */ 2174 struct Mapchar 2175 { 2176 Namfun_t hdr; 2177 const char *name; 2178 wctrans_t trans; 2179 int lctype; 2180 }; 2181 2182 static void put_trans(register Namval_t* np,const char *val,int flags,Namfun_t *fp) 2183 { 2184 struct Mapchar *mp = (struct Mapchar*)fp; 2185 int c,offset = staktell(),off=offset; 2186 if(val) 2187 { 2188 if(mp->lctype!=lctype) 2189 { 2190 mp->lctype = lctype; 2191 mp->trans = wctrans(mp->name); 2192 } 2193 if(!mp->trans || (flags&NV_INTEGER)) 2194 goto skip; 2195 while(c = mbchar(val)) 2196 { 2197 c = towctrans(c,mp->trans); 2198 stakseek(off+c); 2199 stakseek(off); 2200 c = mbconv(stakptr(off),c); 2201 off += c; 2202 stakseek(off); 2203 } 2204 stakputc(0); 2205 val = stakptr(offset); 2206 } 2207 else 2208 { 2209 nv_putv(np,val,flags,fp); 2210 nv_disc(np,fp,NV_POP); 2211 if(!(fp->nofree&1)) 2212 free((void*)fp); 2213 stakseek(offset); 2214 return; 2215 } 2216 skip: 2217 nv_putv(np,val,flags,fp); 2218 stakseek(offset); 2219 } 2220 2221 static const Namdisc_t TRANS_disc = { sizeof(struct Mapchar), put_trans }; 2222 2223 Namfun_t *nv_mapchar(Namval_t *np,const char *name) 2224 { 2225 wctrans_t trans = name?wctrans(name):0; 2226 struct Mapchar *mp=0; 2227 int n=0,low; 2228 if(np) 2229 mp = (struct Mapchar*)nv_hasdisc(np,&TRANS_disc); 2230 if(!name) 2231 return(mp?(Namfun_t*)mp->name:0); 2232 if(!trans) 2233 return(0); 2234 if(!np) 2235 return(((Namfun_t*)0)+1); 2236 if((low=strcmp(name,e_tolower)) && strcmp(name,e_toupper)) 2237 n += strlen(name)+1; 2238 if(mp) 2239 { 2240 if(strcmp(name,mp->name)==0) 2241 return(&mp->hdr); 2242 nv_disc(np,&mp->hdr,NV_POP); 2243 if(!(mp->hdr.nofree&1)) 2244 free((void*)mp); 2245 } 2246 mp = newof(0,struct Mapchar,1,n); 2247 mp->trans = trans; 2248 mp->lctype = lctype; 2249 if(low==0) 2250 mp->name = e_tolower; 2251 else if(n==0) 2252 mp->name = e_toupper; 2253 else 2254 { 2255 mp->name = (char*)(mp+1); 2256 strcpy((char*)mp->name,name); 2257 } 2258 mp->hdr.disc = &TRANS_disc; 2259 return(&mp->hdr); 2260 } 2261