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