⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 exec.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * execute command tree */#include "sh.h"#include "c_test.h"#include <ctype.h>#include "ksh_stat.h"/* Does ps4 get parameter substitutions done? */#ifdef KSH# define PS4_SUBSTITUTE(s)	substitute((s), 0)#else# define PS4_SUBSTITUTE(s)	(s)#endif /* KSH */static int	comexec	 ARGS((struct op *t, struct tbl *volatile tp, char **ap,			      int volatile flags));static void	scriptexec ARGS((struct op *tp, char **ap));static int	call_builtin ARGS((struct tbl *tp, char **wp));static int	iosetup ARGS((struct ioword *iop, struct tbl *tp));static int	herein ARGS((const char *content, int sub));#ifdef KSHstatic char 	*do_selectargs ARGS((char **ap, bool_t print_menu));#endif /* KSH */#ifdef KSHstatic int	dbteste_isa ARGS((Test_env *te, Test_meta meta));static const char *dbteste_getopnd ARGS((Test_env *te, Test_op op,					 int do_eval));static int	dbteste_eval ARGS((Test_env *te, Test_op op, const char *opnd1,				const char *opnd2, int do_eval));static void	dbteste_error ARGS((Test_env *te, int offset, const char *msg));#endif /* KSH */#ifdef OS2static int	search_access1 ARGS((const char *path, int mode, int *errnop));#endif /* OS2 *//* * handle systems that don't have F_SETFD */#ifndef F_SETFD# ifndef MAXFD#   define  MAXFD 64# endif/* a bit field would be smaller, but this will work */static char clexec_tab[MAXFD+1];#endif/* * we now use this function always. */intfd_clexec(fd)    int fd;{#ifndef F_SETFD	if (fd >= 0 && fd < sizeof(clexec_tab)) {		clexec_tab[fd] = 1;		return 0;	}	return -1;#else	return fcntl(fd, F_SETFD, 1);#endif}/* * execute command tree */intexecute(t, flags)	struct op * volatile t;	volatile int flags;	/* if XEXEC don't fork */{	int i;	volatile int rv = 0;	int pv[2];	char ** volatile ap;	char *s, *cp;	struct ioword **iowp;	struct tbl *tp = NULL;	if (t == NULL)		return 0;	/* Is this the end of a pipeline?  If so, we want to evaluate the	 * command arguments	bool_t eval_done = FALSE;	if ((flags&XFORK) && !(flags&XEXEC) && (flags&XPCLOSE)) {		eval_done = TRUE;		tp = eval_execute_args(t, &ap);	}	 */	if ((flags&XFORK) && !(flags&XEXEC) && t->type != TPIPE)		return exchild(t, flags & ~XTIME, -1); /* run in sub-process */	newenv(E_EXEC);	if (trap)		runtraps(0); 	if (t->type == TCOM) {		/* Clear subst_exstat before argument expansion.  Used by		 * null commands (see comexec() and c_eval()) and by c_set().		 */		subst_exstat = 0;		current_lineno = t->lineno;	/* for $LINENO */		/* POSIX says expand command words first, then redirections,		 * and assignments last..		 */		ap = eval(t->args, t->u.evalflags | DOBLANK | DOGLOB | DOTILDE);		if (flags & XTIME)			/* Allow option parsing (bizarre, but POSIX) */			timex_hook(t, &ap);		if (Flag(FXTRACE) && ap[0]) {			shf_fprintf(shl_out, "%s",				PS4_SUBSTITUTE(str_val(global("PS4"))));			for (i = 0; ap[i]; i++)				shf_fprintf(shl_out, "%s%s", ap[i],					ap[i + 1] ? space : newline);			shf_flush(shl_out);		}		if (ap[0])			tp = findcom(ap[0], FC_BI|FC_FUNC);	}	flags &= ~XTIME;	if (t->ioact != NULL || t->type == TPIPE || t->type == TCOPROC) {		e->savefd = (short *) alloc(sizeofN(short, NUFILE), ATEMP);		/* initialize to not redirected */		memset(e->savefd, 0, sizeofN(short, NUFILE));	}	/* do redirection, to be restored in quitenv() */	if (t->ioact != NULL)		for (iowp = t->ioact; *iowp != NULL; iowp++) {			if (iosetup(*iowp, tp) < 0) {				exstat = rv = 1;				/* Redirection failures for special commands				 * cause (non-interactive) shell to exit.				 */				if (tp && tp->type == CSHELL				    && (tp->flag & SPEC_BI))					errorf(null);				/* Deal with FERREXIT, quitenv(), etc. */				goto Break;			}		}		switch(t->type) {	  case TCOM:		rv = comexec(t, tp, ap, flags);		break;	  case TPAREN:		rv = execute(t->left, flags|XFORK);		break;	  case TPIPE:		flags |= XFORK;		flags &= ~XEXEC;		e->savefd[0] = savefd(0, 0);		(void) ksh_dup2(e->savefd[0], 0, FALSE); /* stdin of first */		e->savefd[1] = savefd(1, 0);		while (t->type == TPIPE) {			openpipe(pv);			(void) ksh_dup2(pv[1], 1, FALSE); /* stdout of curr */			/* Let exchild() close pv[0] in child			 * (if this isn't done, commands like			 *    (: ; cat /etc/termcap) | sleep 1			 *  will hang forever).			 */			exchild(t->left, flags|XPIPEO|XCCLOSE, pv[0]);			(void) ksh_dup2(pv[0], 0, FALSE); /* stdin of next */			closepipe(pv);			flags |= XPIPEI;			t = t->right;		}		restfd(1, e->savefd[1]); /* stdout of last */		e->savefd[1] = 0; /* no need to re-restore this */		/* Let exchild() close 0 in parent, after fork, before wait */		i = exchild(t, flags|XPCLOSE, 0);		if (!(flags&XBGND) && !(flags&XXCOM))			rv = i;		break;	  case TLIST:		while (t->type == TLIST) {			execute(t->left, flags & XERROK);			t = t->right;		}		rv = execute(t, flags & XERROK);		break;#ifdef KSH	  case TCOPROC:	  {# ifdef JOB_SIGS		sigset_t	omask;# endif /* JOB_SIGS */# ifdef JOB_SIGS		/* Block sigchild as we are using things changed in the		 * signal handler		 */		sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);		e->type = E_ERRH;		i = ksh_sigsetjmp(e->jbuf, 0);		if (i) {			sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);			quitenv();			unwind(i);			/*NOTREACHED*/		}# endif /* JOB_SIGS */		/* Already have a (live) co-process? */		if (coproc.job && coproc.write >= 0)			errorf("coprocess already exists");		/* Can we re-use the existing co-process pipe? */		coproc_cleanup(TRUE);		/* do this before opening pipes, in case these fail */		e->savefd[0] = savefd(0, 0);		e->savefd[1] = savefd(1, 0);		openpipe(pv);		ksh_dup2(pv[0], 0, FALSE);		close(pv[0]);		coproc.write = pv[1];		coproc.job = (void *) 0;		if (coproc.readw >= 0)			ksh_dup2(coproc.readw, 1, FALSE);		else {			openpipe(pv);			coproc.read = pv[0];			ksh_dup2(pv[1], 1, FALSE);			coproc.readw = pv[1];	 /* closed before first read */			coproc.njobs = 0;			/* create new coprocess id */			++coproc.id;		}# ifdef JOB_SIGS		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);		e->type = E_EXEC; /* no more need for error handler */# endif /* JOB_SIGS */		/* exchild() closes coproc.* in child after fork,		 * will also increment coproc.njobs when the		 * job is actually created.		 */		flags &= ~XEXEC;		exchild(t->left, flags|XBGND|XFORK|XCOPROC|XCCLOSE,			coproc.readw);		break;	  }#endif /* KSH */	  case TASYNC:		/* XXX non-optimal, I think - "(foo &)", forks for (),		 * forks again for async...  parent should optimize		 * this to "foo &"...		 */		rv = execute(t->left, (flags&~XEXEC)|XBGND|XFORK);		break;	  case TOR:	  case TAND:		rv = execute(t->left, XERROK);		if (t->right != NULL && (rv == 0) == (t->type == TAND))			rv = execute(t->right, flags & XERROK);		else			flags |= XERROK;		break;	  case TBANG:		rv = !execute(t->right, XERROK);		break;#ifdef KSH	  case TDBRACKET:	    {		Test_env te;		te.flags = TEF_DBRACKET;		te.pos.wp = t->args;		te.isa = dbteste_isa;		te.getopnd = dbteste_getopnd;		te.eval = dbteste_eval;		te.error = dbteste_error;		rv = test_parse(&te);		break;	    }#endif /* KSH */	  case TFOR:#ifdef KSH	  case TSELECT:	    {		volatile bool_t is_first = TRUE;#endif /* KSH */		ap = (t->vars != NULL) ?			  eval(t->vars, DOBLANK|DOGLOB|DOTILDE)			: e->loc->argv + 1;		e->type = E_LOOP;		while (1) {			i = ksh_sigsetjmp(e->jbuf, 0);			if (!i)				break;			if ((e->flags&EF_BRKCONT_PASS)			    || (i != LBREAK && i != LCONTIN))			{				quitenv();				unwind(i);			} else if (i == LBREAK) {				rv = 0;				goto Break;			}		}		rv = 0; /* in case of a continue */		if (t->type == TFOR) {			while (*ap != NULL) {				setstr(global(t->str), *ap++, KSH_UNWIND_ERROR);				rv = execute(t->left, flags & XERROK);			}		}#ifdef KSH		else { /* TSELECT */			for (;;) {				if (!(cp = do_selectargs(ap, is_first))) {					rv = 1;					break;				}				is_first = FALSE;				setstr(global(t->str), cp, KSH_UNWIND_ERROR);				rv = execute(t->left, flags & XERROK);			}		}	    }#endif /* KSH */		break;	  case TWHILE:	  case TUNTIL:		e->type = E_LOOP;		while (1) {			i = ksh_sigsetjmp(e->jbuf, 0);			if (!i)				break;			if ((e->flags&EF_BRKCONT_PASS)			    || (i != LBREAK && i != LCONTIN))			{				quitenv();				unwind(i);			} else if (i == LBREAK) {				rv = 0;				goto Break;			}		}		rv = 0; /* in case of a continue */		while ((execute(t->left, XERROK) == 0) == (t->type == TWHILE))			rv = execute(t->right, flags & XERROK);		break;	  case TIF:	  case TELIF:		if (t->right == NULL)			break;	/* should be error */		rv = execute(t->left, XERROK) == 0 ?			execute(t->right->left, flags & XERROK) :			execute(t->right->right, flags & XERROK);		break;	  case TCASE:		cp = evalstr(t->str, DOTILDE);		for (t = t->left; t != NULL && t->type == TPAT; t = t->right)		    for (ap = t->vars; *ap; ap++)			if ((s = evalstr(*ap, DOTILDE|DOPAT))			    && gmatch(cp, s, FALSE))				goto Found;		break;	  Found:		rv = execute(t->left, flags & XERROK);		break;	  case TBRACE:		rv = execute(t->left, flags & XERROK);		break;	  case TFUNCT:		rv = define(t->str, t);		break;	  case TTIME:		/* Clear XEXEC so nested execute() call doesn't exit		 * (allows "ls -l | time grep foo").		 */		rv = timex(t, flags & ~XEXEC);		break;	  case TEXEC:		/* an eval'd TCOM */		s = t->args[0];		ap = makenv();#ifndef F_SETFD		for (i = 0; i < sizeof(clexec_tab); i++)			if (clexec_tab[i]) {				close(i);				clexec_tab[i] = 0;			}#endif		restoresigs();		cleanup_proc_env();		/* XINTACT bit is for OS2 */		ksh_execve(t->str, t->args, ap, (flags & XINTACT) ? 1 : 0);		if (errno == ENOEXEC)			scriptexec(t, ap);		else			errorf("%s: %s", s, strerror(errno));	}    Break:	exstat = rv;	quitenv();		/* restores IO */	if ((flags&XEXEC))		unwind(LEXIT);	/* exit child */	if (rv != 0 && !(flags & XERROK)) {		if (Flag(FERREXIT))			unwind(LERROR);		trapsig(SIGERR_);	}	return rv;}/* * execute simple command */static intcomexec(t, tp, ap, flags)	struct op *t;	struct tbl *volatile tp;	register char **ap;	int volatile flags;{	int i;	int rv = 0;	register char *cp;	register char **lastp;	static struct op texec; /* Must be static (XXX but why?) */	int type_flags;	int keepasn_ok;	int fcflags = FC_BI|FC_FUNC|FC_PATH;#ifdef KSH	/* snag the last argument for $_ XXX not the same as at&t ksh,	 * which only seems to set $_ after a newline (but not in	 * functions/dot scripts, but in interactive and scipt) -	 * perhaps save last arg here and set it in shell()?.	 */	if (Flag(FTALKING) && *(lastp = ap)) {		while (*++lastp)			;		/* setstr() can't fail here */		setstr(typeset("_", LOCAL, 0, INTEGER, 0), *--lastp,		       KSH_RETURN_ERROR);	}#endif /* KSH */	/* Deal with the shell builtins builtin, exec and command since	 * they can be followed by other commands.  This must be done before	 * we know if we should create a local block, which must be done	 * before we can do a path search (in case the assignments change	 * PATH).	 * Odd cases:	 *   FOO=bar exec > /dev/null		FOO is kept but not exported	 *   FOO=bar exec foobar		FOO is exported	 *   FOO=bar command exec > /dev/null	FOO is neither kept nor exported	 *   FOO=bar command			FOO is neither kept nor exported	 *   PATH=... foobar			use new PATH in foobar search	 */	keepasn_ok = 1;	while (tp && tp->type == CSHELL) {		fcflags = FC_BI|FC_FUNC|FC_PATH;/* undo effects of command */		if (tp->val.f == c_builtin) {			if ((cp = *++ap) == NULL) {				tp = NULL;				break;			}			tp = findcom(cp, FC_BI);			if (tp == NULL)				errorf("builtin: %s: not a builtin", cp);			continue;		} else if (tp->val.f == c_exec) {			if (ap[1] == NULL)				break;			ap++;			flags |= XEXEC;		} else if (tp->val.f == c_command) {			int optc, saw_p = 0;			/* Ugly dealing with options in two places (here and			 * in c_command(), but such is life)			 */			ksh_getopt_reset(&builtin_opt, 0);			while ((optc = ksh_getopt(ap, &builtin_opt, ":p"))									== 'p')				saw_p = 1;			if (optc != EOF)				break;	/* command -vV or something */			/* don't look for functions */			fcflags = FC_BI|FC_PATH;			if (saw_p) {				if (Flag(FRESTRICTED)) {					warningf(TRUE,						"command -p: restricted");					rv = 1;					goto Leave;				}				fcflags |= FC_DEFPATH;			}			ap += builtin_opt.optind;			/* POSIX says special builtins lose their status			 * if accessed using command.			 */			keepasn_ok = 0;			if (!ap[0]) {				/* ensure command with no args exits with 0 */				subst_exstat = 0;				break;			}		} else			break;		tp = findcom(ap[0], fcflags & (FC_BI|FC_FUNC));	}	if (keepasn_ok && (!ap[0] || (tp && (tp->flag & KEEPASN))))		type_flags = 0;	else {		/* create new variable/function block */		newblock();		/* ksh functions don't keep assignments, POSIX functions do. */		if (keepasn_ok && tp && tp->type == CFUNC		    && !(tp->flag & FKSH))			type_flags = 0;		else			type_flags = LOCAL|LOCAL_COPY|EXPORT;	}	if (Flag(FEXPORT))		type_flags |= EXPORT;	for (i = 0; t->vars[i]; i++) {		cp = evalstr(t->vars[i], DOASNTILDE);		if (Flag(FXTRACE)) {			if (i == 0)				shf_fprintf(shl_out, "%s",					PS4_SUBSTITUTE(str_val(global("PS4"))));			shf_fprintf(shl_out, "%s%s", cp,				t->vars[i + 1] ? space : newline);			if (!t->vars[i + 1])				shf_flush(shl_out);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -