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 */
rehash(register Namval_t * np,void * data)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 */
nospace(int unused)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 */
put_ed(register Namval_t * np,const char * val,int flags,Namfun_t * fp)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 */
put_history(register Namval_t * np,const char * val,int flags,Namfun_t * fp)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 */
put_optindex(Namval_t * np,const char * val,int flags,Namfun_t * fp)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
nget_optindex(register Namval_t * np,Namfun_t * fp)266 static Sfdouble_t nget_optindex(register Namval_t* np, Namfun_t *fp)
267 {
268 return((Sfdouble_t)*np->nvalue.lp);
269 }
270
clone_optindex(Namval_t * np,Namval_t * mp,int flags,Namfun_t * fp)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 */
put_restricted(register Namval_t * np,const char * val,int flags,Namfun_t * fp)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
put_cdpath(register Namval_t * np,const char * val,int flags,Namfun_t * fp)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
msg_translate(const char * catalog,const char * message)345 static char* msg_translate(const char* catalog, const char* message)
346 {
347 NOT_USED(catalog);
348 return((char*)message);
349 }
350 #else
msg_translate(const char * message,int type)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 */
put_lang(Namval_t * np,const char * val,int flags,Namfun_t * fp)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 */
put_ifs(register Namval_t * np,const char * val,int flags,Namfun_t * fp)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 */
get_ifs(register Namval_t * np,Namfun_t * fp)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
put_seconds(register Namval_t * np,const char * val,int flags,Namfun_t * fp)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
get_seconds(register Namval_t * np,Namfun_t * fp)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
nget_seconds(register Namval_t * np,Namfun_t * fp)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 */
put_rand(register Namval_t * np,const char * val,int flags,Namfun_t * fp)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 */
nget_rand(register Namval_t * np,Namfun_t * fp)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
get_rand(register Namval_t * np,Namfun_t * fp)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 */
nget_lineno(Namval_t * np,Namfun_t * fp)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
put_lineno(Namval_t * np,const char * val,int flags,Namfun_t * fp)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
get_lineno(register Namval_t * np,Namfun_t * fp)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
get_lastarg(Namval_t * np,Namfun_t * fp)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
put_lastarg(Namval_t * np,const char * val,int flags,Namfun_t * fp)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
hasgetdisc(register Namfun_t * fp)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 */
sh_setmatch(const char * v,int vsize,int nmatch,int match[])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
get_match(register Namval_t * np,Namfun_t * fp)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
get_version(register Namval_t * np,Namfun_t * fp)775 static char* get_version(register Namval_t* np, Namfun_t *fp)
776 {
777 return(nv_getv(np,fp));
778 }
779
nget_version(register Namval_t * np,Namfun_t * fp)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 */
vpath_set(char * str,int mode)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 */
put_vpath(register Namval_t * np,const char * val,int flags,Namfun_t * fp)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
get_nspace(Namval_t * np,Namfun_t * fp)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 */
newconf(const char * name,const char * path,const char * value)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)
a2e(char * d,const char * s)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
init_ebcdic(void)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 */
sh_type(register const char * path)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
get_mode(Namval_t * np,Namfun_t * nfp)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
put_mode(Namval_t * np,const char * val,int flag,Namfun_t * nfp)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 */
sh_init(register int argc,register char * argv[],Shinit_f userinit)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
sh_getinterp(void)1335 Shell_t *sh_getinterp(void)
1336 {
1337 return(&sh);
1338 }
1339
1340 /*
1341 * reinitialize before executing a script
1342 */
sh_reinit(char * argv[])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 */
nv_cover(register Namval_t * np)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
next_stat(register Namval_t * np,Dt_t * root,Namfun_t * fp)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
create_stat(Namval_t * np,const char * name,int flag,Namfun_t * fp)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
name_stat(Namval_t * np,Namfun_t * fp)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
stat_init(Shell_t * shp)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 */
nv_init(Shell_t * shp)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
inittree(Shell_t * shp,const struct shtable2 * name_vals)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
env_init(Shell_t * shp)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 */
sh_term(void)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
DISABLE(int opt)1815 unsigned long sh_isoption DISABLE (int opt)
1816 {
1817 return(sh_isoption(opt));
1818 }
1819
DISABLE(int opt)1820 unsigned long sh_onoption DISABLE (int opt)
1821 {
1822 return(sh_onoption(opt));
1823 }
1824
DISABLE(int opt)1825 unsigned long sh_offoption DISABLE (int opt)
1826 {
1827 return(sh_offoption(opt));
1828 }
1829
DISABLE(void)1830 void sh_sigcheck DISABLE (void)
1831 {
1832 sh_sigcheck();
1833 }
1834
DISABLE(void)1835 Dt_t* sh_bltin_tree DISABLE (void)
1836 {
1837 return(sh.bltin_tree);
1838 }
1839