14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1982-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.Chin@Sun.COM * by AT&T Intellectual Property * 84887Schin * * 94887Schin * A copy of the License is available at * 104887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 124887Schin * * 134887Schin * Information and Software Systems Research * 144887Schin * AT&T Research * 154887Schin * Florham Park NJ * 164887Schin * * 174887Schin * David Korn <dgk@research.att.com> * 184887Schin * * 194887Schin ***********************************************************************/ 204887Schin /* 214887Schin * bash specific extensions 224887Schin * originally provided by Karsten Fleischer 234887Schin */ 244887Schin 254887Schin #include "defs.h" 264887Schin #include "path.h" 274887Schin #include "io.h" 284887Schin #include "builtins.h" 294887Schin #include "name.h" 304887Schin 314887Schin #ifndef BASH_MAJOR 324887Schin # define BASH_MAJOR "1" 334887Schin # define BASH_MINOR "0" 344887Schin # define BASH_PATCH "0" 354887Schin # define BASH_BUILD "0" 364887Schin # define BASH_RELEASE "experimental" 374887Schin #endif 384887Schin #define BASH_VERSION BASH_MAJOR "." BASH_MINOR "." BASH_PATCH "(" BASH_BUILD ")-" BASH_RELEASE 394887Schin 404887Schin 414887Schin extern const char bash_pre_rc[]; 424887Schin 434887Schin static char *login_files[4]; 444887Schin 454887Schin const char sh_bash1[] = 464887Schin "[B?Enable brace group expansion. This option is only availabe in bash " 474887Schin "compatibility mode. In ksh mode, brace group expansion is always on.]" 484887Schin "[P?Do not follow symbolic links, use physical directory structure " 494887Schin "instead. Only available in bash compatibility mode.]"; 504887Schin const char sh_bash2[] = 514887Schin "[O]:?[shopt_option?\ashopt_option\a is one of the shell options accepted by " 524887Schin "the \bshopt\b builtin. If \ashopt_option\a is present, \b-O\b sets " 534887Schin "the value of that option; \b+O\b unsets it. If \ashopt_option\a is " 544887Schin "not supplied, the names and values of the shell options accepted by " 554887Schin "\bshopt\b are printed on the standard output. If the invocation " 564887Schin "option is \b+O\b, the output is displayed in a format that may be " 574887Schin "reused as input. Only available if invoked as \bbash\b.]" 584887Schin "[01:init-file|rcfile]:[file?Execute commands from \afile\a instead of the " 594887Schin "standard personal initialization file ~/.bashrc if the shell is " 604887Schin "interactive. Only available if invoked as \bbash\b.]" 614887Schin "[02:editing?For option compatibility with \bbash\b only. Ignored.]" 624887Schin "[03:profile?Read either the system-wide startup file or any of the " 634887Schin "personal initialization files. On by default for interactive " 644887Schin "shells. Only available if invoked as \bbash\b.]" 65*8462SApril.Chin@Sun.COM "[04:posix?If invoked as \bbash\b, turn on POSIX compatibility. \bBash\b in " 664887Schin "POSIX mode is not the same as \bksh\b.]" 67*8462SApril.Chin@Sun.COM "[05:version?Print version number and exit.]"; 684887Schin 694887Schin const char sh_optshopt[] = 704887Schin "+[-1c?\n@(#)$Id: shopt (AT&T Research) 2003-02-13 $\n]" 714887Schin "[-author?Karsten Fleischer <K.Fleischer@omnium.de>]" 724887Schin USAGE_LICENSE 734887Schin "[+NAME?shopt - set/unset variables controlling optional shell behavior]" 744887Schin "[+DESCRIPTION?\bshopt\b sets or unsets variables controlling optional shell " 754887Schin "behavior. With no options, or with the \b-p\b option, a list of all " 764887Schin "settable options is displayed, with an indication of whether or not " 774887Schin "each is set.]" 784887Schin "[p?Causes output to be displayed in a form that may be reused as input.]" 794887Schin "[s?Set each \aoptname\a.]" 804887Schin "[u?Unset each \aoptname\a.]" 814887Schin "[q?Suppress output (quiet mode). The return status indicates whether the " 824887Schin "\aoptname\a is set or unset. If multiple \aoptname\a arguments are " 834887Schin "given with \b-q\b, the return status is zero if all \aoptname\as are " 844887Schin "enabled; non-zero otherwise.]" 854887Schin "[o?Restricts the values of \aoptname\a to be those defined for the \b-o\b " 864887Schin "option to the set builtin.]" 874887Schin "[+?If either \b-s\b or \b-u\b is used with no \aoptname\a arguments, the " 884887Schin "display is limited to those options which are set or unset.]" 894887Schin "[+?\bshopt\b supports all bash options. Some settings do not have any effect " 904887Schin "or are are always on and cannot be changed.]" 914887Schin "[+?The value of \aoptname\a must be one of the following:]{" 924887Schin "[+cdable_vars?If set, arguments to the \bcd\b command are " 934887Schin "assumed to be names of variables whose values are to " 944887Schin "be used if the usual \bcd\b proceeding fails.]" 954887Schin "[+cdspell?Currently ignored.]" 964887Schin "[+checkhash?Always on.]" 974887Schin "[+checkwinsize?Currently ignored.]" 984887Schin "[+cmdhist?Always on.]" 994887Schin "[+dotglob?If set, include filenames beginning with a \b.\b " 1004887Schin "in the results of pathname expansion.]" 1014887Schin "[+execfail?Always on.]" 1024887Schin "[+expand_aliases?Always on.]" 1034887Schin "[+extglob?Enable extended pattern matching features.]" 1044887Schin "[+histappend?Always on.]" 1054887Schin "[+histreedit?If set and an edit mode is selected, the user " 1064887Schin "is given the opportunity to re-edit a failed history " 1074887Schin "substitution.]" 1084887Schin "[+histverify?If set and an edit mode is selected, the result " 1094887Schin "of a history substitution will not be executed " 1104887Schin "immediately but be placed in the edit buffer for " 1114887Schin "further modifications.]" 1124887Schin "[+hostcomplete?Currently ignored.]" 1134887Schin "[+huponexit?Currently ignored.]" 1144887Schin "[+interactive_comments?Always on.]" 1154887Schin "[+lithist?Always on.]" 1164887Schin "[+login_shell?This option is set if the shell is started as " 1174887Schin "a login shell. The value cannot be changed.]" 1184887Schin "[+mailwarn?Currently ignored.]" 1194887Schin "[+no_empty_cmd_completion?Always on.]" 1204887Schin "[+nocaseglob?Match filenames in a case-insensitive fashion " 1214887Schin "when performing filename expansion.]" 1224887Schin "[+nullglob?Allows filename patterns which match no files to " 1234887Schin "expand to a null string, rather than themselves.]" 1244887Schin "[+progcomp?Currently ignored.]" 1254887Schin "[+promptvars?Currently ignored.]" 1264887Schin "[+restricted_shell?This option is set if the shell is started " 1274887Schin "as a restricted shell. The value cannot be changed. " 1284887Schin "It is not reset during execution of startup files, " 1294887Schin "allowing the startup files to determine whether the " 1304887Schin "shell is restricted.]" 1314887Schin "[+shift_verbose?Currently ignored.]" 1324887Schin "[+sourcepath?If set, the \b.\b builtin uses the value of PATH " 1334887Schin "to find the directory containing the file supplied " 1344887Schin "as an argument.]" 1354887Schin "[+xpg_echo?If set, the \becho\b and \bprint\b builtins " 1364887Schin "expand backslash-escape sequences.]" 1374887Schin "}" 1384887Schin "\n" 1394887Schin "\n[optname ...]\n" 1404887Schin "\n" 1414887Schin "[+EXIT STATUS?]{" 1424887Schin "[+?The return status when listing options is zero if all \aoptnames\a " 1434887Schin "are enabled, non-zero otherwise. When setting or unsetting options, " 1444887Schin "the return status is zero unless an \aoptname\a is not a valid shell " 1454887Schin "option.]" 1464887Schin "}" 1474887Schin 1484887Schin "[+SEE ALSO?\bset\b(1)]" 1494887Schin ; 1504887Schin 1514887Schin /* GLOBIGNORE discipline. Turn on SH_DOTGLOB on set, turn off on unset. */ 1524887Schin 1534887Schin static void put_globignore(register Namval_t* np, const char *val, int flags, Namfun_t *fp) 1544887Schin { 1554887Schin if(val) 1564887Schin sh_onoption(SH_DOTGLOB); 1574887Schin else 1584887Schin sh_offoption(SH_DOTGLOB); 1594887Schin 1604887Schin nv_putv(np,val,flags,fp); 1614887Schin } 1624887Schin 1634887Schin const Namdisc_t SH_GLOBIGNORE_disc = { sizeof(Namfun_t), put_globignore }; 1644887Schin 1654887Schin /* FUNCNAME discipline */ 1664887Schin 1674887Schin struct funcname 1684887Schin { 1694887Schin Namfun_t hdr; 1704887Schin }; 1714887Schin 1724887Schin static void put_funcname(register Namval_t* np,const char *val,int flags,Namfun_t *fp) 1734887Schin { 1744887Schin /* bash silently returns with an error when FUNCNAME is set, 1754887Schin unsetting FUNCNAME is allowed */ 1764887Schin if(val && !(flags&NV_RDONLY)) 1774887Schin error_info.exit(1); 1784887Schin 1794887Schin nv_putv(np,val,flags,fp); 1804887Schin } 1814887Schin 1824887Schin const Namdisc_t SH_FUNCNAME_disc = { sizeof(struct funcname), put_funcname }; 1834887Schin 1844887Schin #define SET_SET 1 1854887Schin #define SET_UNSET 2 1864887Schin #define SET_NOARGS 4 1874887Schin 1884887Schin /* shopt builtin */ 1894887Schin 1904887Schin int b_shopt(int argc,register char *argv[],void *extra) 1914887Schin { 1924887Schin Shell_t *shp = (Shell_t*)extra; 1934887Schin int n, f, ret=0; 1944887Schin Shopt_t newflags=shp->options, opt; 1954887Schin int verbose=PRINT_SHOPT|PRINT_ALL|PRINT_NO_HEADER|PRINT_VERBOSE; 1964887Schin int setflag=0, quietflag=0, oflag=0; 1974887Schin memset(&opt,0,sizeof(opt)); 1984887Schin #if SHOPT_RAWONLY 1994887Schin on_option(&newflags,SH_VIRAW); 2004887Schin #endif 2014887Schin while((n = optget(argv,sh_optshopt))) 2024887Schin { 2034887Schin switch(n) 2044887Schin { 2054887Schin case 'p': 2064887Schin verbose&=~PRINT_VERBOSE; 2074887Schin break; 2084887Schin case 's': 2094887Schin case 'u': 2104887Schin setflag|=n=='s'?SET_SET:SET_UNSET; 2114887Schin if(setflag==(SET_SET|SET_UNSET)) 2124887Schin { 2134887Schin errormsg(SH_DICT,ERROR_ERROR,"cannot set and unset options simultaneously"); 2144887Schin error_info.errors++; 2154887Schin } 2164887Schin break; 2174887Schin case 'q': 2184887Schin quietflag=1; 2194887Schin break; 2204887Schin case 'o': 2214887Schin oflag=1; 2224887Schin verbose&=~PRINT_SHOPT; 2234887Schin break; 2244887Schin case ':': 2254887Schin errormsg(SH_DICT,2, "%s", opt_info.arg); 2264887Schin continue; 2274887Schin case '?': 2284887Schin errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); 2294887Schin return(-1); 2304887Schin } 2314887Schin } 2324887Schin if(error_info.errors) 2334887Schin errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*))); 2344887Schin argc -= opt_info.index; 2354887Schin if(argc==0) 2364887Schin { 2374887Schin /* no args, -s => mask=current options, -u mask=~(current options) 2384887Schin else mask=all bits */ 2394887Schin if(setflag&SET_SET) 2404887Schin opt=newflags; 2414887Schin else if(setflag&SET_UNSET) 2424887Schin for(n=0;n<4;n++) 2434887Schin opt.v[n]=~newflags.v[n]; 2444887Schin else 2454887Schin memset(&opt,0xff,sizeof(opt)); 2464887Schin setflag=SET_NOARGS; 2474887Schin } 2484887Schin while(argc>0) 2494887Schin { 2504887Schin f=1; 2514887Schin n=sh_lookopt(argv[opt_info.index],&f); 2524887Schin if(n<=0||(setflag 2534887Schin && (is_option(&opt,SH_INTERACTIVE) 2544887Schin || is_option(&opt,SH_RESTRICTED) 2554887Schin || is_option(&opt,SH_RESTRICTED2) 2564887Schin || is_option(&opt,SH_BASH) 2574887Schin || is_option(&opt,SH_LOGIN_SHELL))) 2584887Schin ||(oflag&&(n&SH_BASHOPT))) 2594887Schin { 2604887Schin errormsg(SH_DICT,ERROR_ERROR, e_option, argv[opt_info.index]); 2614887Schin error_info.errors++; 2624887Schin ret=1; 2634887Schin } 2644887Schin else if(f) 2654887Schin on_option(&opt,n&0xff); 2664887Schin else 2674887Schin off_option(&opt,n&0xff); 2684887Schin opt_info.index++; 2694887Schin argc--; 2704887Schin } 2714887Schin if(setflag&(SET_SET|SET_UNSET)) 2724887Schin { 2734887Schin if(setflag&SET_SET) 2744887Schin { 2754887Schin if(sh_isoption(SH_INTERACTIVE)) 2764887Schin off_option(&opt,SH_NOEXEC); 2774887Schin if(is_option(&opt,SH_VI)||is_option(&opt,SH_EMACS)||is_option(&opt,SH_GMACS)) 2784887Schin { 2794887Schin off_option(&newflags,SH_VI); 2804887Schin off_option(&newflags,SH_EMACS); 2814887Schin off_option(&newflags,SH_GMACS); 2824887Schin } 2834887Schin for(n=0;n<4;n++) 2844887Schin newflags.v[n] |= opt.v[n]; 2854887Schin } 2864887Schin else if(setflag&SET_UNSET) 2874887Schin for(n=0;n<4;n++) 2884887Schin newflags.v[n] &= ~opt.v[n]; 289*8462SApril.Chin@Sun.COM sh_applyopts(shp,newflags); 2904887Schin shp->options = newflags; 2914887Schin if(is_option(&newflags,SH_XTRACE)) 2924887Schin sh_trace(argv,1); 2934887Schin } 2944887Schin else if(!(setflag&SET_NOARGS)) /* no -s,-u but args, ret=0 if opt&mask==mask */ 2954887Schin { 2964887Schin for(n=0;n<4;n++) 2974887Schin ret+=((newflags.v[n]&opt.v[n])!=opt.v[n]); 2984887Schin } 2994887Schin if(!quietflag&&!(setflag&(SET_SET|SET_UNSET))) 3004887Schin sh_printopts(newflags,verbose,&opt); 3014887Schin return(ret); 3024887Schin } 3034887Schin 3044887Schin /* mode = 0: init, called two times 3054887Schin before parsing shell args with SH_PREINIT state turned on 3064887Schin second time after sh_init() is through and with SH_PREINIT state turned off 3074887Schin mode > 1: re-init 3084887Schin mode < 0: shutdown 3094887Schin */ 3104887Schin 3114887Schin void bash_init(int mode) 3124887Schin { 313*8462SApril.Chin@Sun.COM Shell_t *shp = &sh; 3144887Schin Sfio_t *iop; 3154887Schin Namval_t *np; 3164887Schin int n=0,xtrace,verbose; 3174887Schin if(mode>0) 3184887Schin goto reinit; 3194887Schin if(mode < 0) 3204887Schin { 3214887Schin /* termination code */ 3224887Schin if(sh_isoption(SH_LOGIN_SHELL) && !sh_isoption(SH_POSIX)) 323*8462SApril.Chin@Sun.COM sh_source(shp, NiL, sh_mactry(shp,(char*)e_bash_logout)); 3244887Schin return; 3254887Schin } 3264887Schin 3274887Schin if(sh_isstate(SH_PREINIT)) 3284887Schin { /* pre-init stage */ 3294887Schin if(sh_isoption(SH_RESTRICTED)) 3304887Schin sh_onoption(SH_RESTRICTED2); 3314887Schin sh_onoption(SH_HISTORY2); 3324887Schin sh_onoption(SH_INTERACTIVE_COMM); 3334887Schin sh_onoption(SH_SOURCEPATH); 3344887Schin sh_onoption(SH_HISTAPPEND); 3354887Schin sh_onoption(SH_CMDHIST); 3364887Schin sh_onoption(SH_LITHIST); 3374887Schin sh_onoption(SH_NOEMPTYCMDCOMPL); 338*8462SApril.Chin@Sun.COM if(shp->login_sh==2) 3394887Schin sh_onoption(SH_LOGIN_SHELL); 3404887Schin if(strcmp(astconf("CONFORMANCE",0,0),"standard")==0) 3414887Schin sh_onoption(SH_POSIX); 3424887Schin if(strcmp(astconf("UNIVERSE",0,0),"att")==0) 3434887Schin sh_onoption(SH_XPG_ECHO); 3444887Schin else 3454887Schin sh_offoption(SH_XPG_ECHO); 3464887Schin if(strcmp(astconf("PATH_RESOLVE",0,0),"physical")==0) 3474887Schin sh_onoption(SH_PHYSICAL); 3484887Schin else 3494887Schin sh_offoption(SH_PHYSICAL); 3504887Schin 3514887Schin /* add builtins */ 3524887Schin sh_addbuiltin("shopt", b_shopt, &sh); 3534887Schin 3544887Schin /* set up some variables needed for --version 3554887Schin * needs to go here because --version option is parsed before the init script. 3564887Schin */ 357*8462SApril.Chin@Sun.COM if(np=nv_open("HOSTTYPE",shp->var_tree,0)) 3584887Schin nv_putval(np, BASH_HOSTTYPE, NV_NOFREE); 359*8462SApril.Chin@Sun.COM if(np=nv_open("MACHTYPE",shp->var_tree,0)) 3604887Schin nv_putval(np, BASH_MACHTYPE, NV_NOFREE); 361*8462SApril.Chin@Sun.COM if(np=nv_open("BASH_VERSION",shp->var_tree,0)) 3624887Schin nv_putval(np, BASH_VERSION, NV_NOFREE); 363*8462SApril.Chin@Sun.COM if(np=nv_open("BASH_VERSINFO",shp->var_tree,0)) 3644887Schin { 3654887Schin char *argv[7]; 3664887Schin argv[0] = BASH_MAJOR; 3674887Schin argv[1] = BASH_MINOR; 3684887Schin argv[2] = BASH_PATCH; 3694887Schin argv[3] = BASH_BUILD; 3704887Schin argv[4] = BASH_RELEASE; 3714887Schin argv[5] = BASH_MACHTYPE; 3724887Schin argv[6] = 0; 3734887Schin nv_setvec(np, 0, 6, argv); 3744887Schin nv_onattr(np,NV_RDONLY); 3754887Schin } 3764887Schin return; 3774887Schin } 3784887Schin 3794887Schin /* rest of init stage */ 3804887Schin 3814887Schin /* restrict BASH_ENV */ 382*8462SApril.Chin@Sun.COM if(np=nv_open("BASH_ENV",shp->var_tree,0)) 3834887Schin { 3844887Schin const Namdisc_t *dp = nv_discfun(NV_DCRESTRICT); 3854887Schin Namfun_t *fp = calloc(dp->dsize,1); 3864887Schin fp->disc = dp; 3874887Schin nv_disc(np, fp, 0); 3884887Schin } 3894887Schin 3904887Schin /* open GLOBIGNORE node */ 391*8462SApril.Chin@Sun.COM if(np=nv_open("GLOBIGNORE",shp->var_tree,0)) 3924887Schin { 3934887Schin const Namdisc_t *dp = &SH_GLOBIGNORE_disc; 3944887Schin Namfun_t *fp = calloc(dp->dsize,1); 3954887Schin fp->disc = dp; 3964887Schin nv_disc(np, fp, 0); 3974887Schin } 3984887Schin 3994887Schin /* set startup files */ 4004887Schin n=0; 401*8462SApril.Chin@Sun.COM if(sh_isoption(SH_LOGIN_SHELL)) 4024887Schin { 4034887Schin if(!sh_isoption(SH_POSIX)) 4044887Schin { 4054887Schin login_files[n++] = (char*)e_bash_profile; 4064887Schin login_files[n++] = (char*)e_bash_login; 4074887Schin } 4084887Schin login_files[n++] = (char*)e_profile; 4094887Schin } 410*8462SApril.Chin@Sun.COM shp->login_files = login_files; 4114887Schin reinit: 4124887Schin xtrace = sh_isoption(SH_XTRACE); 4134887Schin sh_offoption(SH_XTRACE); 4144887Schin verbose = sh_isoption(SH_VERBOSE); 4154887Schin sh_offoption(SH_VERBOSE); 416*8462SApril.Chin@Sun.COM if(np = nv_open("SHELLOPTS", shp->var_tree, NV_NOADD)) 4174887Schin nv_offattr(np,NV_RDONLY); 4184887Schin iop = sfopen(NULL, bash_pre_rc, "s"); 4194887Schin sh_eval(iop,0); 4204887Schin if(xtrace) 4214887Schin sh_offoption(SH_XTRACE); 4224887Schin if(verbose) 4234887Schin sh_offoption(SH_VERBOSE); 4244887Schin } 425