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