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>
This commit is contained in:
parent
c91950f315
commit
7eb8eecbbc
178
shell/ash.c
178
shell/ash.c
@ -8112,7 +8112,7 @@ struct cmdentry {
|
|||||||
#define DO_ABS 0x02 /* checks absolute paths */
|
#define DO_ABS 0x02 /* checks absolute paths */
|
||||||
#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
|
#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
|
||||||
#define DO_ALTPATH 0x08 /* using alternate path */
|
#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 *);
|
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
|
#if ENABLE_ASH_CMDCMD
|
||||||
/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
|
static struct strlist *
|
||||||
static char **
|
fill_arglist(struct arglist *arglist, union node **argpp)
|
||||||
parse_command_args(char **argv, const char **path)
|
|
||||||
{
|
{
|
||||||
|
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 int
|
||||||
|
parse_command_args(struct arglist *arglist, union node **argpp, const char **path)
|
||||||
|
{
|
||||||
|
struct strlist *sp = arglist->list;
|
||||||
char *cp, c;
|
char *cp, c;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
cp = *++argv;
|
sp = sp->next ? sp->next : fill_arglist(arglist, argpp);
|
||||||
if (!cp)
|
if (!sp)
|
||||||
return NULL;
|
return 0;
|
||||||
|
cp = sp->text;
|
||||||
if (*cp++ != '-')
|
if (*cp++ != '-')
|
||||||
break;
|
break;
|
||||||
c = *cp++;
|
c = *cp++;
|
||||||
if (!c)
|
if (!c)
|
||||||
break;
|
break;
|
||||||
if (c == '-' && !*cp) {
|
if (c == '-' && !*cp) {
|
||||||
if (!*++argv)
|
if (!sp->next && !fill_arglist(arglist, argpp))
|
||||||
return NULL;
|
return 0;
|
||||||
|
sp = sp->next;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
@ -8745,12 +8764,14 @@ parse_command_args(char **argv, const char **path)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* run 'typecmd' for other options */
|
/* run 'typecmd' for other options */
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
c = *cp++;
|
c = *cp++;
|
||||||
} while (c);
|
} while (c);
|
||||||
}
|
}
|
||||||
return argv;
|
|
||||||
|
arglist->list = sp;
|
||||||
|
return DO_NOFUNC;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int FAST_FUNC
|
static int FAST_FUNC
|
||||||
@ -10124,7 +10145,7 @@ static int
|
|||||||
evalcommand(union node *cmd, int flags)
|
evalcommand(union node *cmd, int flags)
|
||||||
{
|
{
|
||||||
static const struct builtincmd null_bltin = {
|
static const struct builtincmd null_bltin = {
|
||||||
"\0\0", bltincmd /* why three NULs? */
|
BUILTIN_REGULAR "", bltincmd
|
||||||
};
|
};
|
||||||
struct localvar_list *localvar_stop;
|
struct localvar_list *localvar_stop;
|
||||||
struct parsefile *file_stop;
|
struct parsefile *file_stop;
|
||||||
@ -10134,12 +10155,14 @@ evalcommand(union node *cmd, int flags)
|
|||||||
struct arglist varlist;
|
struct arglist varlist;
|
||||||
char **argv;
|
char **argv;
|
||||||
int argc;
|
int argc;
|
||||||
|
struct strlist *osp;
|
||||||
const struct strlist *sp;
|
const struct strlist *sp;
|
||||||
struct cmdentry cmdentry;
|
struct cmdentry cmdentry;
|
||||||
struct job *jp;
|
struct job *jp;
|
||||||
char *lastarg;
|
char *lastarg;
|
||||||
const char *path;
|
const char *path;
|
||||||
int spclbltin;
|
int spclbltin;
|
||||||
|
int cmd_flag;
|
||||||
int status;
|
int status;
|
||||||
char **nargv;
|
char **nargv;
|
||||||
smallint cmd_is_exec;
|
smallint cmd_is_exec;
|
||||||
@ -10161,26 +10184,46 @@ evalcommand(union node *cmd, int flags)
|
|||||||
arglist.lastp = &arglist.list;
|
arglist.lastp = &arglist.list;
|
||||||
*arglist.lastp = NULL;
|
*arglist.lastp = NULL;
|
||||||
|
|
||||||
|
cmd_flag = 0;
|
||||||
|
cmd_is_exec = 0;
|
||||||
|
spclbltin = -1;
|
||||||
|
path = NULL;
|
||||||
|
|
||||||
argc = 0;
|
argc = 0;
|
||||||
if (cmd->ncmd.args) {
|
argp = cmd->ncmd.args;
|
||||||
struct builtincmd *bcmd;
|
osp = fill_arglist(&arglist, &argp);
|
||||||
smallint pseudovarflag;
|
if (osp) {
|
||||||
|
int pseudovarflag = 0;
|
||||||
|
|
||||||
bcmd = find_builtin(cmd->ncmd.args->narg.text);
|
for (;;) {
|
||||||
pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
|
find_command(arglist.list->text, &cmdentry,
|
||||||
|
cmd_flag | DO_REGBLTIN, pathval());
|
||||||
|
|
||||||
for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
|
/* implement bltin and command here */
|
||||||
struct strlist **spp;
|
if (cmdentry.cmdtype != CMDBUILTIN)
|
||||||
|
break;
|
||||||
|
|
||||||
spp = arglist.lastp;
|
pseudovarflag = IS_BUILTIN_ASSIGN(cmdentry.u.cmd);
|
||||||
if (pseudovarflag && isassignment(argp->narg.text))
|
if (spclbltin < 0) {
|
||||||
expandarg(argp, &arglist, EXP_VARTILDE);
|
spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
|
||||||
else
|
}
|
||||||
expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
|
cmd_is_exec = cmdentry.u.cmd == EXECCMD;
|
||||||
|
if (cmdentry.u.cmd != COMMANDCMD)
|
||||||
|
break;
|
||||||
|
|
||||||
for (sp = *spp; sp; sp = sp->next)
|
cmd_flag = parse_command_args(&arglist, &argp, &path);
|
||||||
argc++;
|
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. */
|
/* 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);
|
status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
|
||||||
|
|
||||||
path = vpath.var_text;
|
|
||||||
for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
|
for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
|
||||||
struct strlist **spp;
|
struct strlist **spp;
|
||||||
char *p;
|
|
||||||
|
|
||||||
spp = varlist.lastp;
|
spp = varlist.lastp;
|
||||||
expandarg(argp, &varlist, EXP_VARTILDE);
|
expandarg(argp, &varlist, EXP_VARTILDE);
|
||||||
|
|
||||||
mklocal((*spp)->text);
|
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. */
|
/* Print the command if xflag is set. */
|
||||||
@ -10265,46 +10298,16 @@ evalcommand(union node *cmd, int flags)
|
|||||||
safe_write(preverrout_fd, "\n", 1);
|
safe_write(preverrout_fd, "\n", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_is_exec = 0;
|
|
||||||
spclbltin = -1;
|
|
||||||
|
|
||||||
/* Now locate the command. */
|
/* Now locate the command. */
|
||||||
if (argc) {
|
if (cmdentry.cmdtype != CMDBUILTIN
|
||||||
int cmd_flag = DO_ERR;
|
|| !(IS_BUILTIN_REGULAR(cmdentry.u.cmd))
|
||||||
#if ENABLE_ASH_CMDCMD
|
) {
|
||||||
const char *oldpath = path + 5;
|
find_command(argv[0], &cmdentry, cmd_flag | DO_ERR,
|
||||||
#endif
|
path ? path : pathval());
|
||||||
path += 5;
|
if (cmdentry.cmdtype == CMDUNKNOWN) {
|
||||||
for (;;) {
|
status = 127;
|
||||||
find_command(argv[0], &cmdentry, cmd_flag, path);
|
flush_stdout_stderr();
|
||||||
if (cmdentry.cmdtype == CMDUNKNOWN) {
|
goto bail;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -10383,6 +10386,7 @@ evalcommand(union node *cmd, int flags)
|
|||||||
/* fall through to exec'ing external program */
|
/* fall through to exec'ing external program */
|
||||||
}
|
}
|
||||||
listsetvar(varlist.list, VEXPORT|VSTACK);
|
listsetvar(varlist.list, VEXPORT|VSTACK);
|
||||||
|
path = path ? path : pathval();
|
||||||
shellexec(argv[0], argv, path, cmdentry.u.index);
|
shellexec(argv[0], argv, path, cmdentry.u.index);
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
} /* default */
|
} /* 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 */
|
/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
|
||||||
|
|
||||||
updatetbl = (path == pathval());
|
updatetbl = (path == pathval());
|
||||||
if (!updatetbl) {
|
if (!updatetbl)
|
||||||
act |= DO_ALTPATH;
|
act |= DO_ALTPATH;
|
||||||
if (strstr(path, "%builtin") != NULL)
|
|
||||||
act |= DO_ALTBLTIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If name is in the table, check answer will be ok */
|
/* If name is in the table, check answer will be ok */
|
||||||
cmdp = cmdlookup(name, 0);
|
cmdp = cmdlookup(name, 0);
|
||||||
@ -13555,16 +13556,19 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
|
|||||||
abort();
|
abort();
|
||||||
#endif
|
#endif
|
||||||
case CMDNORMAL:
|
case CMDNORMAL:
|
||||||
bit = DO_ALTPATH;
|
bit = DO_ALTPATH | DO_REGBLTIN;
|
||||||
break;
|
break;
|
||||||
case CMDFUNCTION:
|
case CMDFUNCTION:
|
||||||
bit = DO_NOFUNC;
|
bit = DO_NOFUNC;
|
||||||
break;
|
break;
|
||||||
case CMDBUILTIN:
|
case CMDBUILTIN:
|
||||||
bit = IS_BUILTIN_REGULAR(cmdp->param.cmd) ? 0 : DO_ALTBLTIN;
|
bit = IS_BUILTIN_REGULAR(cmdp->param.cmd) ? 0 : DO_REGBLTIN;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (act & bit) {
|
if (act & bit) {
|
||||||
|
if (act & bit & DO_REGBLTIN)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
updatetbl = 0;
|
updatetbl = 0;
|
||||||
cmdp = NULL;
|
cmdp = NULL;
|
||||||
} else if (cmdp->rehash == 0)
|
} else if (cmdp->rehash == 0)
|
||||||
@ -13577,14 +13581,15 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
|
|||||||
if (bcmd) {
|
if (bcmd) {
|
||||||
if (IS_BUILTIN_REGULAR(bcmd))
|
if (IS_BUILTIN_REGULAR(bcmd))
|
||||||
goto builtin_success;
|
goto builtin_success;
|
||||||
if (act & DO_ALTPATH) {
|
if (act & DO_ALTPATH)
|
||||||
if (!(act & DO_ALTBLTIN))
|
goto builtin_success;
|
||||||
goto builtin_success;
|
if (builtinloc <= 0)
|
||||||
} else if (builtinloc <= 0) {
|
|
||||||
goto builtin_success;
|
goto builtin_success;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (act & DO_REGBLTIN)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
#if ENABLE_FEATURE_SH_STANDALONE
|
#if ENABLE_FEATURE_SH_STANDALONE
|
||||||
{
|
{
|
||||||
int applet_no = find_applet_by_name(name);
|
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
|
#endif
|
||||||
ash_msg("%s: %s", name, errmsg(e, "not found"));
|
ash_msg("%s: %s", name, errmsg(e, "not found"));
|
||||||
}
|
}
|
||||||
|
fail:
|
||||||
entry->cmdtype = CMDUNKNOWN;
|
entry->cmdtype = CMDUNKNOWN;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user