Exemplo n.º 1
0
/*XXX
 * - if no magic,
 *	if dest given, copy to dst
 *	return ?
 * - if magic && (no globbing || syntax error)
 *	debunk to dst
 *	return ?
 * - return ?
 */
int
has_globbing(const char *xp, const char *xpe)
{
	const unsigned char *p = (const unsigned char *) xp;
	const unsigned char *pe = (const unsigned char *) xpe;
	int c;
	int nest = 0, bnest = 0;
	bool saw_glob = false;
	/* inside [...] */
	bool in_bracket = false;

	for (; p < pe; p++) {
		if (!ISMAGIC(*p))
			continue;
		if ((c = *++p) == '*' || c == '?')
			saw_glob = true;
		else if (c == '[') {
			if (!in_bracket) {
				saw_glob = true;
				in_bracket = true;
				if (ISMAGIC(p[1]) && p[2] == '!')
					p += 2;
				if (ISMAGIC(p[1]) && p[2] == ']')
					p += 2;
			}
			/*XXX Do we need to check ranges here? POSIX Q */
		} else if (c == ']') {
			if (in_bracket) {
				if (bnest)
					/* [a*(b]) */
					return (0);
				in_bracket = false;
			}
		} else if ((c & 0x80) && vstrchr("*+?@! ", c & 0x7f)) {
			saw_glob = true;
			if (in_bracket)
				bnest++;
			else
				nest++;
		} else if (c == '|') {
			if (in_bracket && !bnest)
				/* *(a[foo|bar]) */
				return (0);
		} else if (c == /*(*/ ')') {
			if (in_bracket) {
				if (!bnest--)
					/* *(a[b)c] */
					return (0);
			} else if (nest)
				nest--;
		}
		/*
		 * else must be a MAGIC-MAGIC, or MAGIC-!,
		 * MAGIC--, MAGIC-], MAGIC-{, MAGIC-, MAGIC-}
		 */
	}
	return (saw_glob && !in_bracket && !nest);
}
Exemplo n.º 2
0
/*
 * search for command with PATH
 */
