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