aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2020-02-21 12:55:36 +0000
committerRon Yorston <rmy@pobox.com>2020-02-21 12:55:36 +0000
commit63c8e755021cf35c8a94ea1291c1e123164a7917 (patch)
treec971d1e74f99b57d61759cff536e47eee9480157
parent896d625cc9e03a726d535da18539602763769d3b (diff)
parente2dd2afc8e4dbcf1061818adc68d2e74a1fa64d3 (diff)
downloadbusybox-w32-63c8e755021cf35c8a94ea1291c1e123164a7917.tar.gz
busybox-w32-63c8e755021cf35c8a94ea1291c1e123164a7917.tar.bz2
busybox-w32-63c8e755021cf35c8a94ea1291c1e123164a7917.zip
ash: merge changes to local variables from upstream
This brings in dash commit cbb71a8 (eval: Add assignment built-in support again) which finally makes it possible to sort out local commit 65189dacb (ash: fix local PATH assignments). These changes also simplify handling of shellexec and remove the need for varlist in the forkshell structure.
-rw-r--r--shell/ash.c311
-rw-r--r--shell/ash_test/ash-misc/exitcode_trap2.right1
-rwxr-xr-xshell/ash_test/ash-misc/exitcode_trap2.tests9
-rw-r--r--shell/ash_test/ash-redir/redir_exec1.right1
-rw-r--r--shell/hush_test/hush-misc/exitcode_trap2.right1
-rwxr-xr-xshell/hush_test/hush-misc/exitcode_trap2.tests9
6 files changed, 156 insertions, 176 deletions
diff --git a/shell/ash.c b/shell/ash.c
index cd15d44a6..f33f72b80 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -380,7 +380,6 @@ struct forkshell {
380 union node *n; 380 union node *n;
381 char **argv; 381 char **argv;
382 char *path; 382 char *path;
383 struct strlist *varlist;
384}; 383};
385 384
386enum { 385enum {
@@ -2699,24 +2698,6 @@ unsetvar(const char *s)
2699} 2698}
2700 2699
2701/* 2700/*
2702 * Process a linked list of variable assignments.
2703 */
2704static void
2705listsetvar(struct strlist *list_set_var, int flags)
2706{
2707 struct strlist *lp = list_set_var;
2708
2709 if (!lp)
2710 return;
2711 INT_OFF;
2712 do {
2713 setvareq(lp->text, flags);
2714 lp = lp->next;
2715 } while (lp);
2716 INT_ON;
2717}
2718
2719/*
2720 * Generate a list of variables satisfying the given conditions. 2701 * Generate a list of variables satisfying the given conditions.
2721 */ 2702 */
2722#if !ENABLE_FEATURE_SH_NOFORK 2703#if !ENABLE_FEATURE_SH_NOFORK
@@ -8663,7 +8644,7 @@ struct cmdentry {
8663#define DO_ABS 0x02 /* checks absolute paths */ 8644#define DO_ABS 0x02 /* checks absolute paths */
8664#define DO_NOFUNC 0x04 /* don't return shell functions, for command */ 8645#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
8665#define DO_ALTPATH 0x08 /* using alternate path */ 8646#define DO_ALTPATH 0x08 /* using alternate path */
8666#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */ 8647#define DO_REGBLTIN 0x10 /* regular built-ins and functions only */
8667 8648
8668static void find_command(char *, struct cmdentry *, int, const char *); 8649static void find_command(char *, struct cmdentry *, int, const char *);
8669 8650
@@ -9281,24 +9262,43 @@ typecmd(int argc UNUSED_PARAM, char **argv)
9281} 9262}
9282 9263
9283#if ENABLE_ASH_CMDCMD 9264#if ENABLE_ASH_CMDCMD
9265static struct strlist *
9266fill_arglist(struct arglist *arglist, union node **argpp)
9267{
9268 struct strlist **lastp = arglist->lastp;
9269 union node *argp;
9270
9271 while ((argp = *argpp) != NULL) {
9272 expandarg(argp, arglist, EXP_FULL | EXP_TILDE);
9273 *argpp = argp->narg.next;
9274 if (*lastp)
9275 break;
9276 }
9277
9278 return *lastp;
9279}
9280
9284/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */ 9281/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
9285static char ** 9282static int
9286parse_command_args(char **argv, const char **path) 9283parse_command_args(struct arglist *arglist, union node **argpp, const char **path)
9287{ 9284{
9285 struct strlist *sp = arglist->list;
9288 char *cp, c; 9286 char *cp, c;
9289 9287
9290 for (;;) { 9288 for (;;) {
9291 cp = *++argv; 9289 sp = sp->next ? sp->next : fill_arglist(arglist, argpp);
9292 if (!cp) 9290 if (!sp)
9293 return NULL; 9291 return 0;
9292 cp = sp->text;
9294 if (*cp++ != '-') 9293 if (*cp++ != '-')
9295 break; 9294 break;
9296 c = *cp++; 9295 c = *cp++;
9297 if (!c) 9296 if (!c)
9298 break; 9297 break;
9299 if (c == '-' && !*cp) { 9298 if (c == '-' && !*cp) {
9300 if (!*++argv) 9299 if (!sp->next && !fill_arglist(arglist, argpp))
9301 return NULL; 9300 return 0;
9301 sp = sp->next;
9302 break; 9302 break;
9303 } 9303 }
9304 do { 9304 do {
@@ -9308,12 +9308,14 @@ parse_command_args(char **argv, const char **path)
9308 break; 9308 break;
9309 default: 9309 default:
9310 /* run 'typecmd' for other options */ 9310 /* run 'typecmd' for other options */
9311 return NULL; 9311 return 0;
9312 } 9312 }
9313 c = *cp++; 9313 c = *cp++;
9314 } while (c); 9314 } while (c);
9315 } 9315 }
9316 return argv; 9316
9317 arglist->list = sp;
9318 return DO_NOFUNC;
9317} 9319}
9318 9320
9319static int FAST_FUNC 9321static int FAST_FUNC
@@ -10397,18 +10399,23 @@ poplocalvars(int keep)
10397 * Create a new localvar environment. 10399 * Create a new localvar environment.
10398 */ 10400 */
10399static struct localvar_list * 10401static struct localvar_list *
10400pushlocalvars(void) 10402pushlocalvars(int push)
10401{ 10403{
10402 struct localvar_list *ll; 10404 struct localvar_list *ll;
10405 struct localvar_list *top;
10406
10407 top = localvar_stack;
10408 if (!push)
10409 goto out;
10403 10410
10404 INT_OFF; 10411 INT_OFF;
10405 ll = ckzalloc(sizeof(*ll)); 10412 ll = ckzalloc(sizeof(*ll));
10406 /*ll->lv = NULL; - zalloc did it */ 10413 /*ll->lv = NULL; - zalloc did it */
10407 ll->next = localvar_stack; 10414 ll->next = top;
10408 localvar_stack = ll; 10415 localvar_stack = ll;
10409 INT_ON; 10416 INT_ON;
10410 10417 out:
10411 return ll->next; 10418 return top;
10412} 10419}
10413 10420
10414static void 10421static void
@@ -10467,7 +10474,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
10467 * (options will be restored on return from the function). 10474 * (options will be restored on return from the function).
10468 */ 10475 */
10469static void 10476static void
10470mklocal(char *name) 10477mklocal(char *name, int flags)
10471{ 10478{
10472 struct localvar *lvp; 10479 struct localvar *lvp;
10473 struct var **vpp; 10480 struct var **vpp;
@@ -10504,9 +10511,9 @@ mklocal(char *name)
10504 if (vp == NULL) { 10511 if (vp == NULL) {
10505 /* variable did not exist yet */ 10512 /* variable did not exist yet */
10506 if (eq) 10513 if (eq)
10507 vp = setvareq(name, VSTRFIXED); 10514 vp = setvareq(name, VSTRFIXED | flags);
10508 else 10515 else
10509 vp = setvar(name, NULL, VSTRFIXED); 10516 vp = setvar(name, NULL, VSTRFIXED | flags);
10510 lvp->flags = VUNSET; 10517 lvp->flags = VUNSET;
10511 } else { 10518 } else {
10512 lvp->text = vp->var_text; 10519 lvp->text = vp->var_text;
@@ -10516,7 +10523,7 @@ mklocal(char *name)
10516 */ 10523 */
10517 vp->flags |= VSTRFIXED|VTEXTFIXED; 10524 vp->flags |= VSTRFIXED|VTEXTFIXED;
10518 if (eq) 10525 if (eq)
10519 setvareq(name, 0); 10526 setvareq(name, flags);
10520 else 10527 else
10521 /* "local VAR" unsets VAR: */ 10528 /* "local VAR" unsets VAR: */
10522 setvar0(name, NULL); 10529 setvar0(name, NULL);
@@ -10542,7 +10549,7 @@ localcmd(int argc UNUSED_PARAM, char **argv)
10542 10549
10543 argv = argptr; 10550 argv = argptr;
10544 while ((name = *argv++) != NULL) { 10551 while ((name = *argv++) != NULL) {
10545 mklocal(name); 10552 mklocal(name, 0);
10546 } 10553 }
10547 return 0; 10554 return 0;
10548} 10555}
@@ -10803,7 +10810,7 @@ static int
10803evalcommand(union node *cmd, int flags) 10810evalcommand(union node *cmd, int flags)
10804{ 10811{
10805 static const struct builtincmd null_bltin = { 10812 static const struct builtincmd null_bltin = {
10806 "\0\0", bltincmd /* why three NULs? */ 10813 BUILTIN_REGULAR "", bltincmd
10807 }; 10814 };
10808 struct localvar_list *localvar_stop; 10815 struct localvar_list *localvar_stop;
10809 struct parsefile *file_stop; 10816 struct parsefile *file_stop;
@@ -10813,18 +10820,19 @@ evalcommand(union node *cmd, int flags)
10813 struct arglist varlist; 10820 struct arglist varlist;
10814 char **argv; 10821 char **argv;
10815 int argc; 10822 int argc;
10823 struct strlist *osp;
10816 const struct strlist *sp; 10824 const struct strlist *sp;
10817 struct cmdentry cmdentry; 10825 struct cmdentry cmdentry;
10818 struct job *jp; 10826 struct job *jp;
10819 char *lastarg; 10827 char *lastarg;
10820 const char *path; 10828 const char *path;
10821 int spclbltin; 10829 int spclbltin;
10830 int cmd_flag;
10822 int status; 10831 int status;
10823 char **nargv; 10832 char **nargv;
10824 smallint cmd_is_exec; 10833 smallint cmd_is_exec;
10825#if ENABLE_PLATFORM_MINGW32 10834 int vflags;
10826 int cmdpath; 10835 int vlocal;
10827#endif
10828 10836
10829 errlinno = lineno = cmd->ncmd.linno; 10837 errlinno = lineno = cmd->ncmd.linno;
10830 if (funcline) 10838 if (funcline)
@@ -10832,7 +10840,6 @@ evalcommand(union node *cmd, int flags)
10832 10840
10833 /* First expand the arguments. */ 10841 /* First expand the arguments. */
10834 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); 10842 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
10835 localvar_stop = pushlocalvars();
10836 file_stop = g_parsefile; 10843 file_stop = g_parsefile;
10837 back_exitstatus = 0; 10844 back_exitstatus = 0;
10838 10845
@@ -10843,28 +10850,58 @@ evalcommand(union node *cmd, int flags)
10843 arglist.lastp = &arglist.list; 10850 arglist.lastp = &arglist.list;
10844 *arglist.lastp = NULL; 10851 *arglist.lastp = NULL;
10845 10852
10853 cmd_flag = 0;
10854 cmd_is_exec = 0;
10855 spclbltin = -1;
10856 vflags = 0;
10857 vlocal = 0;
10858 path = NULL;
10859
10846 argc = 0; 10860 argc = 0;
10847 if (cmd->ncmd.args) { 10861 argp = cmd->ncmd.args;
10848 struct builtincmd *bcmd; 10862 osp = fill_arglist(&arglist, &argp);
10849 smallint pseudovarflag; 10863 if (osp) {
10864 int pseudovarflag = 0;
10850 10865
10851 bcmd = find_builtin(cmd->ncmd.args->narg.text); 10866 for (;;) {
10852 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd); 10867 find_command(arglist.list->text, &cmdentry,
10868 cmd_flag | DO_REGBLTIN, pathval());
10853 10869
10854 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) { 10870 vlocal++;
10855 struct strlist **spp;
10856 10871
10857 spp = arglist.lastp; 10872 /* implement bltin and command here */
10858 if (pseudovarflag && isassignment(argp->narg.text)) 10873 if (cmdentry.cmdtype != CMDBUILTIN)
10859 expandarg(argp, &arglist, EXP_VARTILDE); 10874 break;
10860 else
10861 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
10862 10875
10863 for (sp = *spp; sp; sp = sp->next) 10876 pseudovarflag = IS_BUILTIN_ASSIGN(cmdentry.u.cmd);
10864 argc++; 10877 if (spclbltin < 0) {
10878 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
10879 vlocal = !spclbltin;
10880 }
10881 cmd_is_exec = cmdentry.u.cmd == EXECCMD;
10882 if (cmdentry.u.cmd != COMMANDCMD)
10883 break;
10884
10885 cmd_flag = parse_command_args(&arglist, &argp, &path);
10886 if (!cmd_flag)
10887 break;
10865 } 10888 }
10889
10890 for (; argp; argp = argp->narg.next)
10891 expandarg(argp, &arglist,
10892 pseudovarflag &&
10893 isassignment(argp->narg.text) ?
10894 EXP_VARTILDE : EXP_FULL | EXP_TILDE);
10895
10896 for (sp = arglist.list; sp; sp = sp->next)
10897 argc++;
10898
10899 if (cmd_is_exec && argc > 1)
10900 vflags = VEXPORT;
10866 } 10901 }
10867 10902
10903 localvar_stop = pushlocalvars(vlocal);
10904
10868 /* Reserve one extra spot at the front for shellexec. */ 10905 /* Reserve one extra spot at the front for shellexec. */
10869 nargv = stalloc(sizeof(char *) * (argc + 2)); 10906 nargv = stalloc(sizeof(char *) * (argc + 2));
10870 argv = ++nargv; 10907 argv = ++nargv;
@@ -10892,34 +10929,28 @@ evalcommand(union node *cmd, int flags)
10892 } 10929 }
10893 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2); 10930 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
10894 10931
10895#if !ENABLE_PLATFORM_MINGW32 10932 if (status) {
10896 path = vpath.var_text; 10933 bail:
10934 exitstatus = status;
10935
10936 /* We have a redirection error. */
10937 if (spclbltin > 0)
10938 raise_exception(EXERROR);
10939
10940 goto out;
10941 }
10942
10897 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { 10943 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
10898 struct strlist **spp; 10944 struct strlist **spp;
10899 char *p;
10900 10945
10901 spp = varlist.lastp; 10946 spp = varlist.lastp;
10902 expandarg(argp, &varlist, EXP_VARTILDE); 10947 expandarg(argp, &varlist, EXP_VARTILDE);
10903 10948
10904 mklocal((*spp)->text); 10949 if (vlocal)
10905 10950 mklocal((*spp)->text, VEXPORT);
10906 /* 10951 else
10907 * Modify the command lookup path, if a PATH= assignment 10952 setvareq((*spp)->text, vflags);
10908 * is present
10909 */
10910 p = (*spp)->text;
10911 if (varcmp(p, path) == 0)
10912 path = p;
10913 }
10914#else
10915 /* Set path after any local PATH= has been processed. */
10916 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
10917 struct strlist **spp = varlist.lastp;
10918 expandarg(argp, &varlist, EXP_VARTILDE);
10919 mklocal((*spp)->text);
10920 } 10953 }
10921 path = vpath.var_text;
10922#endif
10923 10954
10924 /* Print the command if xflag is set. */ 10955 /* Print the command if xflag is set. */
10925 if (xflag) { 10956 if (xflag) {
@@ -10957,64 +10988,23 @@ evalcommand(union node *cmd, int flags)
10957 safe_write(preverrout_fd, "\n", 1); 10988 safe_write(preverrout_fd, "\n", 1);
10958 } 10989 }
10959 10990
10960 cmd_is_exec = 0;
10961 spclbltin = -1;
10962
10963 /* Now locate the command. */ 10991 /* Now locate the command. */
10964 if (argc) { 10992 if (cmdentry.cmdtype != CMDBUILTIN
10965 int cmd_flag = DO_ERR; 10993 || !(IS_BUILTIN_REGULAR(cmdentry.u.cmd))
10966#if ENABLE_ASH_CMDCMD 10994 ) {
10967 const char *oldpath = path + 5; 10995 path = path ? path : pathval();
10968#endif 10996 find_command(argv[0], &cmdentry, cmd_flag | DO_ERR, path);
10969 path += 5;
10970 for (;;) {
10971 find_command(argv[0], &cmdentry, cmd_flag, path);
10972 if (cmdentry.cmdtype == CMDUNKNOWN) {
10973 flush_stdout_stderr();
10974 status = 127;
10975 goto bail;
10976 }
10977
10978 /* implement bltin and command here */
10979 if (cmdentry.cmdtype != CMDBUILTIN)
10980 break;
10981 if (spclbltin < 0)
10982 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
10983 if (cmdentry.u.cmd == EXECCMD)
10984 cmd_is_exec = 1;
10985#if ENABLE_ASH_CMDCMD
10986 if (cmdentry.u.cmd == COMMANDCMD) {
10987 path = oldpath;
10988 nargv = parse_command_args(argv, &path);
10989 if (!nargv)
10990 break;
10991 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
10992 * nargv => "PROG". path is updated if -p.
10993 */
10994 argc -= nargv - argv;
10995 argv = nargv;
10996 cmd_flag |= DO_NOFUNC;
10997 } else
10998#endif
10999 break;
11000 }
11001 }
11002
11003 if (status) {
11004 bail:
11005 exitstatus = status;
11006
11007 /* We have a redirection error. */
11008 if (spclbltin > 0)
11009 raise_exception(EXERROR);
11010
11011 goto out;
11012 } 10997 }
11013 10998
11014 jp = NULL; 10999 jp = NULL;
11015 11000
11016 /* Execute the command. */ 11001 /* Execute the command. */
11017 switch (cmdentry.cmdtype) { 11002 switch (cmdentry.cmdtype) {
11003 case CMDUNKNOWN:
11004 status = 127;
11005 flush_stdout_stderr();
11006 goto bail;
11007
11018 default: { 11008 default: {
11019 11009
11020#if ENABLE_FEATURE_SH_STANDALONE \ 11010#if ENABLE_FEATURE_SH_STANDALONE \
@@ -11071,19 +11061,11 @@ evalcommand(union node *cmd, int flags)
11071 fs.argv = argv; 11061 fs.argv = argv;
11072 fs.path = (char*)path; 11062 fs.path = (char*)path;
11073 fs.fd[0] = cmdentry.u.index; 11063 fs.fd[0] = cmdentry.u.index;
11074 fs.varlist = varlist.list;
11075 jp = makejob(/*cmd,*/ 1); 11064 jp = makejob(/*cmd,*/ 1);
11076 spawn_forkshell(&fs, jp, cmd, FORK_FG); 11065 spawn_forkshell(&fs, jp, cmd, FORK_FG);
11077 TRACE(("forked child exited with %d\n", status)); 11066 TRACE(("forked child exited with %d\n", status));
11078 break; 11067 break;
11079 } 11068 }
11080 /* If we're running 'command -p' we need to use the value stored
11081 * in path by parse_command_args(). If PATH is a local variable
11082 * listsetvar() will free the value currently in path so we need
11083 * to fetch the updated version. */
11084 cmdpath = (path != pathval());
11085 listsetvar(varlist.list, VEXPORT|VSTACK);
11086 shellexec(argv[0], argv, cmdpath ? path : pathval(), cmdentry.u.index);
11087#else 11069#else
11088 if (!(flags & EV_EXIT) || may_have_traps) { 11070 if (!(flags & EV_EXIT) || may_have_traps) {
11089 /* No, forking off a child is necessary */ 11071 /* No, forking off a child is necessary */
@@ -11099,17 +11081,11 @@ evalcommand(union node *cmd, int flags)
11099 FORCE_INT_ON; 11081 FORCE_INT_ON;
11100 /* fall through to exec'ing external program */ 11082 /* fall through to exec'ing external program */
11101 } 11083 }
11102 listsetvar(varlist.list, VEXPORT|VSTACK);
11103 shellexec(argv[0], argv, path, cmdentry.u.index);
11104#endif 11084#endif
11085 shellexec(argv[0], argv, path, cmdentry.u.index);
11105 /* NOTREACHED */ 11086 /* NOTREACHED */
11106 } /* default */ 11087 } /* default */
11107 case CMDBUILTIN: 11088 case CMDBUILTIN:
11108 if (spclbltin > 0 || argc == 0) {
11109 poplocalvars(1);
11110 if (cmd_is_exec && argc > 1)
11111 listsetvar(varlist.list, VEXPORT);
11112 }
11113 if (evalbltin(cmdentry.u.cmd, argc, argv, flags) 11089 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)
11114 && !(exception_type == EXERROR && spclbltin <= 0) 11090 && !(exception_type == EXERROR && spclbltin <= 0)
11115 ) { 11091 ) {
@@ -14290,11 +14266,8 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
14290/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */ 14266/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
14291 14267
14292 updatetbl = (path == pathval()); 14268 updatetbl = (path == pathval());
14293 if (!updatetbl) { 14269 if (!updatetbl)
14294 act |= DO_ALTPATH; 14270 act |= DO_ALTPATH;
14295 if (strstr(path, "%builtin") != NULL)
14296 act |= DO_ALTBLTIN;
14297 }
14298 14271
14299 /* If name is in the table, check answer will be ok */ 14272 /* If name is in the table, check answer will be ok */
14300 cmdp = cmdlookup(name, 0); 14273 cmdp = cmdlookup(name, 0);
@@ -14307,16 +14280,19 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
14307 abort(); 14280 abort();
14308#endif 14281#endif
14309 case CMDNORMAL: 14282 case CMDNORMAL:
14310 bit = DO_ALTPATH; 14283 bit = DO_ALTPATH | DO_REGBLTIN;
14311 break; 14284 break;
14312 case CMDFUNCTION: 14285 case CMDFUNCTION:
14313 bit = DO_NOFUNC; 14286 bit = DO_NOFUNC;
14314 break; 14287 break;
14315 case CMDBUILTIN: 14288 case CMDBUILTIN:
14316 bit = IS_BUILTIN_REGULAR(cmdp->param.cmd) ? 0 : DO_ALTBLTIN; 14289 bit = IS_BUILTIN_REGULAR(cmdp->param.cmd) ? 0 : DO_REGBLTIN;
14317 break; 14290 break;
14318 } 14291 }
14319 if (act & bit) { 14292 if (act & bit) {
14293 if (act & bit & DO_REGBLTIN)
14294 goto fail;
14295
14320 updatetbl = 0; 14296 updatetbl = 0;
14321 cmdp = NULL; 14297 cmdp = NULL;
14322 } else if (cmdp->rehash == 0) 14298 } else if (cmdp->rehash == 0)
@@ -14329,14 +14305,15 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
14329 if (bcmd) { 14305 if (bcmd) {
14330 if (IS_BUILTIN_REGULAR(bcmd)) 14306 if (IS_BUILTIN_REGULAR(bcmd))
14331 goto builtin_success; 14307 goto builtin_success;
14332 if (act & DO_ALTPATH) { 14308 if (act & DO_ALTPATH)
14333 if (!(act & DO_ALTBLTIN)) 14309 goto builtin_success;
14334 goto builtin_success; 14310 if (builtinloc <= 0)
14335 } else if (builtinloc <= 0) {
14336 goto builtin_success; 14311 goto builtin_success;
14337 }
14338 } 14312 }
14339 14313
14314 if (act & DO_REGBLTIN)
14315 goto fail;
14316
14340#if ENABLE_FEATURE_SH_STANDALONE 14317#if ENABLE_FEATURE_SH_STANDALONE
14341 { 14318 {
14342 int applet_no = find_applet_by_name(name); 14319 int applet_no = find_applet_by_name(name);
@@ -14443,6 +14420,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
14443#endif 14420#endif
14444 ash_msg("%s: %s", name, errmsg(e, "not found")); 14421 ash_msg("%s: %s", name, errmsg(e, "not found"));
14445 } 14422 }
14423 fail:
14446 entry->cmdtype = CMDUNKNOWN; 14424 entry->cmdtype = CMDUNKNOWN;
14447 return; 14425 return;
14448 14426
@@ -15565,12 +15543,10 @@ static void
15565forkshell_shellexec(struct forkshell *fs) 15543forkshell_shellexec(struct forkshell *fs)
15566{ 15544{
15567 int idx = fs->fd[0]; 15545 int idx = fs->fd[0];
15568 struct strlist *varlist = fs->varlist;
15569 char **argv = fs->argv; 15546 char **argv = fs->argv;
15570 char *path = fs->path; 15547 char *path = fs->path;
15571 15548
15572 FORCE_INT_ON; 15549 FORCE_INT_ON;
15573 listsetvar(varlist, VEXPORT|VSTACK);
15574 shellexec(argv[0], argv, path, idx); 15550 shellexec(argv[0], argv, path, idx);
15575} 15551}
15576 15552
@@ -15736,18 +15712,6 @@ SAVE_PTR((*vpp)->var_text, xasprintf("(*vpp)->var_text '%s'", vp->var_text ?: "N
15736SLIST_COPY_END() 15712SLIST_COPY_END()
15737 15713
15738/* 15714/*
15739 * struct strlist
15740 */
15741SLIST_SIZE_BEGIN(strlist_size,struct strlist)
15742ds.funcstringsize += align_len(p->text);
15743SLIST_SIZE_END()
15744
15745SLIST_COPY_BEGIN(strlist_copy,struct strlist)
15746(*vpp)->text = nodeckstrdup(vp->text);
15747SAVE_PTR((*vpp)->text, xasprintf("(*vpp)->text '%s'", vp->text ?: "NULL"), FREE);
15748SLIST_COPY_END()
15749
15750/*
15751 * struct tblentry 15715 * struct tblentry
15752 */ 15716 */
15753static struct datasize 15717static struct datasize
@@ -16068,7 +16032,6 @@ forkshell_size(struct forkshell *fs)
16068 ds.funcblocksize = calcsize(ds.funcblocksize, fs->n); 16032 ds.funcblocksize = calcsize(ds.funcblocksize, fs->n);
16069 ds = argv_size(ds, fs->argv); 16033 ds = argv_size(ds, fs->argv);
16070 ds.funcstringsize += align_len(fs->path); 16034 ds.funcstringsize += align_len(fs->path);
16071 ds = strlist_size(ds, fs->varlist);
16072 16035
16073#if MAX_HISTORY 16036#if MAX_HISTORY
16074 if (line_input_state) { 16037 if (line_input_state) {
@@ -16097,11 +16060,9 @@ forkshell_copy(struct forkshell *fs, struct forkshell *new)
16097 new->n = copynode(fs->n); 16060 new->n = copynode(fs->n);
16098 new->argv = argv_copy(fs->argv); 16061 new->argv = argv_copy(fs->argv);
16099 new->path = nodeckstrdup(fs->path); 16062 new->path = nodeckstrdup(fs->path);
16100 new->varlist = strlist_copy(fs->varlist); 16063 SAVE_PTR3( new->n, "n", NO_FREE,
16101 SAVE_PTR2( new->n, "n", NO_FREE, 16064 new->argv, "argv", NO_FREE,
16102 new->argv, "argv", NO_FREE); 16065 new->path, xasprintf("path '%s'", fs->path ?: "NULL"), FREE);
16103 SAVE_PTR2(new->path, xasprintf("path '%s'", fs->path ?: "NULL"), FREE,
16104 new->varlist, "varlist", NO_FREE);
16105 16066
16106#if MAX_HISTORY 16067#if MAX_HISTORY
16107 if (line_input_state) { 16068 if (line_input_state) {
diff --git a/shell/ash_test/ash-misc/exitcode_trap2.right b/shell/ash_test/ash-misc/exitcode_trap2.right
new file mode 100644
index 000000000..6644d86bf
--- /dev/null
+++ b/shell/ash_test/ash-misc/exitcode_trap2.right
@@ -0,0 +1 @@
42:42
diff --git a/shell/ash_test/ash-misc/exitcode_trap2.tests b/shell/ash_test/ash-misc/exitcode_trap2.tests
new file mode 100755
index 000000000..f259774bf
--- /dev/null
+++ b/shell/ash_test/ash-misc/exitcode_trap2.tests
@@ -0,0 +1,9 @@
1# "exit" in trap should not use last command's exitcode,
2# but exitcode on entering the trap.
3$THIS_SH -c '
4 trap "false;exit" term
5 kill $$ &
6 (exit 42)
7 wait
8'
9echo 42:$?
diff --git a/shell/ash_test/ash-redir/redir_exec1.right b/shell/ash_test/ash-redir/redir_exec1.right
index c98455bf5..26a664edc 100644
--- a/shell/ash_test/ash-redir/redir_exec1.right
+++ b/shell/ash_test/ash-redir/redir_exec1.right
@@ -1,2 +1 @@
1./redir_exec1.tests: line 1: can't create /cant/be/created: nonexistent directory ./redir_exec1.tests: line 1: can't create /cant/be/created: nonexistent directory
2First
diff --git a/shell/hush_test/hush-misc/exitcode_trap2.right b/shell/hush_test/hush-misc/exitcode_trap2.right
new file mode 100644
index 000000000..6644d86bf
--- /dev/null
+++ b/shell/hush_test/hush-misc/exitcode_trap2.right
@@ -0,0 +1 @@
42:42
diff --git a/shell/hush_test/hush-misc/exitcode_trap2.tests b/shell/hush_test/hush-misc/exitcode_trap2.tests
new file mode 100755
index 000000000..f259774bf
--- /dev/null
+++ b/shell/hush_test/hush-misc/exitcode_trap2.tests
@@ -0,0 +1,9 @@
1# "exit" in trap should not use last command's exitcode,
2# but exitcode on entering the trap.
3$THIS_SH -c '
4 trap "false;exit" term
5 kill $$ &
6 (exit 42)
7 wait
8'
9echo 42:$?