const char *
search_path(const char *name, const char *lpath,
    /* R_OK or X_OK */
    int mode,
    /* set if candidate found, but not suitable */
    int *errnop)
{
	const char *sp, *p;
	char *xp;
	XString xs;
	size_t namelen;
	int ec = 0, ev;

	if (vstrchr(name, '/')) {
		if ((ec = search_access(name, mode)) == 0) {
 search_path_ok:
			if (errnop)
				*errnop = 0;
			return (name);
		}
		goto search_path_err;
	}

	namelen = strlen(name) + 1;
	Xinit(xs, xp, 128, ATEMP);

	sp = lpath;
	while (sp != NULL) {
		xp = Xstring(xs, xp);
		if (!(p = cstrchr(sp, ':')))
			p = sp + strlen(sp);
		if (p != sp) {
			XcheckN(xs, xp, p - sp);
			memcpy(xp, sp, p - sp);
			xp += p - sp;
			*xp++ = '/';
		}
		sp = p;
		XcheckN(xs, xp, namelen);
		memcpy(xp, name, namelen);
		if ((ev = search_access(Xstring(xs, xp), mode)) == 0) {
			name = Xclose(xs, xp + namelen);
			goto search_path_ok;
		}
		/* accumulate non-ENOENT errors only */
		if (ev != ENOENT && ec == 0)
			ec = ev;
		if (*sp++ == '\0')
			sp = NULL;
	}
	Xfree(xs, xp);
 search_path_err:
	if (errnop)
		*errnop = ec ? ec : ENOENT;
	return (NULL);
}
Exemplo n.º 3
0
/* Look for next ) or | (if match_sep) in *(foo|bar) pattern */
const unsigned char *
pat_scan(const unsigned char *p, const unsigned char *pe, int match_sep)
{
	int nest = 0;

	for (; p < pe; p++) {
		if (!ISMAGIC(*p))
			continue;
		if ((*++p == /*(*/ ')' && nest-- == 0) ||
		    (*p == '|' && match_sep && nest == 0))
			return (p + 1);
		if ((*p & 0x80) && vstrchr("*+?@! ", *p & 0x7f))
			nest++;
	}
	return (NULL);
}
Exemplo n.º 4
0
static int
comexec(struct op *t, struct tbl * volatile tp, const char **ap,
    volatile int flags, volatile int *xerrok)
{
	int i;
	volatile int rv = 0;
	const char *cp;
	const char **lastp;
	/* Must be static (XXX but why?) */
	static struct op texec;
	int type_flags;
	bool keepasn_ok;
	int fcflags = FC_BI|FC_FUNC|FC_PATH;
	bool bourne_function_call = false;
	struct block *l_expand, *l_assign;

	/*
	 * 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 script) -
	 * 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);
	}

	/**
	 * 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 = true;
	while (tp && tp->type == CSHELL) {
		/* undo effects of command */
		fcflags = FC_BI|FC_FUNC|FC_PATH;
		if (tp->val.f == c_builtin) {
			if ((cp = *++ap) == NULL ||
			    (!strcmp(cp, "--") && (cp = *++ap) == NULL)) {
				tp = NULL;
				break;
			}
			if ((tp = findcom(cp, FC_BI)) == NULL)
				errorf("%s: %s: %s", Tbuiltin, cp, "not a builtin");
			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)
				/* command -vV or something */
				break;
			/* don't look for functions */
			fcflags = FC_BI|FC_PATH;
			if (saw_p) {
				if (Flag(FRESTRICTED)) {
					warningf(true, "%s: %s",
					    "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 = false;
			if (!ap[0]) {
				/* ensure command with no args exits with 0 */
				subst_exstat = 0;
				break;
			}
#ifndef MKSH_NO_EXTERNAL_CAT
		} else if (tp->val.f == c_cat) {
			/*
			 * if we have any flags, do not use the builtin
			 * in theory, we could allow -u, but that would
			 * mean to use ksh_getopt here and possibly ad-
			 * ded complexity and more code and isn't worth
			 * additional hassle (and the builtin must call
			 * ksh_getopt already but can't come back here)
			 */
			if (ap[1] && ap[1][0] == '-' && ap[1][1] != '\0' &&
			    /* argument, begins with -, is not - or -- */
			    (ap[1][1] != '-' || ap[1][2] != '\0'))
				/* don't look for builtins or functions */
				fcflags = FC_PATH;
			else
				/* go on, use the builtin */
				break;
#endif
#if !defined(MKSH_SMALL)
		} else if (tp->val.f == c_trap) {
			t->u.evalflags &= ~DOTCOMEXEC;
			break;
#endif
		} else
			break;
		tp = findcom(ap[0], fcflags & (FC_BI|FC_FUNC));
	}
#if !defined(MKSH_SMALL)
	if (t->u.evalflags & DOTCOMEXEC)
		flags |= XEXEC;
#endif
	l_expand = e->loc;
	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)) {
			bourne_function_call = true;
			type_flags = EXPORT;
		} else
			type_flags = LOCAL|LOCAL_COPY|EXPORT;
	}
	l_assign = e->loc;
	if (Flag(FEXPORT))
		type_flags |= EXPORT;
	for (i = 0; t->vars[i]; i++) {
		/* do NOT lookup in the new var/fn block just created */
		e->loc = l_expand;
		cp = evalstr(t->vars[i], DOASNTILDE);
		e->loc = l_assign;
		/* but assign in there as usual */

		if (Flag(FXTRACE)) {
			if (i == 0)
				shf_puts(substitute(str_val(global("PS4")), 0),
				    shl_out);
			shf_fprintf(shl_out, "%s%c", cp,
			    t->vars[i + 1] ? ' ' : '\n');
			if (!t->vars[i + 1])
				shf_flush(shl_out);
		}
		typeset(cp, type_flags, 0, 0, 0);
		if (bourne_function_call && !(type_flags & EXPORT))
			typeset(cp, LOCAL|LOCAL_COPY|EXPORT, 0, 0, 0);
	}

	if ((cp = *ap) == NULL) {
		rv = subst_exstat;
		goto Leave;
	} else if (!tp) {
		if (Flag(FRESTRICTED) && vstrchr(cp, '/')) {
			warningf(true, "%s: %s", cp, "restricted");
			rv = 1;
			goto Leave;
		}
		tp = findcom(cp, fcflags);
	}

	switch (tp->type) {

	/* shell built-in */
	case CSHELL:
		rv = call_builtin(tp, (const char **)ap, null);
		if (!keepasn_ok && tp->val.f == c_shift) {
			l_expand->argc = l_assign->argc;
			l_expand->argv = l_assign->argv;
		}
		break;

	/* function call */
	case CFUNC: {
		volatile unsigned char old_xflag;
		volatile uint32_t old_inuse;
		const char * volatile old_kshname;

		if (!(tp->flag & ISSET)) {
			struct tbl *ftp;

			if (!tp->u.fpath) {
				rv = (tp->u2.errnov == ENOENT) ? 127 : 126;
				warningf(true, "%s: %s %s: %s", cp,
				    "can't find", "function definition file",
				    cstrerror(tp->u2.errnov));
				break;
			}
			if (include(tp->u.fpath, 0, NULL, false) < 0) {
				rv = errno;
				warningf(true, "%s: %s %s %s: %s", cp,
				    "can't open", "function definition file",
				    tp->u.fpath, cstrerror(rv));
				rv = 127;
				break;
			}
			if (!(ftp = findfunc(cp, hash(cp), false)) ||
			    !(ftp->flag & ISSET)) {
				warningf(true, "%s: %s %s", cp,
				    "function not defined by", 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] = 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 ? 1 : 0;

		old_inuse = tp->flag & FINUSE;
		tp->flag |= FINUSE;

		e->type = E_FUNC;
		if (!(i = kshsetjmp(e->jbuf))) {
			execute(tp->val.t, flags & XERROK, NULL);
			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 & 0xFF;
			break;
		case LINTR:
		case LEXIT:
		case LLEAVE:
		case LSHELL:
			quitenv(NULL);
			unwind(i);
			/* NOTREACHED */
		default:
			quitenv(NULL);
			internal_errorf("%s %d", "CFUNC", i);
		}
		break;
	}

	/* executable command */
	case CEXEC:
	/* tracked alias */
	case CTALIAS:
		if (!(tp->flag&ISSET)) {
			if (tp->u2.errnov == ENOENT) {
				rv = 127;
				warningf(true, "%s: %s", cp, "not found");
			} else {
				rv = 126;
				warningf(true, "%s: %s: %s", cp, "can't execute",
				    cstrerror(tp->u2.errnov));
			}
			break;
		}

		/* set $_ to programme's full path */
		/* setstr() can't fail here */
		setstr(typeset("_", LOCAL|EXPORT, 0, INTEGER, 0),
		    tp->val.s, KSH_RETURN_ERROR);

		if (flags&XEXEC) {
			j_exit();
			if (!(flags&XBGND)
#ifndef MKSH_UNEMPLOYED
			    || Flag(FMONITOR)
#endif
			    ) {
				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;
		/* for tprint */
		texec.left = t;
		texec.str = tp->val.s;
		texec.args = ap;
		rv = exchild(&texec, flags, xerrok, -1);
		break;
	}
 Leave:
	if (flags & XEXEC) {
		exstat = rv & 0xFF;
		unwind(LLEAVE);
	}
	return (rv);
}
Exemplo n.º 5
0
/*
 * find command
 * either function, hashed command, or built-in (in that order)
 */
struct tbl *
findcom(const char *name, int flags)
{
	static struct tbl temp;
	uint32_t h = hash(name);
	struct tbl *tp = NULL, *tbi;
	/* insert if not found */
	unsigned char insert = Flag(FTRACKALL);
	/* for function autoloading */
	char *fpath;
	union mksh_cchack npath;

	if (vstrchr(name, '/')) {
		insert = 0;
		/* prevent FPATH search below */
		flags &= ~FC_FUNC;
		goto Search;
	}
	tbi = (flags & FC_BI) ? ktsearch(&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 = NULL;
				tp->u2.errnov = ENOENT;
			} else
				tp->u.fpath = search_path(name, fpath, R_OK,
				    &tp->u2.errnov);
		}
	}
	if (!tp && (flags & FC_REGBI) && tbi && (tbi->flag & REG_BI))
		tp = tbi;
	if (!tp && (flags & FC_UNREGBI) && tbi)
		tp = tbi;
	if (!tp && (flags & FC_PATH) && !(flags & FC_DEFPATH)) {
		tp = ktsearch(&taliases, name, h);
		if (tp && (tp->flag & ISSET) &&
		    ksh_access(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 = ktenter(&taliases, name, h);
				tp->type = CTALIAS;
			} else {
				tp = &temp;
				tp->type = CEXEC;
			}
			/* make ~ISSET */
			tp->flag = DEFINED;
		}
		npath.ro = search_path(name,
		    (flags & FC_DEFPATH) ? def_path : path,
		    X_OK, &tp->u2.errnov);
		if (npath.ro) {
			strdupx(tp->val.s, npath.ro, APERM);
			if (npath.ro != name)
				afree(npath.rw, ATEMP);
			tp->flag |= ISSET|ALLOC;
		} else if ((flags & FC_FUNC) &&
		    (fpath = str_val(global("FPATH"))) != null &&
		    (npath.ro = search_path(name, fpath, R_OK,
		    &tp->u2.errnov)) != NULL) {
			/*
			 * 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;
			/* make ~ISSET */
			tp->flag = DEFINED;
			tp->u.fpath = npath.ro;
		}
	}
	return (tp);
}
Exemplo n.º 6
0
static int
comexec(struct op *t, struct tbl * volatile tp, const char **ap,
    volatile int flags, volatile int *xerrok)
{
	int i;
	volatile int rv = 0;
	const char *cp;
	const char **lastp;
	/* Must be static (XXX but why?) */
	static struct op texec;
	int type_flags;
	bool resetspec;
	int fcflags = FC_BI|FC_FUNC|FC_PATH;
	struct block *l_expand, *l_assign;
	int optc;
	const char *exec_argv0 = NULL;
	bool exec_clrenv = false;

	/* snag the last argument for $_ */
	if (Flag(FTALKING) && *(lastp = ap)) {
		/*
		 * 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 script) - perhaps save last arg here and
		 * set it in shell()?.
		 */
		while (*++lastp)
			;
		/* setstr() can't fail here */
		setstr(typeset("_", LOCAL, 0, INTEGER, 0), *--lastp,
		    KSH_RETURN_ERROR);
	}

	/**
	 * 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
	 */
	resetspec = false;
	while (tp && tp->type == CSHELL) {
		/* undo effects of command */
		fcflags = FC_BI|FC_FUNC|FC_PATH;
		if (tp->val.f == c_builtin) {
			if ((cp = *++ap) == NULL ||
			    (!strcmp(cp, "--") && (cp = *++ap) == NULL)) {
				tp = NULL;
				break;
			}
			if ((tp = findcom(cp, FC_BI)) == NULL)
				errorf("%s: %s: %s", Tbuiltin, cp, "not a builtin");
			if (tp->type == CSHELL && (tp->val.f == c_cat
#ifdef MKSH_PRINTF_BUILTIN
			    || tp->val.f == c_printf
#endif
			    ))
				break;
			continue;
		} else if (tp->val.f == c_exec) {
			if (ap[1] == NULL)
				break;
			ksh_getopt_reset(&builtin_opt, GF_ERROR);
			while ((optc = ksh_getopt(ap, &builtin_opt, "a:c")) != -1)
				switch (optc) {
				case 'a':
					exec_argv0 = builtin_opt.optarg;
					break;
				case 'c':
					exec_clrenv = true;
					/* ensure we can actually do this */
					resetspec = true;
					break;
				default:
					rv = 2;
					goto Leave;
				}
			ap += builtin_opt.optind;
			flags |= XEXEC;
		} else if (tp->val.f == c_command) {
			bool saw_p = false;

			/*
			 * 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 = true;
			if (optc != -1)
				/* command -vV or something */
				break;
			/* don't look for functions */
			fcflags = FC_BI|FC_PATH;
			if (saw_p) {
				if (Flag(FRESTRICTED)) {
					warningf(true, "%s: %s",
					    "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.
			 */
			resetspec = true;
			if (!ap[0]) {
				/* ensure command with no args exits with 0 */
				subst_exstat = 0;
				break;
			}
		} else if (tp->val.f == c_cat) {
			/* if we have any flags, do not use the builtin */
			if (ap[1] && ap[1][0] == '-' && ap[1][1] != '\0' &&
			    /* argument, begins with -, is not - or -- */
			    (ap[1][1] != '-' || ap[1][2] != '\0')) {
				struct tbl *ext_cat;

				ext_cat = findcom(Tcat, FC_PATH | FC_FUNC);
				if (ext_cat && (ext_cat->type != CTALIAS ||
				    (ext_cat->flag & ISSET)))
					tp = ext_cat;
			}
			break;
#ifdef MKSH_PRINTF_BUILTIN
		} else if (tp->val.f == c_printf) {
			struct tbl *ext_printf;

			ext_printf = findcom(Tprintf, FC_PATH | FC_FUNC);
			if (ext_printf && (ext_printf->type != CTALIAS ||
			    (ext_printf->flag & ISSET)))
				tp = ext_printf;
			break;
#endif
		} else if (tp->val.f == c_trap) {
			t->u.evalflags &= ~DOTCOMEXEC;
			break;
		} else
			break;
		tp = findcom(ap[0], fcflags & (FC_BI|FC_FUNC));
	}
	if (t->u.evalflags & DOTCOMEXEC)
		flags |= XEXEC;
	l_expand = e->loc;
	if (!resetspec && (!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 (!resetspec && tp && tp->type == CFUNC &&
		    !(tp->flag & FKSH))
			type_flags = EXPORT;
		else
			type_flags = LOCAL|LOCAL_COPY|EXPORT;
	}
	l_assign = e->loc;
	if (exec_clrenv)
		l_assign->flags |= BF_STOPENV;
	if (Flag(FEXPORT))
		type_flags |= EXPORT;
	if (Flag(FXTRACE))
		change_xtrace(2, false);
	for (i = 0; t->vars[i]; i++) {
		/* do NOT lookup in the new var/fn block just created */
		e->loc = l_expand;
		cp = evalstr(t->vars[i], DOASNTILDE | DOSCALAR);
		e->loc = l_assign;
		if (Flag(FXTRACE)) {
			const char *ccp;

			ccp = skip_varname(cp, true);
			if (*ccp == '+')
				++ccp;
			if (*ccp == '=')
				++ccp;
			shf_write(cp, ccp - cp, shl_xtrace);
			print_value_quoted(shl_xtrace, ccp);
			shf_putc(' ', shl_xtrace);
		}
		/* but assign in there as usual */
		typeset(cp, type_flags, 0, 0, 0);
	}

	if (Flag(FXTRACE)) {
		change_xtrace(2, false);
		if (ap[rv = 0]) {
 xtrace_ap_loop:
			print_value_quoted(shl_xtrace, ap[rv]);
			if (ap[++rv]) {
				shf_putc(' ', shl_xtrace);
				goto xtrace_ap_loop;
			}
		}
		change_xtrace(1, false);
	}

	if ((cp = *ap) == NULL) {
		rv = subst_exstat;
		goto Leave;
	} else if (!tp) {
		if (Flag(FRESTRICTED) && vstrchr(cp, '/')) {
			warningf(true, "%s: %s", cp, "restricted");
			rv = 1;
			goto Leave;
		}
		tp = findcom(cp, fcflags);
	}

	switch (tp->type) {

	/* shell built-in */
	case CSHELL:
 do_call_builtin:
		rv = call_builtin(tp, (const char **)ap, null, resetspec);
		if (resetspec && tp->val.f == c_shift) {
			l_expand->argc = l_assign->argc;
			l_expand->argv = l_assign->argv;
		}
		break;

	/* function call */
	case CFUNC: {
		volatile uint32_t old_inuse;
		const char * volatile old_kshname;
		volatile uint8_t old_flags[FNFLAGS];

		if (!(tp->flag & ISSET)) {
			struct tbl *ftp;

			if (!tp->u.fpath) {
				rv = (tp->u2.errnov == ENOENT) ? 127 : 126;
				warningf(true, "%s: %s %s: %s", cp,
				    "can't find", "function definition file",
				    cstrerror(tp->u2.errnov));
				break;
			}
			if (include(tp->u.fpath, 0, NULL, false) < 0) {
				if (!strcmp(cp, Tcat)) {
 no_cat_in_FPATH:
					tp = findcom(Tcat, FC_BI);
					goto do_call_builtin;
				}
#ifdef MKSH_PRINTF_BUILTIN
				if (!strcmp(cp, Tprintf)) {
 no_printf_in_FPATH:
					tp = findcom(Tprintf, FC_BI);
					goto do_call_builtin;
				}
#endif
				warningf(true, "%s: %s %s %s: %s", cp,
				    "can't open", "function definition file",
				    tp->u.fpath, cstrerror(errno));
				rv = 127;
				break;
			}
			if (!(ftp = findfunc(cp, hash(cp), false)) ||
			    !(ftp->flag & ISSET)) {
				if (!strcmp(cp, Tcat))
					goto no_cat_in_FPATH;
#ifdef MKSH_PRINTF_BUILTIN
				if (!strcmp(cp, Tprintf))
					goto no_printf_in_FPATH;
#endif
				warningf(true, "%s: %s %s", cp,
				    "function not defined by", 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] = 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);
		}

		for (type_flags = 0; type_flags < FNFLAGS; ++type_flags)
			old_flags[type_flags] = shell_flags[type_flags];
		change_xtrace((Flag(FXTRACEREC) ? Flag(FXTRACE) : 0) |
		    ((tp->flag & TRACE) ? 1 : 0), false);
		old_inuse = tp->flag & FINUSE;
		tp->flag |= FINUSE;

		e->type = E_FUNC;
		if (!(i = kshsetjmp(e->jbuf))) {
			execute(tp->val.t, flags & XERROK, NULL);
			i = LRETURN;
		}

		kshname = old_kshname;
		change_xtrace(old_flags[(int)FXTRACE], false);
#ifndef MKSH_LEGACY_MODE
		if (tp->flag & FKSH) {
			/* Korn style functions restore Flags on return */
			old_flags[(int)FXTRACE] = Flag(FXTRACE);
			for (type_flags = 0; type_flags < FNFLAGS; ++type_flags)
				shell_flags[type_flags] = old_flags[type_flags];
		}
#endif
		tp->flag = (tp->flag & ~FINUSE) | old_inuse;

		/*
		 * Were we deleted while executing? If so, free the
		 * execution tree.
		 */
		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 & 0xFF;
			break;
		case LINTR:
		case LEXIT:
		case LLEAVE:
		case LSHELL:
			quitenv(NULL);
			unwind(i);
			/* NOTREACHED */
		default:
			quitenv(NULL);
			internal_errorf("%s %d", "CFUNC", i);
		}
		break;
	}

	/* executable command */
	case CEXEC:
	/* tracked alias */
	case CTALIAS:
		if (!(tp->flag&ISSET)) {
			if (tp->u2.errnov == ENOENT) {
				rv = 127;
				warningf(true, "%s: %s", cp, "not found");
			} else {
				rv = 126;
				warningf(true, "%s: %s: %s", cp, "can't execute",
				    cstrerror(tp->u2.errnov));
			}
			break;
		}

		/* set $_ to program's full path */
		/* setstr() can't fail here */
		setstr(typeset("_", LOCAL | EXPORT, 0, INTEGER, 0),
		    tp->val.s, KSH_RETURN_ERROR);

		/* to fork, we set up a TEXEC node and call execute */
		texec.type = TEXEC;
		/* for vistree/dumptree */
		texec.left = t;
		texec.str = tp->val.s;
		texec.args = ap;

		/* in this case we do not fork, of course */
		if (flags & XEXEC) {
			if (exec_argv0)
				texec.args[0] = exec_argv0;
			j_exit();
			if (!(flags & XBGND)
#ifndef MKSH_UNEMPLOYED
			    || Flag(FMONITOR)
#endif
			    ) {
				setexecsig(&sigtraps[SIGINT], SS_RESTORE_ORIG);
				setexecsig(&sigtraps[SIGQUIT], SS_RESTORE_ORIG);
			}
		}

		rv = exchild(&texec, flags, xerrok, -1);
		break;
	}
 Leave:
	if (flags & XEXEC) {
		exstat = rv & 0xFF;
		unwind(LLEAVE);
	}
	return (rv);
}
Exemplo n.º 7
0
/**
 * Called from gwc_parse_dispatch_lines() for each complete line of output.
 *
 * @return FALSE to stop processing of any remaining data.
 */
static bool
gwc_host_line(struct gwc_parse_context *ctx, const char *buf, size_t len)
{
	int c;

	if (GNET_PROPERTY(bootstrap_debug) > 3)
		g_message("BOOT GWC host line (%lu bytes): %s", (ulong) len, buf);

	if (is_strprefix(buf, "ERROR")) {
		g_warning("GWC cache \"%s\" returned %s",
			http_async_url(ctx->handle), buf);
		http_async_cancel(ctx->handle);
		return FALSE;
	}

	if (len <= 2)
		return TRUE;		/* Skip this line silently */

	/*
	 * A line starting with "H|" is a host, with "U|" a GWC URL.
	 * Letters are case-insensitive.
	 */

	if (buf[1] != '|')
		goto malformed;

	c = ascii_toupper(buf[0]);

	if ('H' == c) {
		host_addr_t addr;
		uint16 port;

		if (string_to_host_addr_port(&buf[2], NULL, &addr, &port)) {
			ctx->processed++;
			hcache_add_caught(HOST_G2HUB, addr, port, "GWC");
			if (GNET_PROPERTY(bootstrap_debug) > 1) {
				g_message("BOOT (G2) collected %s from GWC %s",
					host_addr_port_to_string(addr, port),
					http_async_url(ctx->handle));
			}
		}
		return TRUE;
	} else if ('U' == c) {
		char *end = vstrchr(&buf[2], '|');
		char *url;

		if (NULL == end)
			goto malformed;

		ctx->processed++;
		url = h_strndup(&buf[2], ptr_diff(end, &buf[2]));
		gwc_add(url);
		hfree(url);
		return TRUE;
	} else if ('I' == c) {
		return TRUE;		/* Ignore information line */
	}

	/*
	 * If we come here, we did not recognize the line properly.
	 */

	if (GNET_PROPERTY(bootstrap_debug) > 2) {
		g_warning("GWC ignoring unknown line \"%s\" from %s",
			buf, http_async_url(ctx->handle));
	}

	return TRUE;

malformed:
	if (GNET_PROPERTY(bootstrap_debug)) {
		g_warning("GWC ignoring malformed line \"%s\" from %s",
			buf, http_async_url(ctx->handle));
	}

	return TRUE;
}