1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2008 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 /* 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 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 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 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(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 311 void bash_init(int mode) 312 { 313 Shell_t *shp = &sh; 314 Sfio_t *iop; 315 Namval_t *np; 316 int n=0,xtrace,verbose; 317 if(mode>0) 318 goto reinit; 319 if(mode < 0) 320 { 321 /* termination code */ 322 if(sh_isoption(SH_LOGIN_SHELL) && !sh_isoption(SH_POSIX)) 323 sh_source(shp, NiL, sh_mactry(shp,(char*)e_bash_logout)); 324 return; 325 } 326 327 if(sh_isstate(SH_PREINIT)) 328 { /* pre-init stage */ 329 if(sh_isoption(SH_RESTRICTED)) 330 sh_onoption(SH_RESTRICTED2); 331 sh_onoption(SH_HISTORY2); 332 sh_onoption(SH_INTERACTIVE_COMM); 333 sh_onoption(SH_SOURCEPATH); 334 sh_onoption(SH_HISTAPPEND); 335 sh_onoption(SH_CMDHIST); 336 sh_onoption(SH_LITHIST); 337 sh_onoption(SH_NOEMPTYCMDCOMPL); 338 if(shp->login_sh==2) 339 sh_onoption(SH_LOGIN_SHELL); 340 if(strcmp(astconf("CONFORMANCE",0,0),"standard")==0) 341 sh_onoption(SH_POSIX); 342 if(strcmp(astconf("UNIVERSE",0,0),"att")==0) 343 sh_onoption(SH_XPG_ECHO); 344 else 345 sh_offoption(SH_XPG_ECHO); 346 if(strcmp(astconf("PATH_RESOLVE",0,0),"physical")==0) 347 sh_onoption(SH_PHYSICAL); 348 else 349 sh_offoption(SH_PHYSICAL); 350 351 /* add builtins */ 352 sh_addbuiltin("shopt", b_shopt, &sh); 353 354 /* set up some variables needed for --version 355 * needs to go here because --version option is parsed before the init script. 356 */ 357 if(np=nv_open("HOSTTYPE",shp->var_tree,0)) 358 nv_putval(np, BASH_HOSTTYPE, NV_NOFREE); 359 if(np=nv_open("MACHTYPE",shp->var_tree,0)) 360 nv_putval(np, BASH_MACHTYPE, NV_NOFREE); 361 if(np=nv_open("BASH_VERSION",shp->var_tree,0)) 362 nv_putval(np, BASH_VERSION, NV_NOFREE); 363 if(np=nv_open("BASH_VERSINFO",shp->var_tree,0)) 364 { 365 char *argv[7]; 366 argv[0] = BASH_MAJOR; 367 argv[1] = BASH_MINOR; 368 argv[2] = BASH_PATCH; 369 argv[3] = BASH_BUILD; 370 argv[4] = BASH_RELEASE; 371 argv[5] = BASH_MACHTYPE; 372 argv[6] = 0; 373 nv_setvec(np, 0, 6, argv); 374 nv_onattr(np,NV_RDONLY); 375 } 376 return; 377 } 378 379 /* rest of init stage */ 380 381 /* restrict BASH_ENV */ 382 if(np=nv_open("BASH_ENV",shp->var_tree,0)) 383 { 384 const Namdisc_t *dp = nv_discfun(NV_DCRESTRICT); 385 Namfun_t *fp = calloc(dp->dsize,1); 386 fp->disc = dp; 387 nv_disc(np, fp, 0); 388 } 389 390 /* open GLOBIGNORE node */ 391 if(np=nv_open("GLOBIGNORE",shp->var_tree,0)) 392 { 393 const Namdisc_t *dp = &SH_GLOBIGNORE_disc; 394 Namfun_t *fp = calloc(dp->dsize,1); 395 fp->disc = dp; 396 nv_disc(np, fp, 0); 397 } 398 399 /* set startup files */ 400 n=0; 401 if(sh_isoption(SH_LOGIN_SHELL)) 402 { 403 if(!sh_isoption(SH_POSIX)) 404 { 405 login_files[n++] = (char*)e_bash_profile; 406 login_files[n++] = (char*)e_bash_login; 407 } 408 login_files[n++] = (char*)e_profile; 409 } 410 shp->login_files = login_files; 411 reinit: 412 xtrace = sh_isoption(SH_XTRACE); 413 sh_offoption(SH_XTRACE); 414 verbose = sh_isoption(SH_VERBOSE); 415 sh_offoption(SH_VERBOSE); 416 if(np = nv_open("SHELLOPTS", shp->var_tree, NV_NOADD)) 417 nv_offattr(np,NV_RDONLY); 418 iop = sfopen(NULL, bash_pre_rc, "s"); 419 sh_eval(iop,0); 420 if(xtrace) 421 sh_offoption(SH_XTRACE); 422 if(verbose) 423 sh_offoption(SH_VERBOSE); 424 } 425