diff options
author | Ron Yorston <rmy@pobox.com> | 2020-02-21 12:55:36 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2020-02-21 12:55:36 +0000 |
commit | 63c8e755021cf35c8a94ea1291c1e123164a7917 (patch) | |
tree | c971d1e74f99b57d61759cff536e47eee9480157 | |
parent | 896d625cc9e03a726d535da18539602763769d3b (diff) | |
parent | e2dd2afc8e4dbcf1061818adc68d2e74a1fa64d3 (diff) | |
download | busybox-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.c | 311 | ||||
-rw-r--r-- | shell/ash_test/ash-misc/exitcode_trap2.right | 1 | ||||
-rwxr-xr-x | shell/ash_test/ash-misc/exitcode_trap2.tests | 9 | ||||
-rw-r--r-- | shell/ash_test/ash-redir/redir_exec1.right | 1 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/exitcode_trap2.right | 1 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/exitcode_trap2.tests | 9 |
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 | ||
386 | enum { | 385 | enum { |
@@ -2699,24 +2698,6 @@ unsetvar(const char *s) | |||
2699 | } | 2698 | } |
2700 | 2699 | ||
2701 | /* | 2700 | /* |
2702 | * Process a linked list of variable assignments. | ||
2703 | */ | ||
2704 | static void | ||
2705 | listsetvar(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 | ||
8668 | static void find_command(char *, struct cmdentry *, int, const char *); | 8649 | static 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 |
9265 | static struct strlist * | ||
9266 | fill_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 */ |
9285 | static char ** | 9282 | static int |
9286 | parse_command_args(char **argv, const char **path) | 9283 | parse_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 | ||
9319 | static int FAST_FUNC | 9321 | static int FAST_FUNC |
@@ -10397,18 +10399,23 @@ poplocalvars(int keep) | |||
10397 | * Create a new localvar environment. | 10399 | * Create a new localvar environment. |
10398 | */ | 10400 | */ |
10399 | static struct localvar_list * | 10401 | static struct localvar_list * |
10400 | pushlocalvars(void) | 10402 | pushlocalvars(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 | ||
10414 | static void | 10421 | static 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 | */ |
10469 | static void | 10476 | static void |
10470 | mklocal(char *name) | 10477 | mklocal(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 | |||
10803 | evalcommand(union node *cmd, int flags) | 10810 | evalcommand(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 | |||
15565 | forkshell_shellexec(struct forkshell *fs) | 15543 | forkshell_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 | |||
15736 | SLIST_COPY_END() | 15712 | SLIST_COPY_END() |
15737 | 15713 | ||
15738 | /* | 15714 | /* |
15739 | * struct strlist | ||
15740 | */ | ||
15741 | SLIST_SIZE_BEGIN(strlist_size,struct strlist) | ||
15742 | ds.funcstringsize += align_len(p->text); | ||
15743 | SLIST_SIZE_END() | ||
15744 | |||
15745 | SLIST_COPY_BEGIN(strlist_copy,struct strlist) | ||
15746 | (*vpp)->text = nodeckstrdup(vp->text); | ||
15747 | SAVE_PTR((*vpp)->text, xasprintf("(*vpp)->text '%s'", vp->text ?: "NULL"), FREE); | ||
15748 | SLIST_COPY_END() | ||
15749 | |||
15750 | /* | ||
15751 | * struct tblentry | 15715 | * struct tblentry |
15752 | */ | 15716 | */ |
15753 | static struct datasize | 15717 | static 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 | ' | ||
9 | echo 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 | |
2 | First | ||
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 | ' | ||
9 | echo 42:$? | ||