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