summaryrefslogtreecommitdiffstats
path: root/bin/sh/eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'bin/sh/eval.c')
-rw-r--r--bin/sh/eval.c106
1 files changed, 74 insertions, 32 deletions
diff --git a/bin/sh/eval.c b/bin/sh/eval.c
index 5bae2f2..793248b 100644
--- a/bin/sh/eval.c
+++ b/bin/sh/eval.c
@@ -94,6 +94,7 @@ static void evalsubshell(union node *, int);
static void evalredir(union node *, int);
static void expredir(union node *);
static void evalpipe(union node *);
+static int is_valid_fast_cmdsubst(union node *n);
static void evalcommand(union node *, int, struct backcmd *);
static void prehash(union node *);
@@ -110,10 +111,6 @@ RESET {
loopnest = 0;
funcnest = 0;
}
-
-SHELLPROC {
- exitstatus = 0;
-}
#endif
@@ -565,6 +562,19 @@ evalpipe(union node *n)
+static int
+is_valid_fast_cmdsubst(union node *n)
+{
+ union node *argp;
+
+ if (n->type != NCMD)
+ return 0;
+ for (argp = n->ncmd.args ; argp ; argp = argp->narg.next)
+ if (expandhassideeffects(argp->narg.text))
+ return 0;
+ return 1;
+}
+
/*
* Execute a command inside back quotes. If it's a builtin command, we
* want to save its output in a block obtained from malloc. Otherwise
@@ -578,6 +588,8 @@ evalbackcmd(union node *n, struct backcmd *result)
int pip[2];
struct job *jp;
struct stackmark smark; /* unnecessary */
+ struct jmploc jmploc;
+ struct jmploc *savehandler;
setstackmark(&smark);
result->fd = -1;
@@ -588,9 +600,21 @@ evalbackcmd(union node *n, struct backcmd *result)
exitstatus = 0;
goto out;
}
- if (n->type == NCMD) {
+ if (is_valid_fast_cmdsubst(n)) {
exitstatus = oexitstatus;
- evalcommand(n, EV_BACKCMD, result);
+ savehandler = handler;
+ if (setjmp(jmploc.loc)) {
+ if (exception == EXERROR || exception == EXEXEC)
+ exitstatus = 2;
+ else if (exception != 0) {
+ handler = savehandler;
+ longjmp(handler->loc, 1);
+ }
+ } else {
+ handler = &jmploc;
+ evalcommand(n, EV_BACKCMD, result);
+ }
+ handler = savehandler;
} else {
exitstatus = 0;
if (pipe(pip) < 0)
@@ -615,10 +639,35 @@ out:
result->fd, result->buf, result->nleft, result->jp));
}
-
+/*
+ * Check if a builtin can safely be executed in the same process,
+ * even though it should be in a subshell (command substitution).
+ * Note that jobid, jobs, times and trap can show information not
+ * available in a child process; this is deliberate.
+ * The arguments should already have been expanded.
+ */
+static int
+safe_builtin(int idx, int argc, char **argv)
+{
+ if (idx == BLTINCMD || idx == COMMANDCMD || idx == ECHOCMD ||
+ idx == FALSECMD || idx == JOBIDCMD || idx == JOBSCMD ||
+ idx == KILLCMD || idx == PRINTFCMD || idx == PWDCMD ||
+ idx == TESTCMD || idx == TIMESCMD || idx == TRUECMD ||
+ idx == TYPECMD)
+ return (1);
+ if (idx == EXPORTCMD || idx == TRAPCMD || idx == ULIMITCMD ||
+ idx == UMASKCMD)
+ return (argc <= 1 || (argc == 2 && argv[1][0] == '-'));
+ if (idx == SETCMD)
+ return (argc <= 1 || (argc == 2 && (argv[1][0] == '-' ||
+ argv[1][0] == '+') && argv[1][1] == 'o' &&
+ argv[1][2] == '\0'));
+ return (0);
+}
/*
* Execute a simple command.
+ * Note: This may or may not return if (flags & EV_EXIT).
*/
static void
@@ -655,6 +704,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
arglist.lastp = &arglist.list;
varlist.lastp = &varlist.list;
varflag = 1;
+ jp = NULL;
do_clearcmdentry = 0;
oexitstatus = exitstatus;
exitstatus = 0;
@@ -678,7 +728,9 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
argc = 0;
for (sp = arglist.list ; sp ; sp = sp->next)
argc++;
- argv = stalloc(sizeof (char *) * (argc + 1));
+ /* Add one slot at the beginning for tryexec(). */
+ argv = stalloc(sizeof (char *) * (argc + 2));
+ argv++;
for (sp = arglist.list ; sp ; sp = sp->next) {
TRACE(("evalcommand arg: %s\n", sp->text));
@@ -760,7 +812,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
* bookinging effort, since most such runs add
* directories in front of the new PATH.
*/
- clearcmdentry(0);
+ clearcmdentry();
do_clearcmdentry = 1;
}
@@ -802,7 +854,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
argc -= 2;
}
path = _PATH_STDPATH;
- clearcmdentry(0);
+ clearcmdentry();
do_clearcmdentry = 1;
} else if (!strcmp(argv[1], "--")) {
if (argc == 2)
@@ -833,10 +885,8 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
|| ((cmdentry.cmdtype == CMDNORMAL || cmdentry.cmdtype == CMDUNKNOWN)
&& ((flags & EV_EXIT) == 0 || have_traps()))
|| ((flags & EV_BACKCMD) != 0
- && (cmdentry.cmdtype != CMDBUILTIN
- || cmdentry.u.index == CDCMD
- || cmdentry.u.index == DOTCMD
- || cmdentry.u.index == EVALCMD))) {
+ && (cmdentry.cmdtype != CMDBUILTIN ||
+ !safe_builtin(cmdentry.u.index, argc, argv)))) {
jp = makejob(cmd, 1);
mode = cmd->ncmd.backgnd;
if (flags & EV_BACKCMD) {
@@ -875,14 +925,10 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
reffunc(cmdentry.u.func);
savehandler = handler;
if (setjmp(jmploc.loc)) {
- if (exception == EXSHELLPROC)
- freeparam(&saveparam);
- else {
- freeparam(&shellparam);
- shellparam = saveparam;
- if (exception == EXERROR || exception == EXEXEC)
- popredir();
- }
+ freeparam(&shellparam);
+ shellparam = saveparam;
+ if (exception == EXERROR || exception == EXEXEC)
+ popredir();
unreffunc(cmdentry.u.func);
poplocalvars();
localvars = savelocalvars;
@@ -915,7 +961,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
evalskip = 0;
skipcount = 0;
}
- if (flags & EV_EXIT)
+ if (jp)
exitshell(exitstatus);
} else if (cmdentry.cmdtype == CMDBUILTIN) {
#ifdef DEBUG
@@ -947,8 +993,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
*/
if (argc == 0 && !(flags & EV_BACKCMD))
cmdentry.special = 1;
- if (cmdentry.special)
- listsetvar(cmdenviron);
+ listsetvar(cmdenviron, cmdentry.special ? 0 : VNOSET);
if (argc > 0)
bltinsetlocale();
commandname = argv[0];
@@ -964,13 +1009,10 @@ cmddone:
out1 = &output;
out2 = &errout;
freestdout();
- if (e != EXSHELLPROC) {
- commandname = savecmdname;
- if (flags & EV_EXIT) {
- exitshell(exitstatus);
- }
- }
handler = savehandler;
+ commandname = savecmdname;
+ if (jp)
+ exitshell(exitstatus);
if (flags == EV_BACKCMD) {
backcmd->buf = memout.buf;
backcmd->nleft = memout.nextc - memout.buf;
@@ -1019,7 +1061,7 @@ out:
if (lastarg)
setvar("_", lastarg, 0);
if (do_clearcmdentry)
- clearcmdentry(0);
+ clearcmdentry();
popstackmark(&smark);
}
OpenPOWER on IntegriCloud