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