14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*10898Sroland.mainz@nrubsig.org * Copyright (c) 1982-2009 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 78462SApril.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 #pragma prototyped 214887Schin /* 224887Schin * UNIX shell 234887Schin * 244887Schin * S. R. Bourne 254887Schin * Rewritten by David Korn 264887Schin * AT&T Labs 274887Schin * 284887Schin */ 294887Schin 304887Schin #include "defs.h" 314887Schin #include "path.h" 324887Schin #include "builtins.h" 334887Schin #include "terminal.h" 344887Schin #include "edit.h" 354887Schin #include "FEATURE/poll" 364887Schin #if SHOPT_KIA 374887Schin # include "shlex.h" 384887Schin # include "io.h" 394887Schin #endif /* SHOPT_KIA */ 404887Schin #if SHOPT_PFSH 414887Schin # define PFSHOPT "P" 424887Schin #else 434887Schin # define PFSHOPT 444887Schin #endif 454887Schin #if SHOPT_BASH 468462SApril.Chin@Sun.COM # define BASHOPT "\374" 474887Schin #else 484887Schin # define BASHOPT 494887Schin #endif 504887Schin #if SHOPT_HISTEXPAND 514887Schin # define HFLAG "H" 524887Schin #else 534887Schin # define HFLAG "" 544887Schin #endif 554887Schin 564887Schin #define SORT 1 574887Schin #define PRINT 2 584887Schin 594887Schin static char *null; 604887Schin 614887Schin /* The following order is determined by sh_optset */ 624887Schin static const char optksh[] = PFSHOPT BASHOPT "DircabefhkmnpstuvxBCGEl" HFLAG; 634887Schin static const int flagval[] = 644887Schin { 654887Schin #if SHOPT_PFSH 664887Schin SH_PFSH, 674887Schin #endif 684887Schin #if SHOPT_BASH 698462SApril.Chin@Sun.COM SH_POSIX, 704887Schin #endif 714887Schin SH_DICTIONARY, SH_INTERACTIVE, SH_RESTRICTED, SH_CFLAG, 724887Schin SH_ALLEXPORT, SH_NOTIFY, SH_ERREXIT, SH_NOGLOB, SH_TRACKALL, 734887Schin SH_KEYWORD, SH_MONITOR, SH_NOEXEC, SH_PRIVILEGED, SH_SFLAG, SH_TFLAG, 744887Schin SH_NOUNSET, SH_VERBOSE, SH_XTRACE, SH_BRACEEXPAND, SH_NOCLOBBER, 754887Schin SH_GLOBSTARS, SH_RC, SH_LOGIN_SHELL, 764887Schin #if SHOPT_HISTEXPAND 774887Schin SH_HISTEXPAND, 784887Schin #endif 794887Schin 0 804887Schin }; 814887Schin 824887Schin #define NUM_OPTS (sizeof(flagval)/sizeof(*flagval)) 834887Schin 844887Schin typedef struct _arg_ 854887Schin { 868462SApril.Chin@Sun.COM Shell_t *sh; 874887Schin struct dolnod *argfor; /* linked list of blocks to be cleaned up */ 884887Schin struct dolnod *dolh; 894887Schin char flagadr[NUM_OPTS+1]; 904887Schin #if SHOPT_KIA 914887Schin char *kiafile; 924887Schin #endif /* SHOPT_KIA */ 934887Schin } Arg_t; 944887Schin 958462SApril.Chin@Sun.COM static int arg_expand(Shell_t*,struct argnod*,struct argnod**,int); 968462SApril.Chin@Sun.COM static void sh_argset(Arg_t*, char *[]); 978462SApril.Chin@Sun.COM 984887Schin 994887Schin /* ======== option handling ======== */ 1004887Schin 1014887Schin void *sh_argopen(Shell_t *shp) 1024887Schin { 1034887Schin void *addr = newof(0,Arg_t,1,0); 1044887Schin Arg_t *ap = (Arg_t*)addr; 1058462SApril.Chin@Sun.COM ap->sh = shp; 1064887Schin return(addr); 1074887Schin } 1084887Schin 1094887Schin static int infof(Opt_t* op, Sfio_t* sp, const char* s, Optdisc_t* dp) 1104887Schin { 1114887Schin #if SHOPT_BASH 1124887Schin extern const char sh_bash1[], sh_bash2[]; 1134887Schin if(strcmp(s,"bash1")==0) 1144887Schin { 1154887Schin if(sh_isoption(SH_BASH)) 1164887Schin sfputr(sp,sh_bash1,-1); 1174887Schin } 1184887Schin else if(strcmp(s,"bash2")==0) 1194887Schin { 1204887Schin if(sh_isoption(SH_BASH)) 1214887Schin sfputr(sp,sh_bash2,-1); 1224887Schin } 1234887Schin else if(*s==':' && sh_isoption(SH_BASH)) 1244887Schin sfputr(sp,s,-1); 1254887Schin else 1264887Schin #endif 1274887Schin if(*s!=':') 1284887Schin sfputr(sp,sh_set,-1); 1294887Schin return(1); 1304887Schin } 1314887Schin 1324887Schin /* 1334887Schin * This routine turns options on and off 1344887Schin * The options "PDicr" are illegal from set command. 1354887Schin * The -o option is used to set option by name 1364887Schin * This routine returns the number of non-option arguments 1374887Schin */ 1388462SApril.Chin@Sun.COM int sh_argopts(int argc,register char *argv[], void *context) 1394887Schin { 1408462SApril.Chin@Sun.COM Shell_t *shp = (Shell_t*)context; 1418462SApril.Chin@Sun.COM register int n,o; 1428462SApril.Chin@Sun.COM register Arg_t *ap = (Arg_t*)(shp->arg_context); 1438462SApril.Chin@Sun.COM Lex_t *lp = (Lex_t*)(shp->lex_context); 1448462SApril.Chin@Sun.COM Shopt_t newflags; 1454887Schin int setflag=0, action=0, trace=(int)sh_isoption(SH_XTRACE); 1464887Schin Namval_t *np = NIL(Namval_t*); 1474887Schin const char *cp; 1484887Schin int verbose,f; 1494887Schin Optdisc_t disc; 1508462SApril.Chin@Sun.COM newflags=ap->sh->options; 1514887Schin memset(&disc, 0, sizeof(disc)); 1524887Schin disc.version = OPT_VERSION; 1534887Schin disc.infof = infof; 1544887Schin opt_info.disc = &disc; 1554887Schin 1564887Schin if(argc>0) 1574887Schin setflag = 4; 1584887Schin else 1594887Schin argc = -argc; 1604887Schin while((n = optget(argv,setflag?sh_optset:sh_optksh))) 1614887Schin { 1624887Schin o=0; 1638462SApril.Chin@Sun.COM f=*opt_info.option=='-' && (opt_info.num || opt_info.arg); 1644887Schin switch(n) 1654887Schin { 1664887Schin case 'A': 1678462SApril.Chin@Sun.COM np = nv_open(opt_info.arg,ap->sh->var_tree,NV_NOASSIGN|NV_ARRAY|NV_VARNAME); 1684887Schin if(f) 1694887Schin nv_unset(np); 1704887Schin continue; 1714887Schin #if SHOPT_BASH 1724887Schin case 'O': /* shopt options, only in bash mode */ 1734887Schin if(!sh_isoption(SH_BASH)) 1744887Schin errormsg(SH_DICT,ERROR_exit(1), e_option, opt_info.name); 1754887Schin #endif 1764887Schin case 'o': /* set options */ 1774887Schin byname: 1784887Schin if(!opt_info.arg||!*opt_info.arg||*opt_info.arg=='-') 1794887Schin { 1804887Schin action = PRINT; 1814887Schin /* print style: -O => shopt options 1824887Schin * bash => print unset options also, no heading 1834887Schin */ 1844887Schin verbose = (f?PRINT_VERBOSE:PRINT_NO_HEADER)| 1854887Schin (n=='O'?PRINT_SHOPT:0)| 1864887Schin (sh_isoption(SH_BASH)?PRINT_ALL|PRINT_NO_HEADER:0)| 1874887Schin ((opt_info.arg&&(!*opt_info.arg||*opt_info.arg=='-'))?(PRINT_TABLE|PRINT_NO_HEADER):0); 1884887Schin continue; 1894887Schin } 1904887Schin o = sh_lookopt(opt_info.arg,&f); 1914887Schin if(o<=0 1924887Schin || (!sh_isoption(SH_BASH) && (o&SH_BASHEXTRA)) 1934887Schin || ((!sh_isoption(SH_BASH) || n=='o') && (o&SH_BASHOPT)) 1944887Schin 1954887Schin || (setflag && (o&SH_COMMANDLINE))) 1964887Schin { 1974887Schin errormsg(SH_DICT,2, e_option, opt_info.arg); 1984887Schin error_info.errors++; 1994887Schin } 2004887Schin o &= 0xff; 2014887Schin if(sh_isoption(SH_RESTRICTED) && !f && o==SH_RESTRICTED) 2024887Schin errormsg(SH_DICT,ERROR_exit(1), e_restricted, opt_info.arg); 2034887Schin break; 2044887Schin #if SHOPT_BASH 2054887Schin case -1: /* --rcfile */ 2068462SApril.Chin@Sun.COM ap->sh->rcfile = opt_info.arg; 2074887Schin continue; 2084887Schin case -2: /* --noediting */ 2098462SApril.Chin@Sun.COM if (!f) 2108462SApril.Chin@Sun.COM { 2118462SApril.Chin@Sun.COM off_option(&newflags,SH_VI); 2128462SApril.Chin@Sun.COM off_option(&newflags,SH_EMACS); 2138462SApril.Chin@Sun.COM off_option(&newflags,SH_GMACS); 2148462SApril.Chin@Sun.COM } 2154887Schin continue; 2164887Schin case -3: /* --profile */ 2178462SApril.Chin@Sun.COM n = 'l'; 2188462SApril.Chin@Sun.COM goto skip; 2198462SApril.Chin@Sun.COM case -4: /* --posix */ 2204887Schin /* mask lower 8 bits to find char in optksh string */ 2214887Schin n&=0xff; 2224887Schin goto skip; 2238462SApril.Chin@Sun.COM case -5: /* --version */ 2248462SApril.Chin@Sun.COM sfputr(sfstdout, "ksh bash emulation, version ",-1); 2258462SApril.Chin@Sun.COM np = nv_open("BASH_VERSION",ap->sh->var_tree,0); 2268462SApril.Chin@Sun.COM sfputr(sfstdout, nv_getval(np),-1); 2278462SApril.Chin@Sun.COM np = nv_open("MACHTYPE",ap->sh->var_tree,0); 2288462SApril.Chin@Sun.COM sfprintf(sfstdout, " (%s)\n", nv_getval(np)); 2298462SApril.Chin@Sun.COM sh_exit(0); 2304887Schin #endif 2318462SApril.Chin@Sun.COM case -6: /* --default */ 2328462SApril.Chin@Sun.COM { 2338462SApril.Chin@Sun.COM register const Shtable_t *tp; 2348462SApril.Chin@Sun.COM for(tp=shtab_options; o = tp->sh_number; tp++) 2358462SApril.Chin@Sun.COM if(!(o&SH_COMMANDLINE) && is_option(&newflags,o&0xff)) 2368462SApril.Chin@Sun.COM off_option(&newflags,o&0xff); 2378462SApril.Chin@Sun.COM } 2388462SApril.Chin@Sun.COM continue; 2398462SApril.Chin@Sun.COM case -7: 2408462SApril.Chin@Sun.COM f = 0; 2418462SApril.Chin@Sun.COM goto byname; 2424887Schin case 'D': 2434887Schin on_option(&newflags,SH_NOEXEC); 2444887Schin goto skip; 2458462SApril.Chin@Sun.COM case 'T': 2468462SApril.Chin@Sun.COM if (opt_info.num) 2478462SApril.Chin@Sun.COM ap->sh->test |= opt_info.num; 2488462SApril.Chin@Sun.COM else 2498462SApril.Chin@Sun.COM ap->sh->test = 0; 2508462SApril.Chin@Sun.COM continue; 2514887Schin case 's': 2524887Schin if(setflag) 2534887Schin { 2544887Schin action = SORT; 2554887Schin continue; 2564887Schin } 2574887Schin #if SHOPT_KIA 2584887Schin goto skip; 2594887Schin case 'R': 2604887Schin if(setflag) 2614887Schin n = ':'; 2624887Schin else 2634887Schin { 2644887Schin ap->kiafile = opt_info.arg; 2654887Schin n = 'n'; 2664887Schin } 267*10898Sroland.mainz@nrubsig.org /*FALLTHROUGH*/ 2684887Schin #endif /* SHOPT_KIA */ 269*10898Sroland.mainz@nrubsig.org #if SHOPT_REGRESS 270*10898Sroland.mainz@nrubsig.org goto skip; 271*10898Sroland.mainz@nrubsig.org case 'I': 272*10898Sroland.mainz@nrubsig.org continue; 273*10898Sroland.mainz@nrubsig.org #endif /* SHOPT_REGRESS */ 2744887Schin skip: 2754887Schin default: 2764887Schin if(cp=strchr(optksh,n)) 2774887Schin o = flagval[cp-optksh]; 2784887Schin break; 2794887Schin case ':': 2804887Schin if(opt_info.name[0]=='-'&&opt_info.name[1]=='-') 2814887Schin { 2824887Schin opt_info.arg = argv[opt_info.index-1] + 2; 2834887Schin f = 1; 2844887Schin goto byname; 2854887Schin } 2864887Schin errormsg(SH_DICT,2, "%s", opt_info.arg); 2874887Schin continue; 2884887Schin case '?': 2894887Schin errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); 2904887Schin return(-1); 2914887Schin } 2924887Schin if(f) 2934887Schin { 2944887Schin if(o==SH_VI || o==SH_EMACS || o==SH_GMACS) 2954887Schin { 2964887Schin off_option(&newflags,SH_VI); 2974887Schin off_option(&newflags,SH_EMACS); 2984887Schin off_option(&newflags,SH_GMACS); 2994887Schin } 3004887Schin on_option(&newflags,o); 3018462SApril.Chin@Sun.COM off_option(&ap->sh->offoptions,o); 3024887Schin } 3034887Schin else 3044887Schin { 3054887Schin if(o==SH_XTRACE) 3064887Schin trace = 0; 3074887Schin off_option(&newflags,o); 3084887Schin if(setflag==0) 3098462SApril.Chin@Sun.COM on_option(&ap->sh->offoptions,o); 3104887Schin } 3114887Schin } 3124887Schin if(error_info.errors) 3134887Schin errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*))); 3144887Schin /* check for '-' or '+' argument */ 3154887Schin if((cp=argv[opt_info.index]) && cp[1]==0 && (*cp=='+' || *cp=='-') && 3164887Schin strcmp(argv[opt_info.index-1],"--")) 3174887Schin { 3184887Schin opt_info.index++; 3194887Schin off_option(&newflags,SH_XTRACE); 3204887Schin off_option(&newflags,SH_VERBOSE); 3214887Schin trace = 0; 3224887Schin } 3234887Schin if(trace) 3244887Schin sh_trace(argv,1); 3254887Schin argc -= opt_info.index; 3264887Schin argv += opt_info.index; 3274887Schin if(action==PRINT) 3284887Schin sh_printopts(newflags,verbose,0); 3294887Schin if(setflag) 3304887Schin { 3314887Schin if(action==SORT) 3324887Schin { 3334887Schin if(argc>0) 3344887Schin strsort(argv,argc,strcoll); 3354887Schin else 3368462SApril.Chin@Sun.COM strsort(ap->sh->st.dolv+1,ap->sh->st.dolc,strcoll); 3374887Schin } 3384887Schin if(np) 3394887Schin { 3404887Schin nv_setvec(np,0,argc,argv); 3414887Schin nv_close(np); 3424887Schin } 3434887Schin else if(argc>0 || ((cp=argv[-1]) && strcmp(cp,"--")==0)) 3448462SApril.Chin@Sun.COM sh_argset(ap,argv-1); 3454887Schin } 3464887Schin else if(is_option(&newflags,SH_CFLAG)) 3474887Schin { 3488462SApril.Chin@Sun.COM if(!(ap->sh->comdiv = *argv++)) 3494887Schin { 3504887Schin errormsg(SH_DICT,2,e_cneedsarg); 3514887Schin errormsg(SH_DICT,ERROR_usage(2),optusage(NIL(char*))); 3524887Schin } 3534887Schin argc--; 3544887Schin } 3554887Schin /* handling SH_INTERACTIVE and SH_PRIVILEGED has been moved to 3564887Schin * sh_applyopts(), so that the code can be reused from b_shopt(), too 3574887Schin */ 3588462SApril.Chin@Sun.COM sh_applyopts(ap->sh,newflags); 3594887Schin #if SHOPT_KIA 3604887Schin if(ap->kiafile) 3614887Schin { 3628462SApril.Chin@Sun.COM if(!argv[0]) 3638462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_usage(2),"-R requires scriptname"); 3648462SApril.Chin@Sun.COM if(!(lp->kiafile=sfopen(NIL(Sfio_t*),ap->kiafile,"w+"))) 3654887Schin errormsg(SH_DICT,ERROR_system(3),e_create,ap->kiafile); 3668462SApril.Chin@Sun.COM if(!(lp->kiatmp=sftmp(2*SF_BUFSIZE))) 3674887Schin errormsg(SH_DICT,ERROR_system(3),e_tmpcreate); 3688462SApril.Chin@Sun.COM sfputr(lp->kiafile,";vdb;CIAO/ksh",'\n'); 3698462SApril.Chin@Sun.COM lp->kiabegin = sftell(lp->kiafile); 3708462SApril.Chin@Sun.COM lp->entity_tree = dtopen(&_Nvdisc,Dtbag); 3718462SApril.Chin@Sun.COM lp->scriptname = strdup(sh_fmtq(argv[0])); 3728462SApril.Chin@Sun.COM lp->script=kiaentity(lp,lp->scriptname,-1,'p',-1,0,0,'s',0,""); 3738462SApril.Chin@Sun.COM lp->fscript=kiaentity(lp,lp->scriptname,-1,'f',-1,0,0,'s',0,""); 3748462SApril.Chin@Sun.COM lp->unknown=kiaentity(lp,"<unknown>",-1,'p',-1,0,0,'0',0,""); 3758462SApril.Chin@Sun.COM kiaentity(lp,"<unknown>",-1,'p',0,0,lp->unknown,'0',0,""); 3768462SApril.Chin@Sun.COM lp->current = lp->script; 3774887Schin ap->kiafile = 0; 3784887Schin } 3794887Schin #endif /* SHOPT_KIA */ 3804887Schin return(argc); 3814887Schin } 3824887Schin 3834887Schin /* apply new options */ 3844887Schin 3858462SApril.Chin@Sun.COM void sh_applyopts(Shell_t* shp,Shopt_t newflags) 3864887Schin { 3874887Schin /* cannot set -n for interactive shells since there is no way out */ 3884887Schin if(sh_isoption(SH_INTERACTIVE)) 3894887Schin off_option(&newflags,SH_NOEXEC); 3904887Schin if(is_option(&newflags,SH_PRIVILEGED)) 3914887Schin on_option(&newflags,SH_NOUSRPROFILE); 392*10898Sroland.mainz@nrubsig.org if(!sh_isstate(SH_INIT) && is_option(&newflags,SH_PRIVILEGED) != sh_isoption(SH_PRIVILEGED) || sh_isstate(SH_INIT) && is_option(&((Arg_t*)shp->arg_context)->sh->offoptions,SH_PRIVILEGED) && shp->userid!=shp->euserid) 3934887Schin { 394*10898Sroland.mainz@nrubsig.org if(!is_option(&newflags,SH_PRIVILEGED)) 3954887Schin { 3968462SApril.Chin@Sun.COM setuid(shp->userid); 3978462SApril.Chin@Sun.COM setgid(shp->groupid); 3988462SApril.Chin@Sun.COM if(shp->euserid==0) 3994887Schin { 4008462SApril.Chin@Sun.COM shp->euserid = shp->userid; 4018462SApril.Chin@Sun.COM shp->egroupid = shp->groupid; 4024887Schin } 4034887Schin } 4048462SApril.Chin@Sun.COM else if((shp->userid!=shp->euserid && setuid(shp->euserid)<0) || 4058462SApril.Chin@Sun.COM (shp->groupid!=shp->egroupid && setgid(shp->egroupid)<0) || 4068462SApril.Chin@Sun.COM (shp->userid==shp->euserid && shp->groupid==shp->egroupid)) 4074887Schin off_option(&newflags,SH_PRIVILEGED); 4084887Schin } 4094887Schin #if SHOPT_BASH 4104887Schin on_option(&newflags,SH_CMDHIST); 4114887Schin on_option(&newflags,SH_CHECKHASH); 4124887Schin on_option(&newflags,SH_EXECFAIL); 4134887Schin on_option(&newflags,SH_EXPAND_ALIASES); 4144887Schin on_option(&newflags,SH_HISTAPPEND); 4154887Schin on_option(&newflags,SH_INTERACTIVE_COMM); 4164887Schin on_option(&newflags,SH_LITHIST); 4174887Schin on_option(&newflags,SH_NOEMPTYCMDCOMPL); 4184887Schin 4194887Schin if(!is_option(&newflags,SH_XPG_ECHO) && sh_isoption(SH_XPG_ECHO)) 4204887Schin astconf("UNIVERSE", 0, "ucb"); 4214887Schin if(is_option(&newflags,SH_XPG_ECHO) && !sh_isoption(SH_XPG_ECHO)) 4224887Schin astconf("UNIVERSE", 0, "att"); 4234887Schin if(!is_option(&newflags,SH_PHYSICAL) && sh_isoption(SH_PHYSICAL)) 4244887Schin astconf("PATH_RESOLVE", 0, "metaphysical"); 4254887Schin if(is_option(&newflags,SH_PHYSICAL) && !sh_isoption(SH_PHYSICAL)) 4264887Schin astconf("PATH_RESOLVE", 0, "physical"); 4274887Schin if(is_option(&newflags,SH_HISTORY2) && !sh_isoption(SH_HISTORY2)) 4284887Schin { 4294887Schin sh_onstate(SH_HISTORY); 4304887Schin sh_onoption(SH_HISTORY); 4314887Schin } 4324887Schin if(!is_option(&newflags,SH_HISTORY2) && sh_isoption(SH_HISTORY2)) 4334887Schin { 4344887Schin sh_offstate(SH_HISTORY); 4354887Schin sh_offoption(SH_HISTORY); 4364887Schin } 4374887Schin #endif 4388462SApril.Chin@Sun.COM shp->options = newflags; 4394887Schin } 4408462SApril.Chin@Sun.COM 4414887Schin /* 4424887Schin * returns the value of $- 4434887Schin */ 4448462SApril.Chin@Sun.COM char *sh_argdolminus(void* context) 4454887Schin { 4468462SApril.Chin@Sun.COM register Arg_t *ap = (Arg_t*)context; 4474887Schin register const char *cp=optksh; 4484887Schin register char *flagp=ap->flagadr; 4494887Schin while(cp< &optksh[NUM_OPTS]) 4504887Schin { 4514887Schin int n = flagval[cp-optksh]; 4524887Schin if(sh_isoption(n)) 4534887Schin *flagp++ = *cp; 4544887Schin cp++; 4554887Schin } 4564887Schin *flagp = 0; 4574887Schin return(ap->flagadr); 4584887Schin } 4594887Schin 4604887Schin /* 4614887Schin * set up positional parameters 4624887Schin */ 4638462SApril.Chin@Sun.COM static void sh_argset(Arg_t *ap,char *argv[]) 4644887Schin { 4658462SApril.Chin@Sun.COM sh_argfree(ap->sh,ap->dolh,0); 4664887Schin ap->dolh = sh_argcreate(argv); 4674887Schin /* link into chain */ 4684887Schin ap->dolh->dolnxt = ap->argfor; 4694887Schin ap->argfor = ap->dolh; 4708462SApril.Chin@Sun.COM ap->sh->st.dolc = ap->dolh->dolnum-1; 4718462SApril.Chin@Sun.COM ap->sh->st.dolv = ap->dolh->dolval; 4724887Schin } 4734887Schin 4744887Schin /* 4754887Schin * free the argument list if the use count is 1 4764887Schin * If count is greater than 1 decrement count and return same blk 4774887Schin * Free the argument list if the use count is 1 and return next blk 4784887Schin * Delete the blk from the argfor chain 4794887Schin * If flag is set, then the block dolh is not freed 4804887Schin */ 4818462SApril.Chin@Sun.COM struct dolnod *sh_argfree(Shell_t *shp, struct dolnod *blk,int flag) 4824887Schin { 4834887Schin register struct dolnod* argr=blk; 4844887Schin register struct dolnod* argblk; 4858462SApril.Chin@Sun.COM register Arg_t *ap = (Arg_t*)shp->arg_context; 4864887Schin if(argblk=argr) 4874887Schin { 4884887Schin if((--argblk->dolrefcnt)==0) 4894887Schin { 4904887Schin argr = argblk->dolnxt; 4914887Schin if(flag && argblk==ap->dolh) 4924887Schin ap->dolh->dolrefcnt = 1; 4934887Schin else 4944887Schin { 4954887Schin /* delete from chain */ 4964887Schin if(ap->argfor == argblk) 4974887Schin ap->argfor = argblk->dolnxt; 4984887Schin else 4994887Schin { 5004887Schin for(argr=ap->argfor;argr;argr=argr->dolnxt) 5014887Schin if(argr->dolnxt==argblk) 5024887Schin break; 5034887Schin if(!argr) 5044887Schin return(NIL(struct dolnod*)); 5054887Schin argr->dolnxt = argblk->dolnxt; 5064887Schin argr = argblk->dolnxt; 5074887Schin } 5084887Schin free((void*)argblk); 5094887Schin } 5104887Schin } 5114887Schin } 5124887Schin return(argr); 5134887Schin } 5144887Schin 5154887Schin /* 5164887Schin * grab space for arglist and copy args 5174887Schin * The strings are copied after the argment vector 5184887Schin */ 5194887Schin struct dolnod *sh_argcreate(register char *argv[]) 5204887Schin { 5214887Schin register struct dolnod *dp; 5224887Schin register char **pp=argv, *sp; 5234887Schin register int size=0,n; 5244887Schin /* count args and number of bytes of arglist */ 5254887Schin while(sp= *pp++) 5264887Schin size += strlen(sp); 5274887Schin n = (pp - argv)-1; 5284887Schin dp=new_of(struct dolnod,n*sizeof(char*)+size+n); 5294887Schin dp->dolrefcnt=1; /* use count */ 5304887Schin dp->dolnum = n; 5314887Schin dp->dolnxt = 0; 5324887Schin pp = dp->dolval; 5334887Schin sp = (char*)dp + sizeof(struct dolnod) + n*sizeof(char*); 5344887Schin while(n--) 5354887Schin { 5364887Schin *pp++ = sp; 5374887Schin sp = strcopy(sp, *argv++) + 1; 5384887Schin } 5394887Schin *pp = NIL(char*); 5404887Schin return(dp); 5414887Schin } 5424887Schin 5434887Schin /* 5444887Schin * used to set new arguments for functions 5454887Schin */ 5468462SApril.Chin@Sun.COM struct dolnod *sh_argnew(Shell_t *shp,char *argi[], struct dolnod **savargfor) 5474887Schin { 5488462SApril.Chin@Sun.COM register Arg_t *ap = (Arg_t*)shp->arg_context; 5494887Schin register struct dolnod *olddolh = ap->dolh; 5504887Schin *savargfor = ap->argfor; 5514887Schin ap->dolh = 0; 5524887Schin ap->argfor = 0; 5538462SApril.Chin@Sun.COM sh_argset(ap,argi); 5544887Schin return(olddolh); 5554887Schin } 5564887Schin 5574887Schin /* 5584887Schin * reset arguments as they were before function 5594887Schin */ 5608462SApril.Chin@Sun.COM void sh_argreset(Shell_t *shp,struct dolnod *blk, struct dolnod *afor) 5614887Schin { 5628462SApril.Chin@Sun.COM register Arg_t *ap = (Arg_t*)shp->arg_context; 5638462SApril.Chin@Sun.COM while(ap->argfor=sh_argfree(shp,ap->argfor,0)); 5644887Schin ap->argfor = afor; 5654887Schin if(ap->dolh = blk) 5664887Schin { 5678462SApril.Chin@Sun.COM shp->st.dolc = ap->dolh->dolnum-1; 5688462SApril.Chin@Sun.COM shp->st.dolv = ap->dolh->dolval; 5694887Schin } 5704887Schin } 5714887Schin 5724887Schin /* 5734887Schin * increase the use count so that an sh_argset will not make it go away 5744887Schin */ 5758462SApril.Chin@Sun.COM struct dolnod *sh_arguse(Shell_t* shp) 5764887Schin { 5774887Schin register struct dolnod *dh; 5788462SApril.Chin@Sun.COM register Arg_t *ap = (Arg_t*)shp->arg_context; 5794887Schin if(dh=ap->dolh) 5804887Schin dh->dolrefcnt++; 5814887Schin return(dh); 5824887Schin } 5834887Schin 5844887Schin /* 5854887Schin * Print option settings on standard output 5864887Schin * if mode is inclusive or of PRINT_* 5874887Schin * if <mask> is set, only options with this mask value are displayed 5884887Schin */ 5894887Schin void sh_printopts(Shopt_t oflags,register int mode, Shopt_t *mask) 5904887Schin { 5914887Schin register const Shtable_t *tp; 5924887Schin const char *name; 5934887Schin int on; 5944887Schin int value; 5954887Schin if(!(mode&PRINT_NO_HEADER)) 5964887Schin sfputr(sfstdout,sh_translate(e_heading),'\n'); 5974887Schin if(mode&PRINT_TABLE) 5984887Schin { 5994887Schin int w; 6004887Schin int c; 6014887Schin int r; 6024887Schin int i; 6034887Schin 6044887Schin c = 0; 6054887Schin for(tp=shtab_options; value=tp->sh_number; tp++) 6064887Schin { 6074887Schin if(mask && !is_option(mask,value&0xff)) 6084887Schin continue; 6094887Schin name = tp->sh_name; 6104887Schin if(name[0] == 'n' && name[1] == 'o' && name[2] != 't') 6114887Schin name += 2; 6124887Schin if(c<(w=strlen(name))) 6134887Schin c = w; 6144887Schin } 6154887Schin c += 4; 6164887Schin if((w = ed_window()) < (2*c)) 6174887Schin w = 2*c; 6184887Schin r = w / c; 6194887Schin i = 0; 6204887Schin for(tp=shtab_options; value=tp->sh_number; tp++) 6214887Schin { 6224887Schin if(mask && !is_option(mask,value&0xff)) 6234887Schin continue; 6244887Schin on = !!is_option(&oflags,value); 6254887Schin value &= 0xff; 6264887Schin name = tp->sh_name; 6274887Schin if(name[0] == 'n' && name[1] == 'o' && name[2] != 't') 6284887Schin { 6294887Schin name += 2; 6304887Schin on = !on; 6314887Schin } 6324887Schin if(++i>=r) 6334887Schin { 6344887Schin i = 0; 6354887Schin sfprintf(sfstdout, "%s%s\n", on ? "" : "no", name); 6364887Schin } 6374887Schin else 6384887Schin sfprintf(sfstdout, "%s%-*s", on ? "" : "no", on ? c : (c-2), name); 6394887Schin } 6404887Schin if(i) 6414887Schin sfputc(sfstdout,'\n'); 6424887Schin return; 6434887Schin } 6444887Schin #if SHOPT_RAWONLY 6454887Schin on_option(&oflags,SH_VIRAW); 6464887Schin #endif 6474887Schin if(!(mode&(PRINT_ALL|PRINT_VERBOSE))) /* only print set options */ 6484887Schin { 6494887Schin if(mode&PRINT_SHOPT) 6504887Schin sfwrite(sfstdout,"shopt -s",3); 6514887Schin else 6528462SApril.Chin@Sun.COM sfwrite(sfstdout,"set --default",13); 6534887Schin } 6544887Schin for(tp=shtab_options; value=tp->sh_number; tp++) 6554887Schin { 6564887Schin if(mask && !is_option(mask,value&0xff)) 6574887Schin continue; 6584887Schin if(sh_isoption(SH_BASH)) 6594887Schin { 6604887Schin if (!(mode&PRINT_SHOPT) != !(value&SH_BASHOPT)) 6614887Schin continue; 6624887Schin } 6634887Schin else if (value&(SH_BASHEXTRA|SH_BASHOPT)) 6644887Schin continue; 6654887Schin on = !!is_option(&oflags,value); 6664887Schin name = tp->sh_name; 6674887Schin if(name[0] == 'n' && name[1] == 'o' && name[2] != 't') 6684887Schin { 6694887Schin name += 2; 6704887Schin on = !on; 6714887Schin } 6724887Schin if(mode&PRINT_VERBOSE) 6734887Schin { 6744887Schin sfputr(sfstdout,name,' '); 6754887Schin sfnputc(sfstdout,' ',24-strlen(name)); 6764887Schin sfputr(sfstdout,on ? sh_translate(e_on) : sh_translate(e_off),'\n'); 6774887Schin } 6784887Schin else if(mode&PRINT_ALL) /* print unset options also */ 6794887Schin { 6804887Schin if(mode&PRINT_SHOPT) 6814887Schin sfprintf(sfstdout, "shopt -%c %s\n", 6824887Schin on?'s':'u', 6834887Schin name); 6844887Schin else 6854887Schin sfprintf(sfstdout, "set %co %s\n", 6864887Schin on?'-':'+', 6874887Schin name); 6884887Schin } 6894887Schin else if(!(value&SH_COMMANDLINE) && is_option(&oflags,value&0xff)) 6904887Schin sfprintf(sfstdout," %s%s%s",(mode&PRINT_SHOPT)?"":"--",on?"":"no",name); 6914887Schin } 6924887Schin if(!(mode&(PRINT_VERBOSE|PRINT_ALL))) 6934887Schin sfputc(sfstdout,'\n'); 6944887Schin } 6954887Schin 6964887Schin /* 6974887Schin * build an argument list 6984887Schin */ 6998462SApril.Chin@Sun.COM char **sh_argbuild(Shell_t *shp,int *nargs, const struct comnod *comptr,int flag) 7004887Schin { 7014887Schin register struct argnod *argp; 7024887Schin struct argnod *arghead=0; 7038462SApril.Chin@Sun.COM shp->xargmin = 0; 7044887Schin { 7054887Schin register const struct comnod *ac = comptr; 7064887Schin register int n; 7074887Schin /* see if the arguments have already been expanded */ 7084887Schin if(!ac->comarg) 7094887Schin { 7104887Schin *nargs = 0; 7114887Schin return(&null); 7124887Schin } 7134887Schin else if(!(ac->comtyp&COMSCAN)) 7144887Schin { 7154887Schin register struct dolnod *ap = (struct dolnod*)ac->comarg; 7164887Schin *nargs = ap->dolnum; 7174887Schin return(ap->dolval+ap->dolbot); 7184887Schin } 7198462SApril.Chin@Sun.COM shp->lastpath = 0; 7204887Schin *nargs = 0; 7214887Schin if(ac) 7224887Schin { 7234887Schin if(ac->comnamp == SYSLET) 7244887Schin flag |= ARG_LET; 7254887Schin argp = ac->comarg; 7264887Schin while(argp) 7274887Schin { 7288462SApril.Chin@Sun.COM n = arg_expand(shp,argp,&arghead,flag); 7294887Schin if(n>1) 7304887Schin { 7318462SApril.Chin@Sun.COM if(shp->xargmin==0) 7328462SApril.Chin@Sun.COM shp->xargmin = *nargs; 7338462SApril.Chin@Sun.COM shp->xargmax = *nargs+n; 7344887Schin } 7354887Schin *nargs += n; 7364887Schin argp = argp->argnxt.ap; 7374887Schin } 7384887Schin argp = arghead; 7394887Schin } 7404887Schin } 7414887Schin { 7424887Schin register char **comargn; 7434887Schin register int argn; 7444887Schin register char **comargm; 7454887Schin argn = *nargs; 7464887Schin /* allow room to prepend args */ 7474887Schin argn += 1; 7484887Schin 7498462SApril.Chin@Sun.COM comargn=(char**)stkalloc(shp->stk,(unsigned)(argn+1)*sizeof(char*)); 7504887Schin comargm = comargn += argn; 7514887Schin *comargn = NIL(char*); 7524887Schin if(!argp) 7534887Schin { 7544887Schin /* reserve an extra null pointer */ 7554887Schin *--comargn = 0; 7564887Schin return(comargn); 7574887Schin } 7584887Schin while(argp) 7594887Schin { 7604887Schin struct argnod *nextarg = argp->argchn.ap; 7614887Schin argp->argchn.ap = 0; 7624887Schin *--comargn = argp->argval; 7634887Schin if(!(argp->argflag&ARG_RAW)) 7644887Schin sh_trim(*comargn); 7654887Schin if(!(argp=nextarg) || (argp->argflag&ARG_MAKE)) 7664887Schin { 7674887Schin if((argn=comargm-comargn)>1) 7684887Schin strsort(comargn,argn,strcoll); 7694887Schin comargm = comargn; 7704887Schin } 7714887Schin } 7728462SApril.Chin@Sun.COM shp->last_table = 0; 7734887Schin return(comargn); 7744887Schin } 7754887Schin } 7764887Schin 7774887Schin #if _pipe_socketpair && !_socketpair_devfd 7784887Schin # define sh_pipe arg_pipe 7794887Schin /* 7804887Schin * create a real pipe (not a socket) and print message on failure 7814887Schin */ 7824887Schin static int arg_pipe(register int pv[]) 7834887Schin { 7844887Schin int fd[2]; 7854887Schin if(pipe(fd)<0 || (pv[0]=fd[0])<0 || (pv[1]=fd[1])<0) 7864887Schin errormsg(SH_DICT,ERROR_system(1),e_pipe); 7874887Schin pv[0] = sh_iomovefd(pv[0]); 7884887Schin pv[1] = sh_iomovefd(pv[1]); 7894887Schin sh.fdstatus[pv[0]] = IONOSEEK|IOREAD; 7904887Schin sh.fdstatus[pv[1]] = IONOSEEK|IOWRITE; 7914887Schin sh_subsavefd(pv[0]); 7924887Schin sh_subsavefd(pv[1]); 7934887Schin return(0); 7944887Schin } 7954887Schin #endif 7964887Schin 797*10898Sroland.mainz@nrubsig.org struct argnod *sh_argprocsub(Shell_t *shp,struct argnod *argp) 798*10898Sroland.mainz@nrubsig.org { 799*10898Sroland.mainz@nrubsig.org /* argument of the form <(cmd) or >(cmd) */ 800*10898Sroland.mainz@nrubsig.org register struct argnod *ap; 801*10898Sroland.mainz@nrubsig.org int monitor, fd, pv[2]; 802*10898Sroland.mainz@nrubsig.org int subshell = shp->subshell; 803*10898Sroland.mainz@nrubsig.org ap = (struct argnod*)stkseek(shp->stk,ARGVAL); 804*10898Sroland.mainz@nrubsig.org ap->argflag |= ARG_MAKE; 805*10898Sroland.mainz@nrubsig.org ap->argflag &= ~ARG_RAW; 806*10898Sroland.mainz@nrubsig.org sfwrite(shp->stk,e_devfdNN,8); 807*10898Sroland.mainz@nrubsig.org sh_pipe(pv); 808*10898Sroland.mainz@nrubsig.org fd = argp->argflag&ARG_RAW; 809*10898Sroland.mainz@nrubsig.org sfputr(shp->stk,fmtbase((long)pv[fd],10,0),0); 810*10898Sroland.mainz@nrubsig.org ap = (struct argnod*)stkfreeze(shp->stk,0); 811*10898Sroland.mainz@nrubsig.org shp->inpipe = shp->outpipe = 0; 812*10898Sroland.mainz@nrubsig.org if(monitor = (sh_isstate(SH_MONITOR)!=0)) 813*10898Sroland.mainz@nrubsig.org sh_offstate(SH_MONITOR); 814*10898Sroland.mainz@nrubsig.org shp->subshell = 0; 815*10898Sroland.mainz@nrubsig.org if(fd) 816*10898Sroland.mainz@nrubsig.org { 817*10898Sroland.mainz@nrubsig.org shp->inpipe = pv; 818*10898Sroland.mainz@nrubsig.org sh_exec((Shnode_t*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT)); 819*10898Sroland.mainz@nrubsig.org } 820*10898Sroland.mainz@nrubsig.org else 821*10898Sroland.mainz@nrubsig.org { 822*10898Sroland.mainz@nrubsig.org shp->outpipe = pv; 823*10898Sroland.mainz@nrubsig.org sh_exec((Shnode_t*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT)); 824*10898Sroland.mainz@nrubsig.org } 825*10898Sroland.mainz@nrubsig.org shp->subshell = subshell; 826*10898Sroland.mainz@nrubsig.org if(monitor) 827*10898Sroland.mainz@nrubsig.org sh_onstate(SH_MONITOR); 828*10898Sroland.mainz@nrubsig.org close(pv[1-fd]); 829*10898Sroland.mainz@nrubsig.org sh_iosave(shp,-pv[fd], shp->topfd, (char*)0); 830*10898Sroland.mainz@nrubsig.org return(ap); 831*10898Sroland.mainz@nrubsig.org } 832*10898Sroland.mainz@nrubsig.org 8334887Schin /* Argument expansion */ 8348462SApril.Chin@Sun.COM static int arg_expand(Shell_t *shp,register struct argnod *argp, struct argnod **argchain,int flag) 8354887Schin { 8364887Schin register int count = 0; 8374887Schin argp->argflag &= ~ARG_MAKE; 8384887Schin #if SHOPT_DEVFD 8394887Schin if(*argp->argval==0 && (argp->argflag&ARG_EXP)) 8404887Schin { 841*10898Sroland.mainz@nrubsig.org struct argnod *ap; 842*10898Sroland.mainz@nrubsig.org ap = sh_argprocsub(shp,argp); 8434887Schin ap->argchn.ap = *argchain; 8444887Schin *argchain = ap; 8454887Schin count++; 8464887Schin } 8474887Schin else 8484887Schin #endif /* SHOPT_DEVFD */ 8494887Schin if(!(argp->argflag&ARG_RAW)) 8504887Schin { 8514887Schin #if SHOPT_OPTIMIZE 8524887Schin struct argnod *ap; 8538462SApril.Chin@Sun.COM sh_stats(STAT_ARGEXPAND); 8544887Schin if(flag&ARG_OPTIMIZE) 8554887Schin argp->argchn.ap=0; 8564887Schin if(ap=argp->argchn.ap) 8574887Schin { 8588462SApril.Chin@Sun.COM sh_stats(STAT_ARGHITS); 8594887Schin count = 1; 8604887Schin ap->argchn.ap = *argchain; 8614887Schin ap->argflag |= ARG_RAW; 8624887Schin ap->argflag &= ~ARG_EXP; 8634887Schin *argchain = ap; 8644887Schin } 8654887Schin else 8664887Schin #endif /* SHOPT_OPTIMIZE */ 8678462SApril.Chin@Sun.COM count = sh_macexpand(shp,argp,argchain,flag); 8684887Schin } 8694887Schin else 8704887Schin { 8714887Schin argp->argchn.ap = *argchain; 8724887Schin *argchain = argp; 8734887Schin argp->argflag |= ARG_MAKE; 8744887Schin count++; 8754887Schin } 8764887Schin return(count); 8774887Schin } 8784887Schin 879