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