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