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 /shell | |
| 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.
Diffstat (limited to 'shell')
| -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:$? | ||
