aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2020-02-19 15:15:13 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2020-02-20 09:36:51 +0100
commit7eb8eecbbc752d04381f35d196bbdf1e3b17e2d1 (patch)
tree52c34b1ccd069bc6155ca213388877fb442a97ce /shell
parentc91950f31532febe34e00ab20d3e5f462d9daa52 (diff)
downloadbusybox-7eb8eecbbc752d04381f35d196bbdf1e3b17e2d1.tar.gz
ash: eval: Add assignment built-in support again
Upstream commit: Date: Sat, 19 May 2018 02:39:52 +0800 eval: Add assignment built-in support again This patch adds assignment built-in support that used to exist in dash prior to 0.3.8-15. This is because it will soon be part of POSIX, and the semantics are now much better defined. Recognition is done at execution time, so even "command -- export" or "var=export; command $var" should work. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r--shell/ash.c176
1 files changed, 91 insertions, 85 deletions
diff --git a/shell/ash.c b/shell/ash.c
index fea4b10a7..145896229 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -8112,7 +8112,7 @@ struct cmdentry {
#define DO_ABS 0x02 /* checks absolute paths */
#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
#define DO_ALTPATH 0x08 /* using alternate path */
-#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
+#define DO_REGBLTIN 0x10 /* regular built-ins and functions only */
static void find_command(char *, struct cmdentry *, int, const char *);
@@ -8718,24 +8718,43 @@ typecmd(int argc UNUSED_PARAM, char **argv)
}
#if ENABLE_ASH_CMDCMD
+static struct strlist *
+fill_arglist(struct arglist *arglist, union node **argpp)
+{
+ struct strlist **lastp = arglist->lastp;
+ union node *argp;
+
+ while ((argp = *argpp) != NULL) {
+ expandarg(argp, arglist, EXP_FULL | EXP_TILDE);
+ *argpp = argp->narg.next;
+ if (*lastp)
+ break;
+ }
+
+ return *lastp;
+}
+
/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
-static char **
-parse_command_args(char **argv, const char **path)
+static int
+parse_command_args(struct arglist *arglist, union node **argpp, const char **path)
{
+ struct strlist *sp = arglist->list;
char *cp, c;
for (;;) {
- cp = *++argv;
- if (!cp)
- return NULL;
+ sp = sp->next ? sp->next : fill_arglist(arglist, argpp);
+ if (!sp)
+ return 0;
+ cp = sp->text;
if (*cp++ != '-')
break;
c = *cp++;
if (!c)
break;
if (c == '-' && !*cp) {
- if (!*++argv)
- return NULL;
+ if (!sp->next && !fill_arglist(arglist, argpp))
+ return 0;
+ sp = sp->next;
break;
}
do {
@@ -8745,12 +8764,14 @@ parse_command_args(char **argv, const char **path)
break;
default:
/* run 'typecmd' for other options */
- return NULL;
+ return 0;
}
c = *cp++;
} while (c);
}
- return argv;
+
+ arglist->list = sp;
+ return DO_NOFUNC;
}
static int FAST_FUNC
@@ -10124,7 +10145,7 @@ static int
evalcommand(union node *cmd, int flags)
{
static const struct builtincmd null_bltin = {
- "\0\0", bltincmd /* why three NULs? */
+ BUILTIN_REGULAR "", bltincmd
};
struct localvar_list *localvar_stop;
struct parsefile *file_stop;
@@ -10134,12 +10155,14 @@ evalcommand(union node *cmd, int flags)
struct arglist varlist;
char **argv;
int argc;
+ struct strlist *osp;
const struct strlist *sp;
struct cmdentry cmdentry;
struct job *jp;
char *lastarg;
const char *path;
int spclbltin;
+ int cmd_flag;
int status;
char **nargv;
smallint cmd_is_exec;
@@ -10161,26 +10184,46 @@ evalcommand(union node *cmd, int flags)
arglist.lastp = &arglist.list;
*arglist.lastp = NULL;
+ cmd_flag = 0;
+ cmd_is_exec = 0;
+ spclbltin = -1;
+ path = NULL;
+
argc = 0;
- if (cmd->ncmd.args) {
- struct builtincmd *bcmd;
- smallint pseudovarflag;
+ argp = cmd->ncmd.args;
+ osp = fill_arglist(&arglist, &argp);
+ if (osp) {
+ int pseudovarflag = 0;
- bcmd = find_builtin(cmd->ncmd.args->narg.text);
- pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
+ for (;;) {
+ find_command(arglist.list->text, &cmdentry,
+ cmd_flag | DO_REGBLTIN, pathval());
- for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
- struct strlist **spp;
+ /* implement bltin and command here */
+ if (cmdentry.cmdtype != CMDBUILTIN)
+ break;
- spp = arglist.lastp;
- if (pseudovarflag && isassignment(argp->narg.text))
- expandarg(argp, &arglist, EXP_VARTILDE);
- else
- expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
+ pseudovarflag = IS_BUILTIN_ASSIGN(cmdentry.u.cmd);
+ if (spclbltin < 0) {
+ spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
+ }
+ cmd_is_exec = cmdentry.u.cmd == EXECCMD;
+ if (cmdentry.u.cmd != COMMANDCMD)
+ break;
- for (sp = *spp; sp; sp = sp->next)
- argc++;
+ cmd_flag = parse_command_args(&arglist, &argp, &path);
+ if (!cmd_flag)
+ break;
}
+
+ for (; argp; argp = argp->narg.next)
+ expandarg(argp, &arglist,
+ pseudovarflag &&
+ isassignment(argp->narg.text) ?
+ EXP_VARTILDE : EXP_FULL | EXP_TILDE);
+
+ for (sp = arglist.list; sp; sp = sp->next)
+ argc++;
}
/* Reserve one extra spot at the front for shellexec. */
@@ -10210,23 +10253,13 @@ evalcommand(union node *cmd, int flags)
}
status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
- path = vpath.var_text;
for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
struct strlist **spp;
- char *p;
spp = varlist.lastp;
expandarg(argp, &varlist, EXP_VARTILDE);
mklocal((*spp)->text);
-
- /*
- * Modify the command lookup path, if a PATH= assignment
- * is present
- */
- p = (*spp)->text;
- if (varcmp(p, path) == 0)
- path = p;
}
/* Print the command if xflag is set. */
@@ -10265,46 +10298,16 @@ evalcommand(union node *cmd, int flags)
safe_write(preverrout_fd, "\n", 1);
}
- cmd_is_exec = 0;
- spclbltin = -1;
-
/* Now locate the command. */
- if (argc) {
- int cmd_flag = DO_ERR;
-#if ENABLE_ASH_CMDCMD
- const char *oldpath = path + 5;
-#endif
- path += 5;
- for (;;) {
- find_command(argv[0], &cmdentry, cmd_flag, path);
- if (cmdentry.cmdtype == CMDUNKNOWN) {
- flush_stdout_stderr();
- status = 127;
- goto bail;
- }
-
- /* implement bltin and command here */
- if (cmdentry.cmdtype != CMDBUILTIN)
- break;
- if (spclbltin < 0)
- spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
- if (cmdentry.u.cmd == EXECCMD)
- cmd_is_exec = 1;
-#if ENABLE_ASH_CMDCMD
- if (cmdentry.u.cmd == COMMANDCMD) {
- path = oldpath;
- nargv = parse_command_args(argv, &path);
- if (!nargv)
- break;
- /* It's "command [-p] PROG ARGS" (that is, no -Vv).
- * nargv => "PROG". path is updated if -p.
- */
- argc -= nargv - argv;
- argv = nargv;
- cmd_flag |= DO_NOFUNC;
- } else
-#endif
- break;
+ if (cmdentry.cmdtype != CMDBUILTIN
+ || !(IS_BUILTIN_REGULAR(cmdentry.u.cmd))
+ ) {
+ find_command(argv[0], &cmdentry, cmd_flag | DO_ERR,
+ path ? path : pathval());
+ if (cmdentry.cmdtype == CMDUNKNOWN) {
+ status = 127;
+ flush_stdout_stderr();
+ goto bail;
}
}
@@ -10383,6 +10386,7 @@ evalcommand(union node *cmd, int flags)
/* fall through to exec'ing external program */
}
listsetvar(varlist.list, VEXPORT|VSTACK);
+ path = path ? path : pathval();
shellexec(argv[0], argv, path, cmdentry.u.index);
/* NOTREACHED */
} /* default */
@@ -13538,11 +13542,8 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
updatetbl = (path == pathval());
- if (!updatetbl) {
+ if (!updatetbl)
act |= DO_ALTPATH;
- if (strstr(path, "%builtin") != NULL)
- act |= DO_ALTBLTIN;
- }
/* If name is in the table, check answer will be ok */
cmdp = cmdlookup(name, 0);
@@ -13555,16 +13556,19 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
abort();
#endif
case CMDNORMAL:
- bit = DO_ALTPATH;
+ bit = DO_ALTPATH | DO_REGBLTIN;
break;
case CMDFUNCTION:
bit = DO_NOFUNC;
break;
case CMDBUILTIN:
- bit = IS_BUILTIN_REGULAR(cmdp->param.cmd) ? 0 : DO_ALTBLTIN;
+ bit = IS_BUILTIN_REGULAR(cmdp->param.cmd) ? 0 : DO_REGBLTIN;
break;
}
if (act & bit) {
+ if (act & bit & DO_REGBLTIN)
+ goto fail;
+
updatetbl = 0;
cmdp = NULL;
} else if (cmdp->rehash == 0)
@@ -13577,14 +13581,15 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
if (bcmd) {
if (IS_BUILTIN_REGULAR(bcmd))
goto builtin_success;
- if (act & DO_ALTPATH) {
- if (!(act & DO_ALTBLTIN))
- goto builtin_success;
- } else if (builtinloc <= 0) {
+ if (act & DO_ALTPATH)
+ goto builtin_success;
+ if (builtinloc <= 0)
goto builtin_success;
- }
}
+ if (act & DO_REGBLTIN)
+ goto fail;
+
#if ENABLE_FEATURE_SH_STANDALONE
{
int applet_no = find_applet_by_name(name);
@@ -13688,6 +13693,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
#endif
ash_msg("%s: %s", name, errmsg(e, "not found"));
}
+ fail:
entry->cmdtype = CMDUNKNOWN;
return;