Beispiel #1
0
Datei: misc.c Projekt: att/ast
int b_eval(int argc, char *argv[], Shbltin_t *context) {
    int r;
    Shell_t *shp = context->shp;
    UNUSED(argc);

    while ((r = optget(argv, sh_opteval))) {
        switch (r) {
            case ':': {
                errormsg(SH_DICT, 2, "%s", opt_info.arg);
                break;
            }
            case '?': {
                errormsg(SH_DICT, ERROR_usage(0), "%s", opt_info.arg);
                return 2;
            }
            default: { break; }
        }
    }

    if (error_info.errors) {
        errormsg(SH_DICT, ERROR_usage(2), "%s", optusage(NULL));
        __builtin_unreachable();
    }
    argv += opt_info.index;
    if (*argv && **argv) {
        sh_offstate(shp, SH_MONITOR);
        sh_eval(shp, sh_sfeval((const char **)argv), 0);
    }
    return shp->exitval;
}
Beispiel #2
0
static int read_tree(Namval_t* np, Sfio_t *iop, int n, Namfun_t *dp)
{
	Sfio_t	*sp;
	char	*cp;
	int	c;
	if(n>=0)
		return(-1);
	while((c = sfgetc(iop)) &&  isblank(c));
	sfungetc(iop,c);
	sfprintf(sh.strbuf,"%s=%c",nv_name(np),0);
	cp = sfstruse(sh.strbuf);
	sp = sfopen((Sfio_t*)0,cp,"s");
	sfstack(iop,sp);
	c=sh_eval(iop,SH_READEVAL);
	return(c);
}
Beispiel #3
0
int Tcl_SplitList(Tcl_Interp *interp, char *list, int *argcPtr, char ***argvPtr)
{
	int result = TCL_ERROR;
	FILE *str;
	static TkshArgcArgv argstruct, *args = &argstruct;
	char *command;
	static int init=0;

#ifndef NO_TCL_EVAL
	if (TkshListMode() == INTERP_TCL)
                return Tcl_TclSplitList(interp, list, argcPtr, argvPtr);
#endif

	if (! init)
	{
		sh_addbuiltin(SPLIT_CMD_NAME, tksh_cmd_split, (void *) args);
		init = 1;
	}

	command = (char *) malloc(strlen(list)+strlen(SPLIT_CMD_NAME)+2);
	dprintf2(("Splitting...\n"));
	if (args && command)
	{
		sprintf(command, "%s %s",SPLIT_CMD_NAME, list);

		args->argcPtr = argcPtr;
		args->argvPtr = argvPtr;

		if ((str = sfopen((Sfio_t *) 0, command, "s")))
		{
			sh_eval(str, 0x8000);
			sfclose(str);
			result = Tksh_OkOrErr();
		}
		free(command);
	}

	return result;
}
Beispiel #4
0
int    b_eval(int argc,char *argv[], void *extra)
{
	register int r;
	register Shell_t *shp = ((Shbltin_t*)extra)->shp;
	NOT_USED(argc);
	while (r = optget(argv,sh_opteval)) switch (r)
	{
	    case ':':
		errormsg(SH_DICT,2, "%s", opt_info.arg);
		break;
	    case '?':
		errormsg(SH_DICT,ERROR_usage(0), "%s",opt_info.arg);
		return(2);
	}
	if(error_info.errors)
		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
	argv += opt_info.index;
	if(*argv && **argv)
	{
		sh_offstate(SH_MONITOR);
		sh_eval(sh_sfeval(argv),0);
	}
	return(shp->exitval);
}
Beispiel #5
0
int	b_hist(int argc,char *argv[], void *extra)
{
	register History_t *hp;
	register char *arg;
	register int flag,fdo;
	register Shell_t *shp = ((Shbltin_t*)extra)->shp;
	Sfio_t *outfile;
	char *fname;
	int range[2], incr, index2, indx= -1;
	char *edit = 0;		/* name of editor */
	char *replace = 0;		/* replace old=new */
	int lflag = 0, nflag = 0, rflag = 0;
#if SHOPT_HISTEXPAND
	int pflag = 0;
#endif
	Histloc_t location;
	NOT_USED(argc);
	if(!sh_histinit((void*)shp))
		errormsg(SH_DICT,ERROR_system(1),e_histopen);
	hp = shp->gd->hist_ptr;
	while((flag = optget(argv,sh_opthist))) switch(flag)
	{
	    case 'e':
		edit = opt_info.arg;
		break;
	    case 'n':
		nflag++;
		break;
	    case 'l':
		lflag++;
		break;
	    case 'r':
		rflag++;
		break;
	    case 's':
		edit = "-";
		break;
#if SHOPT_HISTEXPAND
	    case 'p':
		pflag++;
		break;
#endif
	    case 'N':
		if(indx<=0)
		{
			if((flag = hist_max(hp) - opt_info.num-1) < 0)
				flag = 1;
			range[++indx] = flag;
			break;
		}
	    case ':':
		errormsg(SH_DICT,2, "%s", opt_info.arg);
		break;
	    case '?':
		errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
		break;
	}
	if(error_info.errors)
		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
	argv += (opt_info.index-1);
#if SHOPT_HISTEXPAND
	if(pflag)
	{
		hist_cancel(hp);
		pflag = 0;
		while(arg=argv[1])
		{
			flag = hist_expand(arg,&replace);
			if(!(flag & HIST_ERROR))
				sfputr(sfstdout, replace, '\n');
			else
				pflag = 1;
			if(replace)
				free(replace);
			argv++;
		}
		return pflag;
	}
#endif
	flag = indx;
	while(flag<1 && (arg=argv[1]))
	{
		/* look for old=new argument */
		if(!replace && strchr(arg+1,'='))
		{
			replace = arg;
			argv++;
			continue;
		}
		else if(isdigit(*arg) || *arg == '-')
		{
			/* see if completely numeric */
			do	arg++;
			while(isdigit(*arg));
			if(*arg==0)
			{
				arg = argv[1];
				range[++flag] = (int)strtol(arg, (char**)0, 10);
				if(*arg == '-')
					range[flag] += (hist_max(hp)-1);
				argv++;
				continue;
			}
		}
		/* search for last line starting with string */
		location = hist_find(hp,argv[1],hist_max(hp)-1,0,-1);
		if((range[++flag] = location.hist_command) < 0)
			errormsg(SH_DICT,ERROR_exit(1),e_found,argv[1]);
		argv++;
	}
	if(flag <0)
	{
		/* set default starting range */
		if(lflag)
		{
			flag = hist_max(hp)-16;
			if(flag<1)
				flag = 1;
		}
		else
			flag = hist_max(hp)-2;
		range[0] = flag;
		flag = 0;
	}
	index2 = hist_min(hp);
	if(range[0]<index2)
		range[0] = index2;
	if(flag==0)
		/* set default termination range */
		range[1] = ((lflag && !edit)?hist_max(hp)-1:range[0]);
	if(range[1]>=(flag=(hist_max(hp) - !lflag)))
		range[1] = flag;
	/* check for valid ranges */
	if(range[1]<index2 || range[0]>=flag)
		errormsg(SH_DICT,ERROR_exit(1),e_badrange,range[0],range[1]);
	if(edit && *edit=='-' && range[0]!=range[1])
		errormsg(SH_DICT,ERROR_exit(1),e_eneedsarg);
	/* now list commands from range[rflag] to range[1-rflag] */
	incr = 1;
	flag = rflag>0;
	if(range[1-flag] < range[flag])
		incr = -1;
	if(lflag)
	{
		outfile = sfstdout;
		arg = "\n\t";
	}
	else
	{
		if(!(fname=pathtmp(NIL(char*),0,0,NIL(int*))))
			errormsg(SH_DICT,ERROR_exit(1),e_create,"");
		if((fdo=open(fname,O_CREAT|O_RDWR,S_IRUSR|S_IWUSR)) < 0)
			errormsg(SH_DICT,ERROR_system(1),e_create,fname);
		outfile= sfnew(NIL(Sfio_t*),shp->outbuff,IOBSIZE,fdo,SF_WRITE);
		arg = "\n";
		nflag++;
	}
	while(1)
	{
		if(nflag==0)
			sfprintf(outfile,"%d\t",range[flag]);
		else if(lflag)
			sfputc(outfile,'\t');
		hist_list(shp->gd->hist_ptr,outfile,hist_tell(shp->gd->hist_ptr,range[flag]),0,arg);
		if(lflag)
			sh_sigcheck(shp);
		if(range[flag] == range[1-flag])
			break;
		range[flag] += incr;
	}
	if(lflag)
		return(0);
	sfclose(outfile);
	hist_eof(hp);
	arg = edit;
	if(!arg && !(arg=nv_getval(sh_scoped(shp,HISTEDIT))) && !(arg=nv_getval(sh_scoped(shp,FCEDNOD))))
		arg = (char*)e_defedit;
#ifdef apollo
	/*
	 * Code to support the FC using the pad editor.
	 * Exampled of how to use: HISTEDIT=pad
	 */
	if (strcmp (arg, "pad") == 0)
	{
		extern int pad_create(char*);
		sh_close(fdo);
		fdo = pad_create(fname);
		pad_wait(fdo);
		unlink(fname);
		strcat(fname, ".bak");
		unlink(fname);
		lseek(fdo,(off_t)0,SEEK_SET);
	}
	else
	{
#endif /* apollo */
	if(*arg != '-')
	{
		char *com[3];
		com[0] =  arg;
		com[1] =  fname;
		com[2] = 0;
		error_info.errors = sh_eval(sh_sfeval(com),0);
	}
	fdo = sh_chkopen(fname);
	unlink(fname);
	free((void*)fname);
#ifdef apollo
	}
#endif /* apollo */
	/* don't history fc itself unless forked */
	error_info.flags |= ERROR_SILENT;
	if(!sh_isstate(SH_FORKED))
		hist_cancel(hp);
	sh_onstate(SH_HISTORY);
	sh_onstate(SH_VERBOSE);	/* echo lines as read */
	if(replace)
		hist_subst(error_info.id,fdo,replace);
	else if(error_info.errors == 0)
	{
		char buff[IOBSIZE+1];
		Sfio_t *iop = sfnew(NIL(Sfio_t*),buff,IOBSIZE,fdo,SF_READ);
		/* read in and run the command */
		if(shp->hist_depth++ > HIST_RECURSE)
			errormsg(SH_DICT,ERROR_exit(1),e_toodeep,"history");
		sh_eval(iop,1);
		shp->hist_depth--;
	}
Beispiel #6
0
void bash_init(int mode)
{
	Shell_t		*shp = &sh;
	Sfio_t		*iop;
	Namval_t	*np;
	int		n=0,xtrace,verbose;
	if(mode>0)
		goto reinit;
	if(mode < 0)
	{
		/* termination code */
		if(sh_isoption(SH_LOGIN_SHELL) && !sh_isoption(SH_POSIX))
			sh_source(shp, NiL, sh_mactry(shp,(char*)e_bash_logout));
		return;	
	}

	if(sh_isstate(SH_PREINIT))
	{	/* pre-init stage */
		if(sh_isoption(SH_RESTRICTED))
			sh_onoption(SH_RESTRICTED2);
		sh_onoption(SH_HISTORY2);
		sh_onoption(SH_INTERACTIVE_COMM);
		sh_onoption(SH_SOURCEPATH);
		sh_onoption(SH_HISTAPPEND);
		sh_onoption(SH_CMDHIST);
		sh_onoption(SH_LITHIST);
		sh_onoption(SH_NOEMPTYCMDCOMPL);
		if(shp->login_sh==2)
			sh_onoption(SH_LOGIN_SHELL);
		if(strcmp(astconf("CONFORMANCE",0,0),"standard")==0)
			sh_onoption(SH_POSIX);
		if(strcmp(astconf("UNIVERSE",0,0),"att")==0)
			sh_onoption(SH_XPG_ECHO);
		else
			sh_offoption(SH_XPG_ECHO);
		if(strcmp(astconf("PATH_RESOLVE",0,0),"physical")==0)
			sh_onoption(SH_PHYSICAL);
		else
			sh_offoption(SH_PHYSICAL);

		/* add builtins */
		sh_addbuiltin("shopt", b_shopt, &sh);

		/* set up some variables needed for --version
		 * needs to go here because --version option is parsed before the init script.
		 */
		if(np=nv_open("HOSTTYPE",shp->var_tree,0))
			nv_putval(np, BASH_HOSTTYPE, NV_NOFREE);
		if(np=nv_open("MACHTYPE",shp->var_tree,0))
			nv_putval(np, BASH_MACHTYPE, NV_NOFREE);
		if(np=nv_open("BASH_VERSION",shp->var_tree,0))
			nv_putval(np, BASH_VERSION, NV_NOFREE);
		if(np=nv_open("BASH_VERSINFO",shp->var_tree,0))
		{
			char *argv[7];
			argv[0] = BASH_MAJOR;
			argv[1] = BASH_MINOR;
			argv[2] = BASH_PATCH;
			argv[3] = BASH_BUILD;
			argv[4] = BASH_RELEASE;
			argv[5] = BASH_MACHTYPE;
			argv[6] = 0;
			nv_setvec(np, 0, 6, argv);
			nv_onattr(np,NV_RDONLY);
		}
		return;
	}

	/* rest of init stage */

	/* restrict BASH_ENV */
	if(np=nv_open("BASH_ENV",shp->var_tree,0))
	{
		const Namdisc_t *dp = nv_discfun(NV_DCRESTRICT);
		Namfun_t *fp = calloc(dp->dsize,1);
		fp->disc = dp;
		nv_disc(np, fp, 0);
	}

	/* open GLOBIGNORE node */
	if(np=nv_open("GLOBIGNORE",shp->var_tree,0))
	{
		const Namdisc_t *dp = &SH_GLOBIGNORE_disc;
		Namfun_t *fp = calloc(dp->dsize,1);
		fp->disc = dp;
		nv_disc(np, fp, 0);
	}

	/* set startup files */
	n=0;
	if(sh_isoption(SH_LOGIN_SHELL))
	{
		if(!sh_isoption(SH_POSIX))
		{
			login_files[n++] = (char*)e_bash_profile;
			login_files[n++] = (char*)e_bash_login;
		}
		login_files[n++] = (char*)e_profile;
	}
	shp->login_files = login_files;
reinit:
	xtrace = sh_isoption(SH_XTRACE);
	sh_offoption(SH_XTRACE);
	verbose = sh_isoption(SH_VERBOSE);
	sh_offoption(SH_VERBOSE);
	if(np = nv_open("SHELLOPTS", shp->var_tree, NV_NOADD))
		nv_offattr(np,NV_RDONLY);
	iop = sfopen(NULL, bash_pre_rc, "s");
	sh_eval(iop,0);
	if(xtrace)
		sh_offoption(SH_XTRACE);
	if(verbose)
		sh_offoption(SH_VERBOSE);
}
Beispiel #7
0
Datei: misc.c Projekt: att/ast
int b_dot_cmd(int n, char *argv[], Shbltin_t *context) {
    char *script;
    Namval_t *np;
    int jmpval;
    Shell_t *shp = context->shp;
    struct sh_scoped savst, *prevscope = shp->st.self;
    int fd;
    char *filename = NULL;
    char *buffer = NULL;
    struct dolnod *saveargfor = NULL;
    volatile struct dolnod *argsave = NULL;
    checkpt_t buff;
    Sfio_t *iop = NULL;
    short level;
    Optdisc_t disc;

    memset(&disc, 0, sizeof(disc));
    disc.version = OPT_VERSION;
    opt_info.disc = &disc;

    while ((n = optget(argv, sh_optdot))) {
        switch (n) {
            case ':': {
                errormsg(SH_DICT, 2, "%s", opt_info.arg);
                break;
            }
            case '?': {
                errormsg(SH_DICT, ERROR_usage(0), "%s", opt_info.arg);
                return 2;
            }
            default: { break; }
        }
    }

    argv += opt_info.index;
    script = *argv;
    if (error_info.errors || !script) {
        errormsg(SH_DICT, ERROR_usage(2), "%s", optusage(NULL));
        __builtin_unreachable();
    }
    if (shp->dot_depth + 1 > DOTMAX) {
        errormsg(SH_DICT, ERROR_exit(1), e_toodeep, script);
        __builtin_unreachable();
    }
    np = shp->posix_fun;
    if (!np) {
        // Check for KornShell style function first.
        np = nv_search(script, shp->fun_tree, 0);
        if (np && is_afunction(np) && !nv_isattr(np, NV_FPOSIX)) {
            if (!FETCH_VT(np->nvalue, ip)) {
                // TODO: Replace this with a comment explaining why the return value of this
                // path_search() call is ignored. At the time I wrote this (2019-03-16) no unit test
                // exercises this statement. I added the void cast to silence Coverity Scan 253792.
                (void)path_search(shp, script, NULL, 0);
                if (FETCH_VT(np->nvalue, ip)) {
                    if (nv_isattr(np, NV_FPOSIX)) np = NULL;
                } else {
                    errormsg(SH_DICT, ERROR_exit(1), e_found, script);
                    __builtin_unreachable();
                }
            }
        } else {
            np = NULL;
        }

        if (!np) {
            fd = path_open(shp, script, path_get(shp, script));
            if (fd < 0) {
                errormsg(SH_DICT, ERROR_system(1), e_open, script);
                __builtin_unreachable();
            }
            filename = path_fullname(shp, stkptr(shp->stk, PATH_OFFSET));
        }
    }
    *prevscope = shp->st;
    shp->st.lineno = np ? ((struct functnod *)nv_funtree(np))->functline : 1;
    shp->st.var_local = shp->st.save_tree = shp->var_tree;
    if (filename) {
        shp->st.filename = filename;
        shp->st.lineno = 1;
    }
    level = shp->fn_depth + shp->dot_depth + 1;
    nv_putval(SH_LEVELNOD, (char *)&level, NV_INT16);
    shp->st.prevst = prevscope;
    shp->st.self = &savst;
    shp->topscope = (Shscope_t *)shp->st.self;
    prevscope->save_tree = shp->var_tree;
    if (np) {
        struct Ufunction *rp = FETCH_VT(np->nvalue, rp);
        shp->st.filename = strdup(rp->fname ? rp->fname : "");
    }
    nv_putval(SH_PATHNAMENOD, shp->st.filename, NV_NOFREE);
    shp->posix_fun = NULL;
    if (np || argv[1]) argsave = sh_argnew(shp, argv, &saveargfor);
    sh_pushcontext(shp, &buff, SH_JMPDOT);
    jmpval = sigsetjmp(buff.buff, 0);
    if (jmpval == 0) {
        shp->dot_depth++;
        if (np) {
            sh_exec(shp, (Shnode_t *)(nv_funtree(np)), sh_isstate(shp, SH_ERREXIT));
        } else {
            buffer = malloc(IOBSIZE + 1);
            iop = sfnew(NULL, buffer, IOBSIZE, fd, SF_READ);
            sh_offstate(shp, SH_NOFORK);
            sh_eval(shp, iop, sh_isstate(shp, SH_PROFILE) ? SH_FUNEVAL : 0);
        }
    }
    sh_popcontext(shp, &buff);
    if (buffer) free(buffer);
    if (!np) {
        free(shp->st.filename);
        shp->st.filename = NULL;
    }
    shp->dot_depth--;
    if ((np || argv[1]) && jmpval != SH_JMPSCRIPT) {
        sh_argreset(shp, (struct dolnod *)argsave, saveargfor);
    } else {
        prevscope->dolc = shp->st.dolc;
        prevscope->dolv = shp->st.dolv;
    }
    if (shp->st.self != &savst) *shp->st.self = shp->st;
    // Only restore the top Shscope_t portion for posix functions.
    memcpy(&shp->st, prevscope, sizeof(Shscope_t));
    shp->topscope = (Shscope_t *)prevscope;
    nv_putval(SH_PATHNAMENOD, shp->st.filename, NV_NOFREE);
    if (jmpval && jmpval != SH_JMPFUN) siglongjmp(shp->jmplist->buff, jmpval);
    return shp->exitval;
}
Beispiel #8
0
Datei: bash.c Projekt: att/ast
//
// mode = 0: init, called two times
//      before parsing shell args with SH_PREINIT state turned on
//      second time after sh_init() is through and with SH_PREINIT state turned off
// mode > 1: re-init
// mode < 0: shutdown
//
void bash_init(Shell_t *shp, int mode) {
    Sfio_t *iop;
    Namval_t *np;
    int n = 0, xtrace, verbose;

    if (mode > 0) goto reinit;
    if (mode < 0) {  // termination code
        if (sh_isoption(shp, SH_LOGIN_SHELL) && !sh_isoption(shp, SH_POSIX)) {
            sh_source(shp, NULL, sh_mactry(shp, (char *)e_bash_logout));
        }
        return;
    }

    if (sh_isstate(shp, SH_PREINIT)) {  // pre-init stage
        if (sh_isoption(shp, SH_RESTRICTED)) sh_onoption(shp, SH_RESTRICTED2);
        sh_onoption(shp, SH_HISTORY2);
        sh_onoption(shp, SH_INTERACTIVE_COMM);
        sh_onoption(shp, SH_SOURCEPATH);
        sh_onoption(shp, SH_HISTAPPEND);
        sh_onoption(shp, SH_CMDHIST);
        sh_onoption(shp, SH_LITHIST);
        sh_onoption(shp, SH_NOEMPTYCMDCOMPL);
        sh_onoption(shp, SH_POSIX);
        if (shp->login_sh == 2) sh_onoption(shp, SH_LOGIN_SHELL);
        if (strcmp(astconf("UNIVERSE", 0, 0), "att") == 0) {
            sh_onoption(shp, SH_XPG_ECHO);
        } else {
            sh_offoption(shp, SH_XPG_ECHO);
        }
        sh_offoption(shp, SH_PHYSICAL);

        // Add builtins.
        sh_addbuiltin(shp, "shopt", b_shopt, &sh);
        sh_addbuiltin(shp, "enable", b_builtin, &sh);

// Set up some variables needed for --version.
// Needs to go here because --version option is parsed before the init script.
#if 0
        /* This was causing a core dump when running set to display all variables */
                if(np=nv_open("HOSTTYPE",shp->var_tree,0))
                        nv_putval(np, BASH_HOSTTYPE, NV_NOFREE);
#endif
        np = nv_open("MACHTYPE", shp->var_tree, 0);
        if (np) nv_putval(np, BASH_MACHTYPE, NV_NOFREE);
        np = nv_open("BASH_VERSION", shp->var_tree, 0);
        if (np) nv_putval(np, BASH_VERSION, NV_NOFREE);
        np = nv_open("BASH_VERSINFO", shp->var_tree, 0);
        if (np) {
            char *argv[7];
            argv[0] = BASH_MAJOR;
            argv[1] = BASH_MINOR;
            argv[2] = BASH_PATCH;
            argv[3] = BASH_BUILD;
            argv[4] = BASH_RELEASE;
            argv[5] = BASH_MACHTYPE;
            argv[6] = 0;
            nv_setvec(np, 0, 6, argv);
            nv_onattr(np, NV_RDONLY);
        }
        return;
    }

    // Rest of init stage.

    // Restrict BASH_ENV.
    np = nv_open("BASH_ENV", shp->var_tree, 0);
    if (np) {
        const Namdisc_t *dp = nv_discfun(DISCFUN_RESTRICT);
        Namfun_t *fp = calloc(dp->dsize, 1);
        fp->disc = dp;
        nv_disc(np, fp, DISC_NOOP);
    }

    // Open GLOBIGNORE node.
    np = nv_open("GLOBIGNORE", shp->var_tree, 0);
    if (np) {
        const Namdisc_t *dp = &SH_GLOBIGNORE_disc;
        Namfun_t *fp = calloc(dp->dsize, 1);
        fp->disc = dp;
        nv_disc(np, fp, DISC_NOOP);
    }

    np = nv_open("BASH_EXECUTION_STRING", shp->var_tree, 0);
    if (np) {
        np->nvalue.cp = shp->comdiv;
        nv_onattr(np, NV_NOFREE);
    }

    // Set startup files.
    n = 0;
    if (sh_isoption(shp, SH_LOGIN_SHELL)) {
        if (!sh_isoption(shp, SH_POSIX)) {
            shp->gd->login_files[n++] = (char *)e_bash_profile;
            shp->gd->login_files[n++] = (char *)e_bash_login;
        }
        shp->gd->login_files[n++] = (char *)e_profile;
    }
    shp->gd->login_files = login_files;

reinit:
    xtrace = sh_isoption(shp, SH_XTRACE);
    sh_offoption(shp, SH_XTRACE);
    verbose = sh_isoption(shp, SH_VERBOSE);
    sh_offoption(shp, SH_VERBOSE);
    np = nv_open("SHELLOPTS", shp->var_tree, NV_NOADD);
    if (np) nv_offattr(np, NV_RDONLY);
    iop = sfopen(NULL, bash_pre_rc, "s");
    sh_eval(shp, iop, 0);
    if (xtrace) sh_offoption(shp, SH_XTRACE);
    if (verbose) sh_offoption(shp, SH_VERBOSE);
}