aboutsummaryrefslogtreecommitdiff
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
parentc91950f31532febe34e00ab20d3e5f462d9daa52 (diff)
downloadbusybox-w32-7eb8eecbbc752d04381f35d196bbdf1e3b17e2d1.tar.gz
busybox-w32-7eb8eecbbc752d04381f35d196bbdf1e3b17e2d1.tar.bz2
busybox-w32-7eb8eecbbc752d04381f35d196bbdf1e3b17e2d1.zip
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>
-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 {
8112#define DO_ABS 0x02 /* checks absolute paths */ 8112#define DO_ABS 0x02 /* checks absolute paths */
8113#define DO_NOFUNC 0x04 /* don't return shell functions, for command */ 8113#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
8114#define DO_ALTPATH 0x08 /* using alternate path */ 8114#define DO_ALTPATH 0x08 /* using alternate path */
8115#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */ 8115#define DO_REGBLTIN 0x10 /* regular built-ins and functions only */
8116 8116
8117static void find_command(char *, struct cmdentry *, int, const char *); 8117static void find_command(char *, struct cmdentry *, int, const char *);
8118 8118
@@ -8718,24 +8718,43 @@ typecmd(int argc UNUSED_PARAM, char **argv)
8718} 8718}
8719 8719
8720#if ENABLE_ASH_CMDCMD 8720#if ENABLE_ASH_CMDCMD
8721static struct strlist *
8722fill_arglist(struct arglist *arglist, union node **argpp)
8723{
8724 struct strlist **lastp = arglist->lastp;
8725 union node *argp;
8726
8727 while ((argp = *argpp) != NULL) {
8728 expandarg(argp, arglist, EXP_FULL | EXP_TILDE);
8729 *argpp = argp->narg.next;
8730 if (*lastp)
8731 break;
8732 }
8733
8734 return *lastp;
8735}
8736
8721/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */ 8737/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8722static char ** 8738static int
8723parse_command_args(char **argv, const char **path) 8739parse_command_args(struct arglist *arglist, union node **argpp, const char **path)
8724{ 8740{
8741 struct strlist *sp = arglist->list;
8725 char *cp, c; 8742 char *cp, c;
8726 8743
8727 for (;;) { 8744 for (;;) {
8728 cp = *++argv; 8745 sp = sp->next ? sp->next : fill_arglist(arglist, argpp);
8729 if (!cp) 8746 if (!sp)
8730 return NULL; 8747 return 0;
8748 cp = sp->text;
8731 if (*cp++ != '-') 8749 if (*cp++ != '-')
8732 break; 8750 break;
8733 c = *cp++; 8751 c = *cp++;
8734 if (!c) 8752 if (!c)
8735 break; 8753 break;
8736 if (c == '-' && !*cp) { 8754 if (c == '-' && !*cp) {
8737 if (!*++argv) 8755 if (!sp->next && !fill_arglist(arglist, argpp))
8738 return NULL; 8756 return 0;
8757 sp = sp->next;
8739 break; 8758 break;
8740 } 8759 }
8741 do { 8760 do {
@@ -8745,12 +8764,14 @@ parse_command_args(char **argv, const char **path)
8745 break; 8764 break;
8746 default: 8765 default:
8747 /* run 'typecmd' for other options */ 8766 /* run 'typecmd' for other options */
8748 return NULL; 8767 return 0;
8749 } 8768 }
8750 c = *cp++; 8769 c = *cp++;
8751 } while (c); 8770 } while (c);
8752 } 8771 }
8753 return argv; 8772
8773 arglist->list = sp;
8774 return DO_NOFUNC;
8754} 8775}
8755 8776
8756static int FAST_FUNC 8777static int FAST_FUNC
@@ -10124,7 +10145,7 @@ static int
10124evalcommand(union node *cmd, int flags) 10145evalcommand(union node *cmd, int flags)
10125{ 10146{
10126 static const struct builtincmd null_bltin = { 10147 static const struct builtincmd null_bltin = {
10127 "\0\0", bltincmd /* why three NULs? */ 10148 BUILTIN_REGULAR "", bltincmd
10128 }; 10149 };
10129 struct localvar_list *localvar_stop; 10150 struct localvar_list *localvar_stop;
10130 struct parsefile *file_stop; 10151 struct parsefile *file_stop;
@@ -10134,12 +10155,14 @@ evalcommand(union node *cmd, int flags)
10134 struct arglist varlist; 10155 struct arglist varlist;
10135 char **argv; 10156 char **argv;
10136 int argc; 10157 int argc;
10158 struct strlist *osp;
10137 const struct strlist *sp; 10159 const struct strlist *sp;
10138 struct cmdentry cmdentry; 10160 struct cmdentry cmdentry;
10139 struct job *jp; 10161 struct job *jp;
10140 char *lastarg; 10162 char *lastarg;
10141 const char *path; 10163 const char *path;
10142 int spclbltin; 10164 int spclbltin;
10165 int cmd_flag;
10143 int status; 10166 int status;
10144 char **nargv; 10167 char **nargv;
10145 smallint cmd_is_exec; 10168 smallint cmd_is_exec;
@@ -10161,26 +10184,46 @@ evalcommand(union node *cmd, int flags)
10161 arglist.lastp = &arglist.list; 10184 arglist.lastp = &arglist.list;
10162 *arglist.lastp = NULL; 10185 *arglist.lastp = NULL;
10163 10186
10187 cmd_flag = 0;
10188 cmd_is_exec = 0;
10189 spclbltin = -1;
10190 path = NULL;
10191
10164 argc = 0; 10192 argc = 0;
10165 if (cmd->ncmd.args) { 10193 argp = cmd->ncmd.args;
10166 struct builtincmd *bcmd; 10194 osp = fill_arglist(&arglist, &argp);
10167 smallint pseudovarflag; 10195 if (osp) {
10196 int pseudovarflag = 0;
10168 10197
10169 bcmd = find_builtin(cmd->ncmd.args->narg.text); 10198 for (;;) {
10170 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd); 10199 find_command(arglist.list->text, &cmdentry,
10200 cmd_flag | DO_REGBLTIN, pathval());
10171 10201
10172 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) { 10202 /* implement bltin and command here */
10173 struct strlist **spp; 10203 if (cmdentry.cmdtype != CMDBUILTIN)
10204 break;
10174 10205
10175 spp = arglist.lastp; 10206 pseudovarflag = IS_BUILTIN_ASSIGN(cmdentry.u.cmd);
10176 if (pseudovarflag && isassignment(argp->narg.text)) 10207 if (spclbltin < 0) {
10177 expandarg(argp, &arglist, EXP_VARTILDE); 10208 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
10178 else 10209 }
10179 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 10210 cmd_is_exec = cmdentry.u.cmd == EXECCMD;
10211 if (cmdentry.u.cmd != COMMANDCMD)
10212 break;
10180 10213
10181 for (sp = *spp; sp; sp = sp->next) 10214 cmd_flag = parse_command_args(&arglist, &argp, &path);
10182 argc++; 10215 if (!cmd_flag)
10216 break;
10183 } 10217 }
10218
10219 for (; argp; argp = argp->narg.next)
10220 expandarg(argp, &arglist,
10221 pseudovarflag &&
10222 isassignment(argp->narg.text) ?
10223 EXP_VARTILDE : EXP_FULL | EXP_TILDE);
10224
10225 for (sp = arglist.list; sp; sp = sp->next)
10226 argc++;
10184 } 10227 }
10185 10228
10186 /* Reserve one extra spot at the front for shellexec. */ 10229 /* Reserve one extra spot at the front for shellexec. */
@@ -10210,23 +10253,13 @@ evalcommand(union node *cmd, int flags)
10210 } 10253 }
10211 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2); 10254 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
10212 10255
10213 path = vpath.var_text;
10214 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { 10256 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
10215 struct strlist **spp; 10257 struct strlist **spp;
10216 char *p;
10217 10258
10218 spp = varlist.lastp; 10259 spp = varlist.lastp;
10219 expandarg(argp, &varlist, EXP_VARTILDE); 10260 expandarg(argp, &varlist, EXP_VARTILDE);
10220 10261
10221 mklocal((*spp)->text); 10262 mklocal((*spp)->text);
10222
10223 /*
10224 * Modify the command lookup path, if a PATH= assignment
10225 * is present
10226 */
10227 p = (*spp)->text;
10228 if (varcmp(p, path) == 0)
10229 path = p;
10230 } 10263 }
10231 10264
10232 /* Print the command if xflag is set. */ 10265 /* Print the command if xflag is set. */
@@ -10265,46 +10298,16 @@ evalcommand(union node *cmd, int flags)
10265 safe_write(preverrout_fd, "\n", 1); 10298 safe_write(preverrout_fd, "\n", 1);
10266 } 10299 }
10267 10300
10268 cmd_is_exec = 0;
10269 spclbltin = -1;
10270
10271 /* Now locate the command. */ 10301 /* Now locate the command. */
10272 if (argc) { 10302 if (cmdentry.cmdtype != CMDBUILTIN
10273 int cmd_flag = DO_ERR; 10303 || !(IS_BUILTIN_REGULAR(cmdentry.u.cmd))
10274#if ENABLE_ASH_CMDCMD 10304 ) {
10275 const char *oldpath = path + 5; 10305 find_command(argv[0], &cmdentry, cmd_flag | DO_ERR,
10276#endif 10306 path ? path : pathval());
10277 path += 5; 10307 if (cmdentry.cmdtype == CMDUNKNOWN) {
10278 for (;;) { 10308 status = 127;
10279 find_command(argv[0], &cmdentry, cmd_flag, path); 10309 flush_stdout_stderr();
10280 if (cmdentry.cmdtype == CMDUNKNOWN) { 10310 goto bail;
10281 flush_stdout_stderr();
10282 status = 127;
10283 goto bail;
10284 }
10285
10286 /* implement bltin and command here */
10287 if (cmdentry.cmdtype != CMDBUILTIN)
10288 break;
10289 if (spclbltin < 0)
10290 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
10291 if (cmdentry.u.cmd == EXECCMD)
10292 cmd_is_exec = 1;
10293#if ENABLE_ASH_CMDCMD
10294 if (cmdentry.u.cmd == COMMANDCMD) {
10295 path = oldpath;
10296 nargv = parse_command_args(argv, &path);
10297 if (!nargv)
10298 break;
10299 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
10300 * nargv => "PROG". path is updated if -p.
10301 */
10302 argc -= nargv - argv;
10303 argv = nargv;
10304 cmd_flag |= DO_NOFUNC;
10305 } else
10306#endif
10307 break;
10308 } 10311 }
10309 } 10312 }
10310 10313
@@ -10383,6 +10386,7 @@ evalcommand(union node *cmd, int flags)
10383 /* fall through to exec'ing external program */ 10386 /* fall through to exec'ing external program */
10384 } 10387 }
10385 listsetvar(varlist.list, VEXPORT|VSTACK); 10388 listsetvar(varlist.list, VEXPORT|VSTACK);
10389 path = path ? path : pathval();
10386 shellexec(argv[0], argv, path, cmdentry.u.index); 10390 shellexec(argv[0], argv, path, cmdentry.u.index);
10387 /* NOTREACHED */ 10391 /* NOTREACHED */
10388 } /* default */ 10392 } /* default */
@@ -13538,11 +13542,8 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
13538/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */ 13542/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
13539 13543
13540 updatetbl = (path == pathval()); 13544 updatetbl = (path == pathval());
13541 if (!updatetbl) { 13545 if (!updatetbl)
13542 act |= DO_ALTPATH; 13546 act |= DO_ALTPATH;
13543 if (strstr(path, "%builtin") != NULL)
13544 act |= DO_ALTBLTIN;
13545 }
13546 13547
13547 /* If name is in the table, check answer will be ok */ 13548 /* If name is in the table, check answer will be ok */
13548 cmdp = cmdlookup(name, 0); 13549 cmdp = cmdlookup(name, 0);
@@ -13555,16 +13556,19 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
13555 abort(); 13556 abort();
13556#endif 13557#endif
13557 case CMDNORMAL: 13558 case CMDNORMAL:
13558 bit = DO_ALTPATH; 13559 bit = DO_ALTPATH | DO_REGBLTIN;
13559 break; 13560 break;
13560 case CMDFUNCTION: 13561 case CMDFUNCTION:
13561 bit = DO_NOFUNC; 13562 bit = DO_NOFUNC;
13562 break; 13563 break;
13563 case CMDBUILTIN: 13564 case CMDBUILTIN:
13564 bit = IS_BUILTIN_REGULAR(cmdp->param.cmd) ? 0 : DO_ALTBLTIN; 13565 bit = IS_BUILTIN_REGULAR(cmdp->param.cmd) ? 0 : DO_REGBLTIN;
13565 break; 13566 break;
13566 } 13567 }
13567 if (act & bit) { 13568 if (act & bit) {
13569 if (act & bit & DO_REGBLTIN)
13570 goto fail;
13571
13568 updatetbl = 0; 13572 updatetbl = 0;
13569 cmdp = NULL; 13573 cmdp = NULL;
13570 } else if (cmdp->rehash == 0) 13574 } else if (cmdp->rehash == 0)
@@ -13577,14 +13581,15 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
13577 if (bcmd) { 13581 if (bcmd) {
13578 if (IS_BUILTIN_REGULAR(bcmd)) 13582 if (IS_BUILTIN_REGULAR(bcmd))
13579 goto builtin_success; 13583 goto builtin_success;
13580 if (act & DO_ALTPATH) { 13584 if (act & DO_ALTPATH)
13581 if (!(act & DO_ALTBLTIN)) 13585 goto builtin_success;
13582 goto builtin_success; 13586 if (builtinloc <= 0)
13583 } else if (builtinloc <= 0) {
13584 goto builtin_success; 13587 goto builtin_success;
13585 }
13586 } 13588 }
13587 13589
13590 if (act & DO_REGBLTIN)
13591 goto fail;
13592
13588#if ENABLE_FEATURE_SH_STANDALONE 13593#if ENABLE_FEATURE_SH_STANDALONE
13589 { 13594 {
13590 int applet_no = find_applet_by_name(name); 13595 int applet_no = find_applet_by_name(name);
@@ -13688,6 +13693,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
13688#endif 13693#endif
13689 ash_msg("%s: %s", name, errmsg(e, "not found")); 13694 ash_msg("%s: %s", name, errmsg(e, "not found"));
13690 } 13695 }
13696 fail:
13691 entry->cmdtype = CMDUNKNOWN; 13697 entry->cmdtype = CMDUNKNOWN;
13692 return; 13698 return;
13693 13699