1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1982-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                  David Korn <dgk@research.att.com>                   *
18*4887Schin *                                                                      *
19*4887Schin ***********************************************************************/
20*4887Schin /*
21*4887Schin  * bash specific extensions
22*4887Schin  * originally provided by Karsten Fleischer
23*4887Schin  */
24*4887Schin 
25*4887Schin #include "defs.h"
26*4887Schin #include "path.h"
27*4887Schin #include "io.h"
28*4887Schin #include "builtins.h"
29*4887Schin #include "name.h"
30*4887Schin 
31*4887Schin #ifndef BASH_MAJOR
32*4887Schin #   define BASH_MAJOR	"1"
33*4887Schin #   define BASH_MINOR	"0"
34*4887Schin #   define BASH_PATCH	"0"
35*4887Schin #   define BASH_BUILD	"0"
36*4887Schin #   define BASH_RELEASE	"experimental"
37*4887Schin #endif
38*4887Schin #define BASH_VERSION	BASH_MAJOR "." BASH_MINOR "." BASH_PATCH "(" BASH_BUILD ")-" BASH_RELEASE
39*4887Schin 
40*4887Schin 
41*4887Schin void	sh_applyopts(Shopt_t);
42*4887Schin 
43*4887Schin extern const char	bash_pre_rc[];
44*4887Schin 
45*4887Schin static char *login_files[4];
46*4887Schin 
47*4887Schin const char sh_bash1[] =
48*4887Schin 	"[B?Enable brace group expansion. This option is only availabe in bash "
49*4887Schin 	"compatibility mode. In ksh mode, brace group expansion is always on.]"
50*4887Schin 	"[P?Do not follow symbolic links, use physical directory structure "
51*4887Schin 	"instead. Only available in bash compatibility mode.]";
52*4887Schin const char sh_bash2[] =
53*4887Schin "[l:login?Make the shell act as if it had been invoked as a login shell. "
54*4887Schin "Only available if invoked as \bbash\b.]"
55*4887Schin "[O]:?[shopt_option?\ashopt_option\a is one of the shell options accepted by "
56*4887Schin 	"the \bshopt\b builtin. If \ashopt_option\a is present, \b-O\b sets "
57*4887Schin 	"the value of that option; \b+O\b unsets it. If \ashopt_option\a is "
58*4887Schin 	"not supplied, the names and values of the shell options accepted by "
59*4887Schin 	"\bshopt\b are printed on the standard output. If the invocation "
60*4887Schin 	"option is \b+O\b, the output is displayed in a format that may be "
61*4887Schin 	"reused as input. Only available if invoked as \bbash\b.]"
62*4887Schin "[01:init-file|rcfile]:[file?Execute commands from \afile\a instead of the "
63*4887Schin 	"standard personal initialization file ~/.bashrc if the shell is "
64*4887Schin 	"interactive. Only available if invoked as \bbash\b.]"
65*4887Schin "[02:editing?For option compatibility with \bbash\b only. Ignored.]"
66*4887Schin "[03:profile?Read either the system-wide startup file or any of the "
67*4887Schin 	"personal initialization files. On by default for interactive "
68*4887Schin 	"shells. Only available if invoked as \bbash\b.]"
69*4887Schin "[04:rc?Read and execute the personal initialization file "
70*4887Schin 	"\b$HOME/.bashrc\b. On by default for interactive shells. Only "
71*4887Schin 	"available if invoked as \bbash\b.]"
72*4887Schin "[05:posix?If invoked as \bbash\b, turn on POSIX compatibility. \bBash\b in "
73*4887Schin 	"POSIX mode is not the same as \bksh\b.]"
74*4887Schin "[06:version?Print version number and exit.]";
75*4887Schin 
76*4887Schin const char sh_optshopt[] =
77*4887Schin "+[-1c?\n@(#)$Id: shopt (AT&T Research) 2003-02-13 $\n]"
78*4887Schin "[-author?Karsten Fleischer <K.Fleischer@omnium.de>]"
79*4887Schin USAGE_LICENSE
80*4887Schin "[+NAME?shopt - set/unset variables controlling optional shell behavior]"
81*4887Schin "[+DESCRIPTION?\bshopt\b sets or unsets variables controlling optional shell "
82*4887Schin 	"behavior. With no options, or with the \b-p\b option, a list of all "
83*4887Schin 	"settable options is displayed, with an indication of whether or not "
84*4887Schin 	"each is set.]"
85*4887Schin "[p?Causes output to be displayed in a form that may be reused as input.]"
86*4887Schin "[s?Set each \aoptname\a.]"
87*4887Schin "[u?Unset each \aoptname\a.]"
88*4887Schin "[q?Suppress output (quiet mode). The return status indicates whether the "
89*4887Schin 	"\aoptname\a is set or unset. If multiple \aoptname\a arguments are "
90*4887Schin 	"given with \b-q\b, the return status is zero if all \aoptname\as are "
91*4887Schin 	"enabled; non-zero otherwise.]"
92*4887Schin "[o?Restricts the values of \aoptname\a to be those defined for the \b-o\b "
93*4887Schin 	"option to the set builtin.]"
94*4887Schin "[+?If either \b-s\b or \b-u\b is used with no \aoptname\a arguments, the "
95*4887Schin 	"display is limited to those options which are set or unset.]"
96*4887Schin "[+?\bshopt\b supports all bash options. Some settings do not have any effect "
97*4887Schin 	"or are are always on and cannot be changed.]"
98*4887Schin "[+?The value of \aoptname\a must be one of the following:]{"
99*4887Schin 		"[+cdable_vars?If set, arguments to the \bcd\b command are "
100*4887Schin 			"assumed to be names of variables whose values are to "
101*4887Schin 			"be used if the usual \bcd\b proceeding fails.]"
102*4887Schin 		"[+cdspell?Currently ignored.]"
103*4887Schin 		"[+checkhash?Always on.]"
104*4887Schin 		"[+checkwinsize?Currently ignored.]"
105*4887Schin 		"[+cmdhist?Always on.]"
106*4887Schin 		"[+dotglob?If set, include filenames beginning with a \b.\b "
107*4887Schin 			"in the results of pathname expansion.]"
108*4887Schin 		"[+execfail?Always on.]"
109*4887Schin 		"[+expand_aliases?Always on.]"
110*4887Schin 		"[+extglob?Enable extended pattern matching features.]"
111*4887Schin 		"[+histappend?Always on.]"
112*4887Schin 		"[+histreedit?If set and an edit mode is selected, the user "
113*4887Schin 			"is given the opportunity to re-edit a failed history "
114*4887Schin 			"substitution.]"
115*4887Schin 		"[+histverify?If set and an edit mode is selected, the result "
116*4887Schin 			"of a history substitution will not be executed "
117*4887Schin 			"immediately but be placed in the edit buffer for "
118*4887Schin 			"further modifications.]"
119*4887Schin 		"[+hostcomplete?Currently ignored.]"
120*4887Schin 		"[+huponexit?Currently ignored.]"
121*4887Schin 		"[+interactive_comments?Always on.]"
122*4887Schin 		"[+lithist?Always on.]"
123*4887Schin 		"[+login_shell?This option is set if the shell is started as "
124*4887Schin 			"a login shell. The value cannot be changed.]"
125*4887Schin 		"[+mailwarn?Currently ignored.]"
126*4887Schin 		"[+no_empty_cmd_completion?Always on.]"
127*4887Schin 		"[+nocaseglob?Match filenames in a case-insensitive fashion "
128*4887Schin 			"when performing filename expansion.]"
129*4887Schin 		"[+nullglob?Allows filename patterns which match no files to "
130*4887Schin 			"expand to a null string, rather than themselves.]"
131*4887Schin 		"[+progcomp?Currently ignored.]"
132*4887Schin 		"[+promptvars?Currently ignored.]"
133*4887Schin 		"[+restricted_shell?This option is set if the shell is started "
134*4887Schin 			"as a restricted shell. The value cannot be changed. "
135*4887Schin 			"It is not reset during execution of startup files, "
136*4887Schin 			"allowing the startup files to determine whether the "
137*4887Schin 			"shell is restricted.]"
138*4887Schin 		"[+shift_verbose?Currently ignored.]"
139*4887Schin 		"[+sourcepath?If set, the \b.\b builtin uses the value of PATH "
140*4887Schin 			"to find the directory containing the file supplied "
141*4887Schin 			"as an argument.]"
142*4887Schin 		"[+xpg_echo?If set, the \becho\b and \bprint\b builtins "
143*4887Schin 			"expand backslash-escape sequences.]"
144*4887Schin "}"
145*4887Schin "\n"
146*4887Schin "\n[optname ...]\n"
147*4887Schin "\n"
148*4887Schin "[+EXIT STATUS?]{"
149*4887Schin 	"[+?The return status when listing options is zero if all \aoptnames\a "
150*4887Schin 	"are enabled, non-zero otherwise. When setting or unsetting options, "
151*4887Schin 	"the return status is zero unless an \aoptname\a is not a valid shell "
152*4887Schin 	"option.]"
153*4887Schin "}"
154*4887Schin 
155*4887Schin "[+SEE ALSO?\bset\b(1)]"
156*4887Schin ;
157*4887Schin 
158*4887Schin /* GLOBIGNORE discipline. Turn on SH_DOTGLOB on set, turn off on unset. */
159*4887Schin 
160*4887Schin static void put_globignore(register Namval_t* np, const char *val, int flags, Namfun_t *fp)
161*4887Schin {
162*4887Schin 	if(val)
163*4887Schin 		sh_onoption(SH_DOTGLOB);
164*4887Schin 	else
165*4887Schin 		sh_offoption(SH_DOTGLOB);
166*4887Schin 
167*4887Schin 	nv_putv(np,val,flags,fp);
168*4887Schin }
169*4887Schin 
170*4887Schin const Namdisc_t SH_GLOBIGNORE_disc  = { sizeof(Namfun_t), put_globignore };
171*4887Schin 
172*4887Schin /* FUNCNAME discipline */
173*4887Schin 
174*4887Schin struct	funcname
175*4887Schin {
176*4887Schin 	Namfun_t	hdr;
177*4887Schin };
178*4887Schin 
179*4887Schin static void put_funcname(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
180*4887Schin {
181*4887Schin 	/* bash silently returns with an error when FUNCNAME is set,
182*4887Schin 	   unsetting FUNCNAME is allowed */
183*4887Schin 	if(val && !(flags&NV_RDONLY))
184*4887Schin 		error_info.exit(1);
185*4887Schin 
186*4887Schin 	nv_putv(np,val,flags,fp);
187*4887Schin }
188*4887Schin 
189*4887Schin const Namdisc_t SH_FUNCNAME_disc  = { sizeof(struct funcname), put_funcname };
190*4887Schin 
191*4887Schin #define	SET_SET		1
192*4887Schin #define	SET_UNSET	2
193*4887Schin #define	SET_NOARGS	4
194*4887Schin 
195*4887Schin /* shopt builtin */
196*4887Schin 
197*4887Schin int     b_shopt(int argc,register char *argv[],void *extra)
198*4887Schin {
199*4887Schin         Shell_t *shp = (Shell_t*)extra;
200*4887Schin 	int n, f, ret=0;
201*4887Schin 	Shopt_t newflags=shp->options, opt;
202*4887Schin 	int verbose=PRINT_SHOPT|PRINT_ALL|PRINT_NO_HEADER|PRINT_VERBOSE;
203*4887Schin 	int setflag=0, quietflag=0, oflag=0;
204*4887Schin 	memset(&opt,0,sizeof(opt));
205*4887Schin #if SHOPT_RAWONLY
206*4887Schin 	on_option(&newflags,SH_VIRAW);
207*4887Schin #endif
208*4887Schin 	while((n = optget(argv,sh_optshopt)))
209*4887Schin 	{
210*4887Schin 		switch(n)
211*4887Schin 		{
212*4887Schin 		case 'p':
213*4887Schin 			verbose&=~PRINT_VERBOSE;
214*4887Schin 			break;
215*4887Schin 		case 's':
216*4887Schin 		case 'u':
217*4887Schin 			setflag|=n=='s'?SET_SET:SET_UNSET;
218*4887Schin 			if(setflag==(SET_SET|SET_UNSET))
219*4887Schin 			{
220*4887Schin 				errormsg(SH_DICT,ERROR_ERROR,"cannot set and unset options simultaneously");
221*4887Schin 				error_info.errors++;
222*4887Schin 			}
223*4887Schin 			break;
224*4887Schin 		case 'q':
225*4887Schin 			quietflag=1;
226*4887Schin 			break;
227*4887Schin 		case 'o':
228*4887Schin 			oflag=1;
229*4887Schin 			verbose&=~PRINT_SHOPT;
230*4887Schin 			break;
231*4887Schin 		case ':':
232*4887Schin 			errormsg(SH_DICT,2, "%s", opt_info.arg);
233*4887Schin 			continue;
234*4887Schin 		case '?':
235*4887Schin 			errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
236*4887Schin 			return(-1);
237*4887Schin 		}
238*4887Schin 	}
239*4887Schin 	if(error_info.errors)
240*4887Schin 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*)));
241*4887Schin 	argc -= opt_info.index;
242*4887Schin 	if(argc==0)
243*4887Schin 	{
244*4887Schin 		/* no args, -s => mask=current options, -u mask=~(current options)
245*4887Schin 		   else mask=all bits */
246*4887Schin 		if(setflag&SET_SET)
247*4887Schin 			opt=newflags;
248*4887Schin 		else if(setflag&SET_UNSET)
249*4887Schin 			for(n=0;n<4;n++)
250*4887Schin 				opt.v[n]=~newflags.v[n];
251*4887Schin 		else
252*4887Schin 			memset(&opt,0xff,sizeof(opt));
253*4887Schin 		setflag=SET_NOARGS;
254*4887Schin 	}
255*4887Schin 	while(argc>0)
256*4887Schin 	{
257*4887Schin 		f=1;
258*4887Schin 		n=sh_lookopt(argv[opt_info.index],&f);
259*4887Schin 		if(n<=0||(setflag
260*4887Schin 			&& (is_option(&opt,SH_INTERACTIVE)
261*4887Schin 			    || is_option(&opt,SH_RESTRICTED)
262*4887Schin 			    || is_option(&opt,SH_RESTRICTED2)
263*4887Schin 			    || is_option(&opt,SH_BASH)
264*4887Schin 			    || is_option(&opt,SH_LOGIN_SHELL)))
265*4887Schin 			||(oflag&&(n&SH_BASHOPT)))
266*4887Schin 		{
267*4887Schin 			errormsg(SH_DICT,ERROR_ERROR, e_option, argv[opt_info.index]);
268*4887Schin 			error_info.errors++;
269*4887Schin 			ret=1;
270*4887Schin 		}
271*4887Schin 		else if(f)
272*4887Schin 			on_option(&opt,n&0xff);
273*4887Schin 		else
274*4887Schin 			off_option(&opt,n&0xff);
275*4887Schin 		opt_info.index++;
276*4887Schin 		argc--;
277*4887Schin 	}
278*4887Schin 	if(setflag&(SET_SET|SET_UNSET))
279*4887Schin 	{
280*4887Schin 		if(setflag&SET_SET)
281*4887Schin 		{
282*4887Schin 			if(sh_isoption(SH_INTERACTIVE))
283*4887Schin 				off_option(&opt,SH_NOEXEC);
284*4887Schin 			if(is_option(&opt,SH_VI)||is_option(&opt,SH_EMACS)||is_option(&opt,SH_GMACS))
285*4887Schin 			{
286*4887Schin 				off_option(&newflags,SH_VI);
287*4887Schin 				off_option(&newflags,SH_EMACS);
288*4887Schin 				off_option(&newflags,SH_GMACS);
289*4887Schin 			}
290*4887Schin 			for(n=0;n<4;n++)
291*4887Schin 				newflags.v[n] |= opt.v[n];
292*4887Schin 		}
293*4887Schin 		else if(setflag&SET_UNSET)
294*4887Schin 			for(n=0;n<4;n++)
295*4887Schin 				newflags.v[n] &= ~opt.v[n];
296*4887Schin 		sh_applyopts(newflags);
297*4887Schin 		shp->options = newflags;
298*4887Schin 		if(is_option(&newflags,SH_XTRACE))
299*4887Schin 			sh_trace(argv,1);
300*4887Schin 	}
301*4887Schin 	else if(!(setflag&SET_NOARGS)) /* no -s,-u but args, ret=0 if opt&mask==mask */
302*4887Schin 	{
303*4887Schin 		for(n=0;n<4;n++)
304*4887Schin 			ret+=((newflags.v[n]&opt.v[n])!=opt.v[n]);
305*4887Schin 	}
306*4887Schin 	if(!quietflag&&!(setflag&(SET_SET|SET_UNSET)))
307*4887Schin 		sh_printopts(newflags,verbose,&opt);
308*4887Schin 	return(ret);
309*4887Schin }
310*4887Schin 
311*4887Schin /* mode = 0: init, called two times
312*4887Schin         before parsing shell args with SH_PREINIT state turned on
313*4887Schin 	second time after sh_init() is through and with SH_PREINIT state turned off
314*4887Schin    mode > 1: re-init
315*4887Schin    mode < 0: shutdown
316*4887Schin */
317*4887Schin 
318*4887Schin void bash_init(int mode)
319*4887Schin {
320*4887Schin 	Sfio_t		*iop;
321*4887Schin 	Namval_t	*np;
322*4887Schin 	int		n=0,xtrace,verbose;
323*4887Schin 	if(mode>0)
324*4887Schin 		goto reinit;
325*4887Schin 	if(mode < 0)
326*4887Schin 	{
327*4887Schin 		/* termination code */
328*4887Schin 		if(sh_isoption(SH_LOGIN_SHELL) && !sh_isoption(SH_POSIX))
329*4887Schin 			sh_source(&sh, NiL, sh_mactry((char*)e_bash_logout));
330*4887Schin 		return;
331*4887Schin 	}
332*4887Schin 
333*4887Schin 	if(sh_isstate(SH_PREINIT))
334*4887Schin 	{	/* pre-init stage */
335*4887Schin 		if(sh_isoption(SH_RESTRICTED))
336*4887Schin 			sh_onoption(SH_RESTRICTED2);
337*4887Schin 		sh_onoption(SH_HISTORY2);
338*4887Schin 		sh_onoption(SH_INTERACTIVE_COMM);
339*4887Schin 		sh_onoption(SH_SOURCEPATH);
340*4887Schin 		sh_onoption(SH_HISTAPPEND);
341*4887Schin 		sh_onoption(SH_CMDHIST);
342*4887Schin 		sh_onoption(SH_LITHIST);
343*4887Schin 		sh_onoption(SH_NOEMPTYCMDCOMPL);
344*4887Schin 		if(sh.login_sh==2)
345*4887Schin 			sh_onoption(SH_LOGIN_SHELL);
346*4887Schin 		if(strcmp(astconf("CONFORMANCE",0,0),"standard")==0)
347*4887Schin 			sh_onoption(SH_POSIX);
348*4887Schin 		if(strcmp(astconf("UNIVERSE",0,0),"att")==0)
349*4887Schin 			sh_onoption(SH_XPG_ECHO);
350*4887Schin 		else
351*4887Schin 			sh_offoption(SH_XPG_ECHO);
352*4887Schin 		if(strcmp(astconf("PATH_RESOLVE",0,0),"physical")==0)
353*4887Schin 			sh_onoption(SH_PHYSICAL);
354*4887Schin 		else
355*4887Schin 			sh_offoption(SH_PHYSICAL);
356*4887Schin 
357*4887Schin 		/* add builtins */
358*4887Schin 		sh_addbuiltin("shopt", b_shopt, &sh);
359*4887Schin 
360*4887Schin 		/* set up some variables needed for --version
361*4887Schin 		 * needs to go here because --version option is parsed before the init script.
362*4887Schin 		 */
363*4887Schin 		if(np=nv_open("HOSTTYPE",sh.var_tree,0))
364*4887Schin 			nv_putval(np, BASH_HOSTTYPE, NV_NOFREE);
365*4887Schin 		if(np=nv_open("MACHTYPE",sh.var_tree,0))
366*4887Schin 			nv_putval(np, BASH_MACHTYPE, NV_NOFREE);
367*4887Schin 		if(np=nv_open("BASH_VERSION",sh.var_tree,0))
368*4887Schin 			nv_putval(np, BASH_VERSION, NV_NOFREE);
369*4887Schin 		if(np=nv_open("BASH_VERSINFO",sh.var_tree,0))
370*4887Schin 		{
371*4887Schin 			char *argv[7];
372*4887Schin 			argv[0] = BASH_MAJOR;
373*4887Schin 			argv[1] = BASH_MINOR;
374*4887Schin 			argv[2] = BASH_PATCH;
375*4887Schin 			argv[3] = BASH_BUILD;
376*4887Schin 			argv[4] = BASH_RELEASE;
377*4887Schin 			argv[5] = BASH_MACHTYPE;
378*4887Schin 			argv[6] = 0;
379*4887Schin 			nv_setvec(np, 0, 6, argv);
380*4887Schin 			nv_onattr(np,NV_RDONLY);
381*4887Schin 		}
382*4887Schin 		return;
383*4887Schin 	}
384*4887Schin 
385*4887Schin 	/* rest of init stage */
386*4887Schin 
387*4887Schin 	/* restrict BASH_ENV */
388*4887Schin 	if(np=nv_open("BASH_ENV",sh.var_tree,0))
389*4887Schin 	{
390*4887Schin 		const Namdisc_t *dp = nv_discfun(NV_DCRESTRICT);
391*4887Schin 		Namfun_t *fp = calloc(dp->dsize,1);
392*4887Schin 		fp->disc = dp;
393*4887Schin 		nv_disc(np, fp, 0);
394*4887Schin 	}
395*4887Schin 
396*4887Schin 	/* open GLOBIGNORE node */
397*4887Schin 	if(np=nv_open("GLOBIGNORE",sh.var_tree,0))
398*4887Schin 	{
399*4887Schin 		const Namdisc_t *dp = &SH_GLOBIGNORE_disc;
400*4887Schin 		Namfun_t *fp = calloc(dp->dsize,1);
401*4887Schin 		fp->disc = dp;
402*4887Schin 		nv_disc(np, fp, 0);
403*4887Schin 	}
404*4887Schin 
405*4887Schin 	/* set startup files */
406*4887Schin 	n=0;
407*4887Schin 	if(!sh_isoption(SH_NOPROFILE))
408*4887Schin 	{
409*4887Schin 		if(!sh_isoption(SH_POSIX))
410*4887Schin 		{
411*4887Schin 			login_files[n++] = (char*)e_bash_profile;
412*4887Schin 			login_files[n++] = (char*)e_bash_login;
413*4887Schin 		}
414*4887Schin 		login_files[n++] = (char*)e_profile;
415*4887Schin 	}
416*4887Schin 	sh.login_files = login_files;
417*4887Schin reinit:
418*4887Schin 	xtrace = sh_isoption(SH_XTRACE);
419*4887Schin 	sh_offoption(SH_XTRACE);
420*4887Schin 	verbose = sh_isoption(SH_VERBOSE);
421*4887Schin 	sh_offoption(SH_VERBOSE);
422*4887Schin 	if(np = nv_open("SHELLOPTS", sh.var_tree, NV_NOADD))
423*4887Schin 		nv_offattr(np,NV_RDONLY);
424*4887Schin 	iop = sfopen(NULL, bash_pre_rc, "s");
425*4887Schin 	sh_eval(iop,0);
426*4887Schin 	if(xtrace)
427*4887Schin 		sh_offoption(SH_XTRACE);
428*4887Schin 	if(verbose)
429*4887Schin 		sh_offoption(SH_VERBOSE);
430*4887Schin }
431