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

📄 exec.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
		}		typeset(cp, type_flags, 0, 0, 0);	}	if ((cp = *ap) == NULL) {		rv = subst_exstat;		goto Leave;	} else if (!tp) {		if (Flag(FRESTRICTED) && ksh_strchr_dirsep(cp)) {			warningf(TRUE, "%s: restricted", cp);			rv = 1;			goto Leave;		}		tp = findcom(cp, fcflags);	}	switch (tp->type) {	  case CSHELL:			/* shell built-in */		rv = call_builtin(tp, ap);		break;	  case CFUNC:			/* function call */	  {		volatile int old_xflag;		volatile Tflag old_inuse;		const char *volatile old_kshname;		if (!(tp->flag & ISSET)) {			struct tbl *ftp;			if (!tp->u.fpath) {				if (tp->u2.errno_) {					warningf(TRUE,				"%s: can't find function definition file - %s",						cp, strerror(tp->u2.errno_));					rv = 126;				} else {					warningf(TRUE,				"%s: can't find function definition file", cp);					rv = 127;				}				break;			}			if (include(tp->u.fpath, 0, (char **) 0, 0) < 0) {				warningf(TRUE,			    "%s: can't open function definition file %s - %s",					cp, tp->u.fpath, strerror(errno));				rv = 127;				break;			}			if (!(ftp = findfunc(cp, hash(cp), FALSE))			    || !(ftp->flag & ISSET))			{				warningf(TRUE,					"%s: function not defined by %s",					cp, tp->u.fpath);				rv = 127;				break;			}			tp = ftp;		}		/* ksh functions set $0 to function name, POSIX functions leave		 * $0 unchanged.		 */		old_kshname = kshname;		if (tp->flag & FKSH)			kshname = ap[0];		else			ap[0] = (char *) kshname;		e->loc->argv = ap;		for (i = 0; *ap++ != NULL; i++)			;		e->loc->argc = i - 1;		/* ksh-style functions handle getopts sanely,		 * bourne/posix functions are insane...		 */		if (tp->flag & FKSH) {			e->loc->flags |= BF_DOGETOPTS;			e->loc->getopts_state = user_opt;			getopts_reset(1);		}		old_xflag = Flag(FXTRACE);		Flag(FXTRACE) = tp->flag & TRACE ? TRUE : FALSE;		old_inuse = tp->flag & FINUSE;		tp->flag |= FINUSE;		e->type = E_FUNC;		i = ksh_sigsetjmp(e->jbuf, 0);		if (i == 0) {			/* seems odd to pass XERROK here, but at&t ksh does */			exstat = execute(tp->val.t, flags & XERROK);			i = LRETURN;		}		kshname = old_kshname;		Flag(FXTRACE) = old_xflag;		tp->flag = (tp->flag & ~FINUSE) | old_inuse;		/* Were we deleted while executing?  If so, free the execution		 * tree.  todo: Unfortunately, the table entry is never re-used		 * until the lookup table is expanded.		 */		if ((tp->flag & (FDELETE|FINUSE)) == FDELETE) {			if (tp->flag & ALLOC) {				tp->flag &= ~ALLOC;				tfree(tp->val.t, tp->areap);			}			tp->flag = 0;		}		switch (i) {		  case LRETURN:		  case LERROR:			rv = exstat;			break;		  case LINTR:		  case LEXIT:		  case LLEAVE:		  case LSHELL:			quitenv();			unwind(i);			/*NOTREACHED*/		  default:			quitenv();			internal_errorf(1, "CFUNC %d", i);		}		break;	  }	  case CEXEC:		/* executable command */	  case CTALIAS:		/* tracked alias */		if (!(tp->flag&ISSET)) {			/* errno_ will be set if the named command was found			 * but could not be executed (permissions, no execute			 * bit, directory, etc).  Print out a (hopefully)			 * useful error message and set the exit status to 126.			 */			if (tp->u2.errno_) {				warningf(TRUE, "%s: cannot execute - %s", cp,					strerror(tp->u2.errno_));				rv = 126;	/* POSIX */			} else {				warningf(TRUE, "%s: not found", cp);				rv = 127;			}			break;		}#ifdef KSH		/* set $_ to program's full path */		/* setstr() can't fail here */		setstr(typeset("_", LOCAL|EXPORT, 0, INTEGER, 0), tp->val.s,		       KSH_RETURN_ERROR);#endif /* KSH */		if (flags&XEXEC) {			j_exit();			if (!(flags&XBGND) || Flag(FMONITOR)) {				setexecsig(&sigtraps[SIGINT], SS_RESTORE_ORIG);				setexecsig(&sigtraps[SIGQUIT], SS_RESTORE_ORIG);			}		}		/* to fork we set up a TEXEC node and call execute */		texec.type = TEXEC;		texec.left = t;	/* for tprint */		texec.str = tp->val.s;		texec.args = ap;		rv = exchild(&texec, flags, -1);		break;	}  Leave:	if (flags & XEXEC) {		exstat = rv;		unwind(LLEAVE);	}	return rv;}static voidscriptexec(tp, ap)	register struct op *tp;	register char **ap;{	char *shell;	shell = str_val(global(EXECSHELL_STR));	if (shell && *shell)		shell = search(shell, path, X_OK, (int *) 0);	if (!shell || !*shell)		shell = EXECSHELL;	*tp->args-- = tp->str;#ifdef	SHARPBANG	{		char buf[LINE];		register char *cp;		register int fd, n;		buf[0] = '\0';		if ((fd = open(tp->str, O_RDONLY)) >= 0) {			if ((n = read(fd, buf, LINE - 1)) > 0)				buf[n] = '\0';			(void) close(fd);		}		if ((buf[0] == '#' && buf[1] == '!' && (cp = &buf[2]))# ifdef OS2		    || (strncmp(buf, "extproc", 7) == 0 && isspace(buf[7])			&& (cp = &buf[7]))# endif /* OS2 */		    )		{			while (*cp && (*cp == ' ' || *cp == '\t'))				cp++;			if (*cp && *cp != '\n') {				char *a0 = cp, *a1 = (char *) 0;# ifdef OS2				char *a2 = cp;# endif /* OS2 */				while (*cp && *cp != '\n' && *cp != ' '				       && *cp != '\t')				{# ifdef OS2			/* Allow shell search without prepended path			 * if shell with / in pathname cannot be found.			 * Use / explicitly so \ can be used if explicit			 * needs to be forced.			 */					if (*cp == '/')						a2 = cp + 1;# endif /* OS2 */					cp++;				}				if (*cp && *cp != '\n') {					*cp++ = '\0';					while (*cp					       && (*cp == ' ' || *cp == '\t'))						cp++;					if (*cp && *cp != '\n') {						a1 = cp;						/* all one argument */						while (*cp && *cp != '\n')							cp++;					}				}				if (*cp == '\n') {					*cp = '\0';					if (a1)						*tp->args-- = a1;# ifdef OS2					if (a0 != a2) {						char *tmp_a0 = str_nsave(a0,							strlen(a0) + 5, ATEMP);						if (search_access(tmp_a0, X_OK,								(int *) 0))							a0 = a2;						afree(tmp_a0, ATEMP);					}# endif /* OS2 */					shell = a0;				}			}# ifdef OS2		} else {		        /* Use ksh documented shell default if present			 * else use OS2_SHELL which is assumed to need			 * the /c option and '\' as dir separater.			 */		         char *p = shell;			 shell = str_val(global("EXECSHELL"));			 if (shell && *shell)				 shell = search(shell, path, X_OK, (int *) 0);			 if (!shell || !*shell) {				 shell = p;				 *tp->args-- = "/c";				 for (p = tp->str; *p; p++)					 if (*p == '/')						 *p = '\\';			 }# endif /* OS2 */		}	}#endif	/* SHARPBANG */	*tp->args = shell;	ksh_execve(tp->args[0], tp->args, ap, 0);	/* report both the program that was run and the bogus shell */	errorf("%s: %s: %s", tp->str, shell, strerror(errno));}intshcomexec(wp)	register char **wp;{	register struct tbl *tp;	tp = tsearch(&builtins, *wp, hash(*wp));	if (tp == NULL)		internal_errorf(1, "shcomexec: %s", *wp);	return call_builtin(tp, wp);}/* * Search function tables for a function.  If create set, a table entry * is created if none is found. */struct tbl *findfunc(name, h, create)	const char *name;	unsigned int h;	int create;{	struct block *l;	struct tbl *tp = (struct tbl *) 0;	for (l = e->loc; l; l = l->next) {		tp = tsearch(&l->funs, name, h);		if (tp)			break;		if (!l->next && create) {			tp = tenter(&l->funs, name, h);			tp->flag = DEFINED;			tp->type = CFUNC;			tp->val.t = (struct op *) 0;			break;		}	}	return tp;}/* * define function.  Returns 1 if function is being undefined (t == 0) and * function did not exist, returns 0 otherwise. */intdefine(name, t)	const char *name;	struct op *t;{	struct tbl *tp;	int was_set = 0;	while (1) {		tp = findfunc(name, hash(name), TRUE);		if (tp->flag & ISSET)			was_set = 1;		/* If this function is currently being executed, we zap this		 * table entry so findfunc() won't see it		 */		if (tp->flag & FINUSE) {			tp->name[0] = '\0';			tp->flag &= ~DEFINED; /* ensure it won't be found */			tp->flag |= FDELETE;		} else			break;	}	if (tp->flag & ALLOC) {		tp->flag &= ~(ISSET|ALLOC);		tfree(tp->val.t, tp->areap);	}	if (t == NULL) {		/* undefine */		tdelete(tp);		return was_set ? 0 : 1;	}	tp->val.t = tcopy(t->left, tp->areap);	tp->flag |= (ISSET|ALLOC);	if (t->u.ksh_func)		tp->flag |= FKSH;	return 0;}/* * add builtin */voidbuiltin(name, func)	const char *name;	int (*func) ARGS((char **));{	register struct tbl *tp;	Tflag flag;	/* see if any flags should be set for this builtin */	for (flag = 0; ; name++) {		if (*name == '=')	/* command does variable assignment */			flag |= KEEPASN;		else if (*name == '*')	/* POSIX special builtin */			flag |= SPEC_BI;		else if (*name == '+')	/* POSIX regular builtin */			flag |= REG_BI;		else			break;	}	tp = tenter(&builtins, name, hash(name));	tp->flag = DEFINED | flag;	tp->type = CSHELL;	tp->val.f = func;}/* * find command * either function, hashed command, or built-in (in that order) */struct tbl *findcom(name, flags)	const char *name;	int	flags;		/* FC_* */{	static struct tbl temp;	unsigned int h = hash(name);	struct tbl *tp = NULL, *tbi;	int insert = Flag(FTRACKALL);	/* insert if not found */	char *fpath;			/* for function autoloading */	char *npath;	if (ksh_strchr_dirsep(name) != NULL) {		insert = 0;		/* prevent FPATH search below */		flags &= ~FC_FUNC;		goto Search;	}	tbi = (flags & FC_BI) ? tsearch(&builtins, name, h) : NULL;	/* POSIX says special builtins first, then functions, then	 * POSIX regular builtins, then search path...	 */	if ((flags & FC_SPECBI) && tbi && (tbi->flag & SPEC_BI))		tp = tbi;	if (!tp && (flags & FC_FUNC)) {		tp = findfunc(name, h, FALSE);		if (tp && !(tp->flag & ISSET)) {			if ((fpath = str_val(global("FPATH"))) == null) {				tp->u.fpath = (char *) 0;				tp->u2.errno_ = 0;			} else				tp->u.fpath = search(name, fpath, R_OK,					&tp->u2.errno_);		}	}	if (!tp && (flags & FC_REGBI) && tbi && (tbi->flag & REG_BI))		tp = tbi;	/* todo: posix says non-special/non-regular builtins must	 * be triggered by some user-controllable means like a	 * special directory in PATH.  Requires modifications to	 * the search() function.  Tracked aliases should be	 * modified to allow tracking of builtin commands.	 * This should be under control of the FPOSIX flag.	 * If this is changed, also change c_whence...	 */	if (!tp && (flags & FC_UNREGBI) && tbi)		tp = tbi;	if (!tp && (flags & FC_PATH) && !(flags & FC_DEFPATH)) {		tp = tsearch(&taliases, name, h);		if (tp && (tp->flag & ISSET) && eaccess(tp->val.s, X_OK) != 0) {			if (tp->flag & ALLOC) {				tp->flag &= ~ALLOC;				afree(tp->val.s, APERM);			}			tp->flag &= ~ISSET;		}	}  Search:	if ((!tp || (tp->type == CTALIAS && !(tp->flag&ISSET)))	    && (flags & FC_PATH))	{		if (!tp) {			if (insert && !(flags & FC_DEFPATH)) {				tp = tenter(&taliases, name, h);				tp->type = CTALIAS;			} else {				tp = &temp;				tp->type = CEXEC;			}			tp->flag = DEFINED;	/* make ~ISSET */		}		npath = search(name, flags & FC_DEFPATH ? def_path : path,				X_OK, &tp->u2.errno_);		if (npath) {			tp->val.s = tp == &temp ? npath : str_save(npath, APERM);			tp->flag |= ISSET|ALLOC;		} else if ((flags & FC_FUNC)			   && (fpath = str_val(global("FPATH"))) != null			   && (npath = search(name, fpath, R_OK,					      &tp->u2.errno_)) != (char *) 0)		{			/* An undocumented feature of at&t ksh is that it			 * searches FPATH if a command is not found, even			 * if the command hasn't been set up as an autoloaded			 * function (ie, no typeset -uf).			 */			tp = &temp;			tp->type = CFUNC;			tp->flag = DEFINED; /* make ~ISSET */			tp->u.fpath = npath;		}	}	return tp;}/* * flush executable commands with relative paths */voidflushcom(all)	int all;		/* just relative or all */{	struct tbl *tp;	struct tstate ts;	for (twalk(&ts, &taliases); (tp = tnext(&ts)) != NULL; )		if ((tp->flag&ISSET) && (all || !ISDIRSEP(tp->val.s[0]))) {			if (tp->flag&ALLOC) {				tp->flag &= ~(ALLOC|ISSET);				afree(tp->val.s, APERM);			}			tp->flag &= ~ISSET;		}}/* Check if path is something we want to find.  Returns -1 for failure. */intsearch_access(path, mode, errnop)	const char *path;	int mode;	int *errnop;		/* set if candidate found, but not suitable */{#ifndef OS2	int ret, err = 0;	struct stat statb;	if (stat(path, &statb) < 0)		return -1;	ret = eaccess(path, mode);	if (ret < 0)		err = errno; /* File exists, but we can't access it */	else if (mode == X_OK		 && (!S_ISREG(statb.st_mode)		     /* This 'cause access() says root can execute everything */		     || !(statb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))))	{		ret = -1;		err = S_ISDIR(statb.st_mode) ? EISDIR : EACCES;	}	if (err && errnop && !*errnop)		*errnop = err;	return ret;#else /* !OS2 */	/*	 * NOTE: ASSUMES path can be modified and has enough room at the	 *       end of the string for a suffix (ie, 4 extra characters).	 *	 Certain code knows this (eg, eval.c(globit()),	 *	 exec.c(search())).	 */	static char *xsuffixes[] = { ".ksh", ".exe", ".", ".sh", ".cmd",

⌨️ 快捷键说明

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