1 /***********************************************************************
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 *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * David Korn <dgk@research.att.com> *
19 ***********************************************************************/
23 * Shell initialization
35 #include "variables.h"
44 #include "FEATURE/time"
45 #include "FEATURE/dynamic"
46 #include "FEATURE/externs"
47 #include "lexstates.h"
50 char e_version
[] = "\n@(#)$Id: Version "
71 #if SHOPT_PFSH && _hdr_exec_attr
85 extern void bash_init(Shell_t
*,int);
88 #define RANDMASK 0x7fff
91 # define ARG_MAX (1*1024*1024)
94 # define CHILD_MAX (1*1024)
101 extern char **environ
;
105 #define getconf(x) strtol(astconf(x,NiL,NiL),NiL,0)
133 int match
[2*(MATCH_MAX
+1)];
136 typedef struct _init_
141 #endif /* SHOPT_FS_3D */
145 Namfun_t CDPATH_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
;
157 Namfun_t SH_VERSION_init
;
158 struct match SH_MATCH_init
;
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
;
166 #endif /* _hdr_locale */
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
*);
176 # define EXE "?(.exe)"
181 static int rand_shift
;
185 * Invalidate all path name bindings
187 static void rehash(register Namval_t
*np
,void *data
)
190 nv_onattr(np
,NV_NOALIAS
);
194 * out of memory routine for stak routines
196 static char *nospace(int unused
)
199 errormsg(SH_DICT
,ERROR_exit(3),e_nospace
);
203 /* Trap for VISUAL and EDITOR variables */
204 static void put_ed(register Namval_t
* np
,const char *val
,int flags
,Namfun_t
*fp
)
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
)))
211 if(!(cp
=val
) && (*name
=='E' || !(cp
=nv_getval(sh_scoped(shp
,EDITNOD
)))))
213 /* turn on vi or emacs option if editor name is either*/
214 cp
= path_basename(cp
);
215 if(strmatch(cp
,"*[Vv][Ii]*"))
217 else if(strmatch(cp
,"*gmacs*"))
219 else if(strmatch(cp
,"*macs*"))
224 sh_offoption(SH_EMACS
);
225 sh_offoption(SH_GMACS
);
229 nv_putv(np
, val
, flags
, fp
);
232 /* Trap for HISTFILE and HISTSIZE variables */
233 static void put_history(register Namval_t
* np
,const char *val
,int flags
,Namfun_t
*fp
)
235 Shell_t
*shp
= nv_shell(np
);
236 void *histopen
= shp
->hist_ptr
;
240 if(np
==HISTFILE
&& (cp
=nv_getval(np
)) && strcmp(val
,cp
)==0)
242 if(np
==HISTSIZE
&& sh_arith(val
)==nv_getnum(HISTSIZE
))
244 hist_close(shp
->hist_ptr
);
246 nv_putv(np
, val
, flags
, fp
);
252 hist_close(histopen
);
256 /* Trap for OPTINDEX */
257 static void put_optindex(Namval_t
* np
,const char *val
,int flags
,Namfun_t
*fp
)
259 Shell_t
*shp
= nv_shell(np
);
260 shp
->st
.opterror
= shp
->st
.optchar
= 0;
261 nv_putv(np
, val
, flags
, fp
);
263 nv_disc(np
,fp
,NV_POP
);
266 static Sfdouble_t
nget_optindex(register Namval_t
* np
, Namfun_t
*fp
)
268 return((Sfdouble_t
)*np
->nvalue
.lp
);
271 static Namfun_t
*clone_optindex(Namval_t
* np
, Namval_t
*mp
, int flags
, Namfun_t
*fp
)
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
;
281 /* Trap for restricted variables FPATH, PATH, SHELL, ENV */
282 static void put_restricted(register Namval_t
* np
,const char *val
,int flags
,Namfun_t
*fp
)
284 Shell_t
*shp
= nv_shell(np
);
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)))
292 nv_scan(shp
->track_tree
,rehash
,(void*)0,NV_TAGGED
,NV_TAGGED
);
293 if(path_scoped
&& !val
)
294 val
= PATHNOD
->nvalue
.cp
;
296 if(val
&& !(flags
&NV_RDONLY
) && np
->nvalue
.cp
&& strcmp(val
,np
->nvalue
.cp
)==0)
299 shp
->pathlist
= (void*)path_unsetfpath((Pathcomp_t
*)shp
->pathlist
);
300 nv_putv(np
, val
, flags
, fp
);
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
);
311 if(shp
->pathlist
= (void*)pp
)
313 if(!val
&& (flags
&NV_NOSCOPE
))
315 Namval_t
*mp
= dtsearch(shp
->var_tree
,np
);
316 if(mp
&& (val
=nv_getval(mp
)))
317 nv_putval(mp
,val
,NV_RDONLY
);
320 sfprintf(sfstderr
,"%d: name=%s val=%s\n",getpid(),name
,val
);
321 path_dump((Pathcomp_t
*)shp
->pathlist
);
326 static void put_cdpath(register Namval_t
* np
,const char *val
,int flags
,Namfun_t
*fp
)
329 Shell_t
*shp
= nv_shell(np
);
330 nv_putv(np
, val
, flags
, fp
);
334 pp
= (void*)path_addpath((Pathcomp_t
*)shp
->cdpathlist
,val
,PATH_CDPATH
);
335 if(shp
->cdpathlist
= (void*)pp
)
341 * This function needs to be modified to handle international
342 * error message translations
344 #if ERROR_VERSION >= 20000101L
345 static char* msg_translate(const char* catalog
, const char* message
)
348 return((char*)message
);
351 static char* msg_translate(const char* message
, int type
)
354 return((char*)message
);
358 /* Trap for LC_ALL, LC_CTYPE, LC_MESSAGES, LC_COLLATE and LANG */
359 static void put_lang(Namval_t
* np
,const char *val
,int flags
,Namfun_t
*fp
)
361 Shell_t
*shp
= nv_shell(np
);
364 char *name
= nv_name(np
);
365 if(name
==(LCALLNOD
)->nvname
)
367 else if(name
==(LCTYPENOD
)->nvname
)
369 else if(name
==(LCMSGNOD
)->nvname
)
371 else if(name
==(LCCOLLNOD
)->nvname
)
373 else if(name
==(LCNUMNOD
)->nvname
)
376 else if(name
==(LANGNOD
)->nvname
)
379 #define LC_LANG LC_ALL
380 else if(name
==(LANGNOD
)->nvname
&& (!(cp
=nv_getval(LCALLNOD
)) || !*cp
))
385 if(!sh_isstate(SH_INIT
) && (type
>=0 || type
==LC_ALL
|| type
==LC_LANG
))
390 ast
.locale
.set
|= AST_LC_setenv
;
392 r
= setlocale(type
,val
?val
:"");
394 ast
.locale
.set
^= AST_LC_setenv
;
398 if(!sh_isstate(SH_INIT
) || shp
->login_sh
==0)
399 errormsg(SH_DICT
,0,e_badlocale
,val
);
402 shp
->decomma
= (lc
=localeconv()) && lc
->decimal_point
&& *lc
->decimal_point
==',';
404 nv_putv(np
, val
, flags
, fp
);
405 if(CC_NATIVE
!=CC_ASCII
&& (type
==LC_ALL
|| type
==LC_LANG
|| type
==LC_CTYPE
))
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
))
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
++)
423 if(state
[0][c
]!=S_REG
)
425 if(state
[2][c
]!=S_ERR
)
437 if(state
[1][c
]==S_REG
)
440 if(state
[3][c
]==S_ERR
)
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
];
452 #if ERROR_VERSION < 20000101L
453 if(type
==LC_ALL
|| type
==LC_MESSAGES
)
454 error_info
.translate
= msg_translate
;
457 #endif /* _hdr_locale */
459 /* Trap for IFS assignment and invalidates state table */
460 static void put_ifs(register Namval_t
* np
,const char *val
,int flags
,Namfun_t
*fp
)
462 register struct ifs
*ip
= (struct ifs
*)fp
;
467 fp
= nv_stack(np
, NIL(Namfun_t
*));
468 if(fp
&& !fp
->nofree
)
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
);
478 * This is the lookup function for IFS
479 * It keeps the sh.ifstable up to date
481 static char* get_ifs(register Namval_t
* np
, Namfun_t
*fp
)
483 register struct ifs
*ip
= (struct ifs
*)fp
;
484 register char *cp
, *value
;
486 register Shell_t
*shp
= nv_shell(np
);
487 value
= nv_getv(np
,fp
);
491 memset(shp
->ifstable
,0,(1<<CHAR_BIT
));
495 while(n
=mbsize(cp
),c
= *(unsigned char*)cp
)
497 while(c
= *(unsigned char*)cp
++)
498 #endif /* SHOPT_MULTIBYTE */
505 shp
->ifstable
[c
] = S_MBYTE
;
508 #endif /* SHOPT_MULTIBYTE */
516 shp
->ifstable
[c
] = n
;
521 shp
->ifstable
[' '] = shp
->ifstable
['\t'] = S_SPACE
;
522 shp
->ifstable
['\n'] = S_NL
;
529 * these functions are used to get and set the SECONDS variable
532 # define dtime(tp) ((double)((tp)->tv_sec)+1e-6*((double)((tp)->tv_usec)))
535 # define dtime(tp) (((double)times(tp))/sh.lim.clk_tck)
536 # define timeofday(a)
539 static void put_seconds(register Namval_t
* np
,const char *val
,int flags
,Namfun_t
*fp
)
545 fp
= nv_stack(np
, NIL(Namfun_t
*));
546 if(fp
&& !fp
->nofree
)
548 nv_putv(np
, val
, flags
, fp
);
554 nv_onattr(np
,NV_DOUBLE
);
555 np
->nvalue
.dp
= new_of(double,0);
557 nv_putv(np
, val
, flags
, fp
);
560 *np
->nvalue
.dp
= dtime(&tp
)-d
;
563 static char* get_seconds(register Namval_t
* np
, Namfun_t
*fp
)
565 Shell_t
*shp
= nv_shell(np
);
566 register int places
= nv_size(np
);
568 double d
, offset
= (np
->nvalue
.dp
?*np
->nvalue
.dp
:0);
571 d
= dtime(&tp
)- offset
;
572 sfprintf(shp
->strbuf
,"%.*f",places
,d
);
573 return(sfstruse(shp
->strbuf
));
576 static Sfdouble_t
nget_seconds(register Namval_t
* np
, Namfun_t
*fp
)
579 double offset
= (np
->nvalue
.dp
?*np
->nvalue
.dp
:0);
582 return(dtime(&tp
)- offset
);
586 * These three functions are used to get and set the RANDOM variable
588 static void put_rand(register Namval_t
* np
,const char *val
,int flags
,Namfun_t
*fp
)
590 struct rand
*rp
= (struct rand
*)fp
;
594 fp
= nv_stack(np
, NIL(Namfun_t
*));
595 if(fp
&& !fp
->nofree
)
604 srand((int)(n
&RANDMASK
));
607 np
->nvalue
.lp
= &rp
->rand_last
;
611 * get random number in range of 0 - 2**15
612 * never pick same number twice in a row
614 static Sfdouble_t
nget_rand(register Namval_t
* np
, Namfun_t
*fp
)
616 register long cur
, last
= *np
->nvalue
.lp
;
619 cur
= (rand()>>rand_shift
)&RANDMASK
;
621 *np
->nvalue
.lp
= cur
;
622 return((Sfdouble_t
)cur
);
625 static char* get_rand(register Namval_t
* np
, Namfun_t
*fp
)
627 register long n
= nget_rand(np
,fp
);
628 return(fmtbase(n
, 10, 0));
632 * These three routines are for LINENO
634 static Sfdouble_t
nget_lineno(Namval_t
* np
, Namfun_t
*fp
)
637 if(error_info
.line
>0)
639 else if(error_info
.context
&& error_info
.context
->line
>0)
640 d
= error_info
.context
->line
;
646 static void put_lineno(Namval_t
* np
,const char *val
,int flags
,Namfun_t
*fp
)
649 Shell_t
*shp
= nv_shell(np
);
652 fp
= nv_stack(np
, NIL(Namfun_t
*));
653 if(fp
&& !fp
->nofree
)
662 shp
->st
.firstline
+= nget_lineno(np
,fp
)+1-n
;
665 static char* get_lineno(register Namval_t
* np
, Namfun_t
*fp
)
667 register long n
= nget_lineno(np
,fp
);
668 return(fmtbase(n
, 10, 0));
671 static char* get_lastarg(Namval_t
* np
, Namfun_t
*fp
)
673 Shell_t
*shp
= nv_shell(np
);
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
);
681 static void put_lastarg(Namval_t
* np
,const char *val
,int flags
,Namfun_t
*fp
)
683 Shell_t
*shp
= nv_shell(np
);
686 sfprintf(shp
->strbuf
,"%.*g",12,*((double*)val
));
687 val
= sfstruse(shp
->strbuf
);
691 if(shp
->lastarg
&& !nv_isattr(np
,NV_NOFREE
))
692 free((void*)shp
->lastarg
);
694 nv_offattr(np
,NV_NOFREE
);
695 shp
->lastarg
= (char*)val
;
696 nv_offattr(np
,NV_EXPORT
);
700 static int hasgetdisc(register Namfun_t
*fp
)
702 while(fp
&& !fp
->disc
->getnum
&& !fp
->disc
->getval
)
708 * store the most recent value for use in .sh.match
710 void sh_setmatch(const char *v
, int vsize
, int nmatch
, int match
[])
712 struct match
*mp
= (struct match
*)(SH_MATCHNOD
->nvfun
);
714 if(mp
->nmatch
= nmatch
)
716 memcpy(mp
->match
,match
,nmatch
*2*sizeof(match
[0]));
717 for(n
=match
[0],i
=1; i
< 2*nmatch
; i
++)
722 for(vsize
=0,i
=0; i
< 2*nmatch
; i
++)
724 if((mp
->match
[i
] -= n
) > vsize
)
725 vsize
= mp
->match
[i
];
728 if(vsize
>= mp
->vsize
)
731 mp
->val
= (char*)realloc(mp
->val
,vsize
+1);
733 mp
->val
= (char*)malloc(vsize
+1);
736 memcpy(mp
->val
,v
,vsize
);
738 nv_putsub(SH_MATCHNOD
, NIL(char*), (nmatch
-1)|ARRAY_FILL
);
743 #define array_scan(np) ((nv_arrayptr(np)->nelem&ARRAY_SCAN))
745 static char* get_match(register Namval_t
* np
, Namfun_t
*fp
)
747 struct match
*mp
= (struct match
*)fp
;
757 free((void*)mp
->rval
);
760 n
= mp
->match
[2*sub
+1]-mp
->match
[2*sub
];
763 val
= mp
->val
+mp
->match
[2*sub
];
764 if(mp
->val
[mp
->match
[2*sub
+1]]==0)
766 mp
->rval
= (char*)malloc(n
+1);
768 memcpy(mp
->rval
,val
,n
);
773 static const Namdisc_t SH_MATCH_disc
= { sizeof(struct match
), 0, get_match
};
775 static char* get_version(register Namval_t
* np
, Namfun_t
*fp
)
777 return(nv_getv(np
,fp
));
780 static Sfdouble_t
nget_version(register Namval_t
* np
, Namfun_t
*fp
)
782 register const char *cp
= e_version
+ strlen(e_version
)-10;
788 if (c
>= '0' && c
<= '9')
793 return((Sfdouble_t
)t
);
796 static const Namdisc_t SH_VERSION_disc
= { 0, 0, get_version
, nget_version
};
800 * set or unset the mappings given a colon separated list of directories
802 static void vpath_set(char *str
, int mode
)
804 register char *lastp
, *oldp
=str
, *newp
=strchr(oldp
,':');
810 if(lastp
=strchr(newp
,':'))
812 mount((mode
?newp
:""),oldp
,FS3D_VIEW
,0);
819 /* catch vpath assignments */
820 static void put_vpath(register Namval_t
* np
,const char *val
,int flags
,Namfun_t
*fp
)
823 if(cp
= nv_getval(np
))
826 vpath_set((char*)val
,1);
827 nv_putv(np
,val
,flags
,fp
);
829 static const Namdisc_t VPATH_disc
= { 0, put_vpath
};
830 static Namfun_t VPATH_init
= { &VPATH_disc
, 1 };
831 #endif /* SHOPT_FS_3D */
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
};
846 static char* get_nspace(Namval_t
* np
, Namfun_t
*fp
)
849 return(nv_name(sh
.namespace));
850 return((char*)np
->nvalue
.cp
);
852 static const Namdisc_t NSPACE_disc
= { 0, 0, get_nspace
};
853 static Namfun_t NSPACE_init
= { &NSPACE_disc
, 1};
854 #endif /* SHOPT_NAMESPACE */
857 static const Namdisc_t LC_disc
= { sizeof(Namfun_t
), put_lang
};
858 #endif /* _hdr_locale */
861 * This function will get called whenever a configuration parameter changes
863 static int newconf(const char *name
, const char *path
, const char *value
)
868 else if(strcmp(name
,"UNIVERSE")==0 && strcmp(astconf(name
,0,0),value
))
871 /* set directory in new universe */
872 if(*(arg
= path_pwd(0))=='/')
874 /* clear out old tracked alias */
876 stakputs(nv_getval(PATHNOD
));
878 nv_putval(PATHNOD
,stakseek(0),NV_RDONLY
);
883 #if (CC_NATIVE != CC_ASCII)
884 static void a2e(char *d
, const char *s
)
886 register const unsigned char *t
;
888 t
= CCMAP(CC_ASCII
, CC_NATIVE
);
889 for(i
=0; i
<(1<<CHAR_BIT
); i
++)
893 static void init_ebcdic(void)
896 char *cp
= (char*)malloc(ST_NONE
*(1<<CHAR_BIT
));
897 for(i
=0; i
< ST_NONE
; i
++)
899 a2e(cp
,sh_lexrstates
[i
]);
900 sh_lexstates
[i
] = cp
;
907 * return SH_TYPE_* bitmask for path
908 * 0 for "not a shell"
910 int sh_type(register const char *path
)
912 register const char* s
;
915 if (s
= (const char*)strrchr(path
, '/'))
930 if (!(t
& (SH_TYPE_KSH
|SH_TYPE_BASH
)))
939 if (*s
== 'b' && *(s
+1) == 'a')
947 if (!(t
& (SH_TYPE_PROFILE
|SH_TYPE_RESTRICTED
)))
950 if (*s
== 'p' && *(s
+1) == 'f')
953 t
|= SH_TYPE_PROFILE
;
960 t
|= SH_TYPE_RESTRICTED
;
966 if (*s
++ == 's' && (*s
== 'h' || *s
== 'u'))
970 if ((t
& SH_TYPE_KSH
) && *s
== '9' && *(s
+1) == '3')
973 if (*s
== '.' && *(s
+1) == 'e' && *(s
+2) == 'x' && *(s
+3) == 'e')
979 return t
& ~(SH_TYPE_BASH
|SH_TYPE_KSH
|SH_TYPE_PROFILE
|SH_TYPE_RESTRICTED
);
983 static char *get_mode(Namval_t
* np
, Namfun_t
* nfp
)
985 mode_t mode
= nv_getn(np
,nfp
);
986 return(fmtperm(mode
));
989 static void put_mode(Namval_t
* np
, const char* val
, int flag
, Namfun_t
* nfp
)
998 mode
= *(Sfdouble_t
*)val
;
1000 mode
= *(double*)val
;
1003 mode
= strperm(val
, &last
,0);
1005 errormsg(SH_DICT
,ERROR_exit(1),"%s: invalid mode string",val
);
1006 nv_putv(np
,(char*)&mode
,NV_INTEGER
,nfp
);
1009 nv_putv(np
,val
,flag
,nfp
);
1012 static const Namdisc_t modedisc
=
1021 * initialize the shell
1023 Shell_t
*sh_init(register int argc
,register char *argv
[], Shinit_f userinit
)
1029 static char *login_files
[3];
1031 n
= strlen(e_version
);
1032 if(e_version
[n
-1]=='$' && e_version
[n
-2]==' ')
1034 #if (CC_NATIVE == CC_ASCII)
1035 memcpy(sh_lexstates
,sh_lexrstates
,ST_NONE
*sizeof(char*));
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();
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
;
1061 sh_regress_init(shp
);
1062 regress
[0] = "__regress__";
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'))
1072 else if (!(regress
[1] = *++av
))
1075 else if (strncmp(a
+2, "regress", 7))
1077 else if (a
[9] == '=')
1078 regress
[1] = a
+ 10;
1079 else if (!(regress
[1] = *++av
))
1081 nopt
= optctx(0, 0);
1082 oopt
= optctx(nopt
, 0);
1083 b___regress__(2, regress
, &shp
->bltindata
);
1090 shp
->userid
=getuid();
1091 shp
->euserid
=geteuid();
1092 shp
->groupid
=getgid();
1093 shp
->egroupid
=getegid();
1094 for(n
=0;n
< 10; n
++)
1096 /* don't use lower bits when rand() generates large numbers */
1097 if(rand() > RANDMASK
)
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
;
1125 #endif /* SHOPT_FS_3D */
1127 /* initialize signal handling */
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 */
1135 type
= sh_type(*argv
);
1136 if(type
&SH_TYPE_LOGIN
)
1140 if(!ENVNOD
->nvalue
.cp
)
1142 sfprintf(shp
->strbuf
,"%s/.kshrc",nv_getval(HOME
));
1143 nv_putval(ENVNOD
,sfstruse(shp
->strbuf
),NV_RDONLY
);
1145 *SHLVL
->nvalue
.ip
+=1;
1149 * try to find the pathname for this interpreter
1150 * try using environment variable _ or argv[0]
1152 char *cp
=nv_getval(L_ARGNOD
);
1153 char buff
[PATH_MAX
+1];
1155 #if _AST_VERSION >= 20090202L
1156 if((n
= pathprog(NiL
, buff
, sizeof(buff
))) > 0 && n
<= sizeof(buff
))
1157 shp
->shpath
= strdup(buff
);
1159 sfprintf(shp
->strbuf
,"/proc/%d/exe",getpid());
1160 if((n
=readlink(sfstruse(shp
->strbuf
),buff
,sizeof(buff
)-1))>0)
1163 shp
->shpath
= strdup(buff
);
1166 else if((cp
&& (sh_type(cp
)&SH_TYPE_SH
)) || (argc
>0 && strchr(cp
= *argv
,'/')))
1169 shp
->shpath
= strdup(cp
);
1170 else if(cp
= nv_getval(PWDNOD
))
1172 int offset
= staktell();
1176 pathcanon(stakptr(offset
),PATH_DOTDOT
);
1177 shp
->shpath
= strdup(stakptr(offset
));
1183 nv_putval(IFSNOD
,(char*)e_sptbnl
,NV_RDONLY
);
1185 nv_stack(VPATHNOD
, &VPATH_init
);
1186 #endif /* SHOPT_FS_3D */
1187 astconfdisc(newconf
);
1189 shp
->st
.tmout
= SHOPT_TIMEOUT
;
1190 #endif /* SHOPT_TIMEOUT */
1191 /* initialize jobs table */
1195 /* check for restricted shell */
1196 if(type
&SH_TYPE_RESTRICTED
)
1197 sh_onoption(SH_RESTRICTED
);
1199 /* check for profile shell */
1200 else if(type
&SH_TYPE_PROFILE
)
1201 sh_onoption(SH_PFSH
);
1204 /* check for invocation as bash */
1205 if(type
&SH_TYPE_BASH
)
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
);
1214 /* look for options */
1215 /* shp->st.dolc is $# */
1216 if((shp
->st
.dolc
= sh_argopts(-argc
,argv
,shp
)) < 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
))
1233 name
= shp
->st
.dolv
[0];
1234 if(name
[1]==':' && (name
[2]=='/' || name
[2]=='\\'))
1239 if((n
= pathposix(name
, NIL(char*), 0)) > 0 && (p
= (char*)malloc(++n
)))
1241 pathposix(name
, p
, n
);
1248 name
[0] = name
[2] = '/';
1256 if (sh_isoption(SH_PFSH
))
1258 struct passwd
*pw
= getpwuid(shp
->userid
);
1260 shp
->user
= strdup(pw
->pw_name
);
1264 /* set[ug]id scripts require the -p flag */
1265 if(shp
->userid
!=shp
->euserid
|| shp
->groupid
!=shp
->egroupid
)
1268 /* require sh -p to run setuid and/or setgid */
1269 if(!sh_isoption(SH_PRIVILEGED
) && shp
->userid
>= SHOPT_P_SUID
)
1271 setuid(shp
->euserid
=shp
->userid
);
1272 setgid(shp
->egroupid
=shp
->groupid
);
1275 #endif /* SHOPT_P_SUID */
1276 sh_onoption(SH_PRIVILEGED
);
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*/
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]);
1289 shp
->shname
= strdup(shp
->st
.dolv
[0]);
1291 * return here for shell script execution
1292 * but not for parenthesis subshells
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);
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);
1330 if(shp
->userinit
=userinit
)
1331 (*userinit
)(shp
, 0);
1335 Shell_t
*sh_getinterp(void)
1341 * reinitialize before executing a script
1343 int sh_reinit(char *argv
[])
1347 Namval_t
*np
,*npnext
;
1349 for(np
=dtfirst(shp
->fun_tree
);np
;np
=npnext
)
1351 if((dp
=shp
->fun_tree
)->walk
)
1353 npnext
= (Namval_t
*)dtnext(shp
->fun_tree
,np
);
1354 if(np
>= shp
->bltin_cmds
&& np
< &shp
->bltin_cmds
[nbltins
])
1356 if(is_abuiltin(np
) && nv_isattr(np
,NV_EXPORT
))
1358 if(*np
->nvname
=='/')
1360 nv_delete(np
,dp
,NV_NOFREE
);
1362 dtclose(shp
->alias_tree
);
1363 shp
->alias_tree
= inittree(shp
,shtab_aliases
);
1364 shp
->last_root
= shp
->var_tree
;
1366 shp
->inuse_bits
= 0;
1368 (*shp
->userinit
)(shp
, 1);
1371 sfclose(shp
->heredocs
);
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
);
1392 /* set up new args */
1394 shp
->arglist
= sh_argcreate(argv
);
1396 sh_argreset(shp
,shp
->arglist
,NIL(struct dolnod
*));
1399 shp
->shname
= error_info
.id
= strdup(shp
->st
.dolv
[0]);
1400 sh_offstate(SH_FORKED
);
1401 shp
->fn_depth
= shp
->dot_depth
= 0;
1403 if(!(SHLVL
->nvalue
.ip
))
1406 SHLVL
->nvalue
.ip
= &shlvl
;
1407 nv_onattr(SHLVL
,NV_INTEGER
|NV_EXPORT
|NV_NOFREE
);
1409 *SHLVL
->nvalue
.ip
+=1;
1410 shp
->st
.filename
= strdup(shp
->lastarg
);
1415 * set when creating a local variable of this name
1417 Namfun_t
*nv_cover(register Namval_t
*np
)
1419 if(np
==IFSNOD
|| np
==PATHNOD
|| np
==SHELLNOD
|| np
==FPATHNOD
|| np
==CDPNOD
|| np
==SECONDS
|| np
==ENVNOD
)
1422 if(np
==LCALLNOD
|| np
==LCTYPENOD
|| np
==LCMSGNOD
|| np
==LCCOLLNOD
|| np
==LCNUMNOD
|| np
==LANGNOD
)
1428 static const char *shdiscnames
[] = { "tilde", 0};
1440 static Namval_t
*next_stat(register Namval_t
* np
, Dt_t
*root
,Namfun_t
*fp
)
1442 struct Stats
*sp
= (struct Stats
*)fp
;
1445 else if(++sp
->current
>=sp
->numnodes
)
1447 return(nv_namptr(sp
->nodes
,sp
->current
));
1450 static Namval_t
*create_stat(Namval_t
*np
,const char *name
,int flag
,Namfun_t
*fp
)
1452 struct Stats
*sp
= (struct Stats
*)fp
;
1453 register const char *cp
=name
;
1456 Shell_t
*shp
= sp
->sh
;
1459 while((i
=*cp
++) && i
!= '=' && i
!= '+' && i
!='[');
1461 for(i
=0; i
< sp
->numnodes
; i
++)
1463 nq
= nv_namptr(sp
->nodes
,i
);
1464 if((n
==0||memcmp(name
,nq
->nvname
,n
)==0) && nq
->nvname
[n
]==0)
1471 fp
->last
= (char*)&name
[n
];
1472 shp
->last_table
= SH_STATS
;
1475 errormsg(SH_DICT
,ERROR_exit(1),e_notelem
,n
,name
,nv_name(np
));
1479 static const Namdisc_t stat_disc
=
1487 static char *name_stat(Namval_t
*np
, Namfun_t
*fp
)
1489 Shell_t
*shp
= sh_getinterp();
1490 sfprintf(shp
->strbuf
,".sh.stats.%s",np
->nvname
);
1491 return(sfstruse(shp
->strbuf
));
1494 static const Namdisc_t stat_child_disc
=
1500 static Namfun_t stat_child_fun
=
1502 &stat_child_disc
, 1, 0, sizeof(Namfun_t
)
1505 static void stat_init(Shell_t
*shp
)
1507 int i
,nstat
= STAT_SUBSHELL
+1;
1508 struct Stats
*sp
= newof(0,struct Stats
,1,nstat
*NV_MINSZ
);
1510 sp
->numnodes
= nstat
;
1511 sp
->nodes
= (char*)(sp
+1);
1512 shp
->stats
= (int*)calloc(sizeof(int*),nstat
);
1514 for(i
=0; i
< nstat
; i
++)
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
);
1521 np
->nvalue
.ip
= &shp
->stats
[i
];
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
);
1527 nv_setvtree(SH_STATS
);
1530 # define stat_init(x)
1531 #endif /* SHOPT_STATS */
1534 * Initialize the shell name and alias table
1536 static Init_t
*nv_init(Shell_t
*shp
)
1539 register Init_t
*ip
;
1541 ip
= newof(0,Init_t
,1,0);
1544 shp
->nvfun
.last
= (char*)shp
;
1545 shp
->nvfun
.nofree
= 1;
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;
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
);
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
);
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
);
1657 * initialize name-value pairs
1660 static Dt_t
*inittree(Shell_t
*shp
,const struct shtable2
*name_vals
)
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
++)
1669 np
= (Namval_t
*)calloc(n
,sizeof(Namval_t
));
1670 if(!shp
->bltin_nodes
)
1672 shp
->bltin_nodes
= np
;
1673 shp
->bltin_nnodes
= n
;
1675 else if(name_vals
==(const struct shtable2
*)shtab_builtins
)
1677 shp
->bltin_cmds
= np
;
1680 base_treep
= treep
= dtopen(&_Nvdisc
,Dtoset
);
1681 treep
->user
= (void*)shp
;
1682 for(tp
=name_vals
;*tp
->sh_name
;tp
++,np
++)
1684 if((np
->nvname
= strrchr(tp
->sh_name
,'.')) && np
->nvname
!=((char*)tp
->sh_name
))
1688 np
->nvname
= (char*)tp
->sh_name
;
1692 if(name_vals
==(const struct shtable2
*)shtab_builtins
)
1693 np
->nvalue
.bfp
= ((struct shtable3
*)tp
)->sh_value
;
1696 if(name_vals
== shtab_variables
)
1697 np
->nvfun
= &sh
.nvfun
;
1698 np
->nvalue
.cp
= (char*)tp
->sh_value
;
1700 nv_setattr(np
,tp
->sh_number
);
1702 nv_mount(np
,(const char*)0,dict
=dtopen(&_Nvdisc
,Dtoset
));
1703 if(nv_isattr(np
,NV_INTEGER
))
1715 * read in the process environment and set up name-value pairs
1716 * skip over items that are not name-value pairs
1719 static void env_init(Shell_t
*shp
)
1722 register Namval_t
*np
;
1723 register char **ep
=environ
;
1724 register char *next
=0;
1726 shp
->env
= env_open(environ
,3);
1727 env_delete(shp
->env
,"_");
1733 if(*cp
=='A' && cp
[1]=='_' && cp
[2]=='_' && cp
[3]=='z' && cp
[4]=='=')
1735 else if(np
=nv_open(cp
,shp
->var_tree
,(NV_EXPORT
|NV_IDENT
|NV_ASSIGN
|NV_NOFAIL
)))
1737 nv_onattr(np
,NV_IMPORT
);
1741 else /* swap with front */
1743 ep
[-1] = environ
[shp
->nenv
];
1744 environ
[shp
->nenv
++] = cp
;
1749 if(next
= strchr(++cp
,'='))
1751 np
= nv_search(cp
+2,shp
->var_tree
,NV_ADD
);
1752 if(np
!=SHLVL
&& nv_isattr(np
,NV_IMPORT
|NV_EXPORT
))
1754 int flag
= *(unsigned char*)cp
-' ';
1755 int size
= *(unsigned char*)(cp
+1)-' ';
1756 if((flag
&NV_INTEGER
) && size
==0)
1758 /* check for floating*/
1759 char *ep
,*val
= nv_getval(np
);
1761 if(*ep
=='.' || *ep
=='e' || *ep
=='E')
1767 strtol(ep
+1,&lp
,10);
1781 nv_newattr(np
,flag
|NV_IMPORT
|NV_EXPORT
,size
);
1788 env_delete(shp
->env
,e_envmarker
);
1790 if(nv_isnull(PWDNOD
) || nv_isattr(PWDNOD
,NV_TAGGED
))
1792 nv_offattr(PWDNOD
,NV_TAGGED
);
1795 if((cp
= nv_getval(SHELLNOD
)) && (sh_type(cp
)&SH_TYPE_RESTRICTED
))
1796 sh_onoption(SH_RESTRICTED
); /* restricted shell */
1801 * terminate shell and free up the space
1805 sfdisc(sfstdin
,SF_POPDISC
);
1806 free((char*)sh
.outbuff
);
1807 stakset(NIL(char*),0);
1811 /* function versions of these */
1813 #define DISABLE /* proto workaround */
1815 unsigned long sh_isoption
DISABLE (int opt
)
1817 return(sh_isoption(opt
));
1820 unsigned long sh_onoption
DISABLE (int opt
)
1822 return(sh_onoption(opt
));
1825 unsigned long sh_offoption
DISABLE (int opt
)
1827 return(sh_offoption(opt
));
1830 void sh_sigcheck
DISABLE (void)
1835 Dt_t
* sh_bltin_tree
DISABLE (void)
1837 return(sh
.bltin_tree
);