diff options
author | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2011-01-04 19:56:15 +0700 |
---|---|---|
committer | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2011-01-04 19:56:15 +0700 |
commit | 5f6f2162512106adf120d4b528bb125e93e34429 (patch) | |
tree | 7d7449f755633c263be7125ad58d21cc3ca5b8a7 /shell | |
parent | 9db69882bee2d528d706d61d34ef7741122330be (diff) | |
parent | a116552869db5e7793ae10968eb3c962c69b3d8c (diff) | |
download | busybox-w32-5f6f2162512106adf120d4b528bb125e93e34429.tar.gz busybox-w32-5f6f2162512106adf120d4b528bb125e93e34429.tar.bz2 busybox-w32-5f6f2162512106adf120d4b528bb125e93e34429.zip |
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash.c | 11 | ||||
-rw-r--r-- | shell/ash_test/recho.c | 13 | ||||
-rw-r--r-- | shell/ash_test/zecho.c | 5 | ||||
-rw-r--r-- | shell/hush.c | 559 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/assignment3.right | 2 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/assignment3.tests | 5 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/pipefail.right | 40 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/pipefail.tests | 45 | ||||
-rw-r--r-- | shell/hush_test/hush-parsing/comment1.right | 2 | ||||
-rwxr-xr-x | shell/hush_test/hush-parsing/comment1.tests | 2 | ||||
-rw-r--r-- | shell/hush_test/hush-parsing/eol1.right | 1 | ||||
-rwxr-xr-x | shell/hush_test/hush-parsing/eol1.tests | 18 |
12 files changed, 465 insertions, 238 deletions
diff --git a/shell/ash.c b/shell/ash.c index ccf4288a9..f7baf2b3b 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -57,7 +57,9 @@ | |||
57 | #include <sys/times.h> | 57 | #include <sys/times.h> |
58 | 58 | ||
59 | #include "shell_common.h" | 59 | #include "shell_common.h" |
60 | #include "math.h" | 60 | #if ENABLE_SH_MATH_SUPPORT |
61 | # include "math.h" | ||
62 | #endif | ||
61 | #if ENABLE_ASH_RANDOM_SUPPORT | 63 | #if ENABLE_ASH_RANDOM_SUPPORT |
62 | # include "random.h" | 64 | # include "random.h" |
63 | #else | 65 | #else |
@@ -5834,6 +5836,11 @@ static struct arglist exparg; | |||
5834 | /* | 5836 | /* |
5835 | * Our own itoa(). | 5837 | * Our own itoa(). |
5836 | */ | 5838 | */ |
5839 | #if !ENABLE_SH_MATH_SUPPORT | ||
5840 | /* cvtnum() is used even if math support is off (to prepare $? values and such) */ | ||
5841 | typedef long arith_t; | ||
5842 | # define ARITH_FMT "%ld" | ||
5843 | #endif | ||
5837 | static int | 5844 | static int |
5838 | cvtnum(arith_t num) | 5845 | cvtnum(arith_t num) |
5839 | { | 5846 | { |
@@ -13648,7 +13655,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
13648 | } | 13655 | } |
13649 | } | 13656 | } |
13650 | #endif | 13657 | #endif |
13651 | if (/* argv[0] && */ argv[0][0] == '-') | 13658 | if (argv[0] && argv[0][0] == '-') |
13652 | isloginsh = 1; | 13659 | isloginsh = 1; |
13653 | if (isloginsh) { | 13660 | if (isloginsh) { |
13654 | state = 1; | 13661 | state = 1; |
diff --git a/shell/ash_test/recho.c b/shell/ash_test/recho.c index fb48d9c48..42a5feafd 100644 --- a/shell/ash_test/recho.c +++ b/shell/ash_test/recho.c | |||
@@ -29,12 +29,9 @@ | |||
29 | 29 | ||
30 | void strprint(); | 30 | void strprint(); |
31 | 31 | ||
32 | int | 32 | int main(int argc, char **argv) |
33 | main(argc, argv) | ||
34 | int argc; | ||
35 | char **argv; | ||
36 | { | 33 | { |
37 | register int i; | 34 | int i; |
38 | 35 | ||
39 | for (i = 1; i < argc; i++) { | 36 | for (i = 1; i < argc; i++) { |
40 | printf("argv[%d] = <", i); | 37 | printf("argv[%d] = <", i); |
@@ -44,11 +41,9 @@ char **argv; | |||
44 | exit(EXIT_SUCCESS); | 41 | exit(EXIT_SUCCESS); |
45 | } | 42 | } |
46 | 43 | ||
47 | void | 44 | void strprint(char *str) |
48 | strprint(str) | ||
49 | char *str; | ||
50 | { | 45 | { |
51 | register unsigned char *s; | 46 | unsigned char *s; |
52 | 47 | ||
53 | for (s = (unsigned char *)str; s && *s; s++) { | 48 | for (s = (unsigned char *)str; s && *s; s++) { |
54 | if (*s < ' ') { | 49 | if (*s < ' ') { |
diff --git a/shell/ash_test/zecho.c b/shell/ash_test/zecho.c index bf876f641..cbaa59b81 100644 --- a/shell/ash_test/zecho.c +++ b/shell/ash_test/zecho.c | |||
@@ -21,10 +21,7 @@ | |||
21 | #include <stdio.h> | 21 | #include <stdio.h> |
22 | #include <stdlib.h> | 22 | #include <stdlib.h> |
23 | 23 | ||
24 | int | 24 | int main(int argc, char **argv) |
25 | main(argc, argv) | ||
26 | int argc; | ||
27 | char **argv; | ||
28 | { | 25 | { |
29 | argv++; | 26 | argv++; |
30 | 27 | ||
diff --git a/shell/hush.c b/shell/hush.c index 9dd30c436..a771e9cd9 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -82,7 +82,11 @@ | |||
82 | * aaa | 82 | * aaa |
83 | */ | 83 | */ |
84 | #include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ | 84 | #include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ |
85 | #include <malloc.h> /* for malloc_trim */ | 85 | #if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ |
86 | || defined(__APPLE__) \ | ||
87 | ) | ||
88 | # include <malloc.h> /* for malloc_trim */ | ||
89 | #endif | ||
86 | #include <glob.h> | 90 | #include <glob.h> |
87 | /* #include <dmalloc.h> */ | 91 | /* #include <dmalloc.h> */ |
88 | #if ENABLE_HUSH_CASE | 92 | #if ENABLE_HUSH_CASE |
@@ -245,9 +249,15 @@ | |||
245 | //config: msh is deprecated and will be removed, please migrate to hush. | 249 | //config: msh is deprecated and will be removed, please migrate to hush. |
246 | //config: | 250 | //config: |
247 | 251 | ||
248 | //usage:#define hush_trivial_usage NOUSAGE_STR | 252 | /* -i (interactive) and -s (read stdin) are also accepted, |
253 | * but currently do nothing, therefore aren't shown in help. | ||
254 | * NOMMU-specific options are not meant to be used by users, | ||
255 | * therefore we don't show them either. | ||
256 | */ | ||
257 | //usage:#define hush_trivial_usage | ||
258 | //usage: "[-nx] [-c SCRIPT]" | ||
249 | //usage:#define hush_full_usage "" | 259 | //usage:#define hush_full_usage "" |
250 | //usage:#define msh_trivial_usage NOUSAGE_STR | 260 | //usage:#define msh_trivial_usage hush_trivial_usage |
251 | //usage:#define msh_full_usage "" | 261 | //usage:#define msh_full_usage "" |
252 | //usage:#define sh_trivial_usage NOUSAGE_STR | 262 | //usage:#define sh_trivial_usage NOUSAGE_STR |
253 | //usage:#define sh_full_usage "" | 263 | //usage:#define sh_full_usage "" |
@@ -507,6 +517,7 @@ struct command { | |||
507 | # define CMD_FUNCDEF 3 | 517 | # define CMD_FUNCDEF 3 |
508 | #endif | 518 | #endif |
509 | 519 | ||
520 | smalluint cmd_exitcode; | ||
510 | /* if non-NULL, this "command" is { list }, ( list ), or a compound statement */ | 521 | /* if non-NULL, this "command" is { list }, ( list ), or a compound statement */ |
511 | struct pipe *group; | 522 | struct pipe *group; |
512 | #if !BB_MMU | 523 | #if !BB_MMU |
@@ -542,7 +553,6 @@ struct command { | |||
542 | #define IS_NULL_CMD(cmd) \ | 553 | #define IS_NULL_CMD(cmd) \ |
543 | (!(cmd)->group && !(cmd)->argv && !(cmd)->redirects) | 554 | (!(cmd)->group && !(cmd)->argv && !(cmd)->redirects) |
544 | 555 | ||
545 | |||
546 | struct pipe { | 556 | struct pipe { |
547 | struct pipe *next; | 557 | struct pipe *next; |
548 | int num_cmds; /* total number of commands in pipe */ | 558 | int num_cmds; /* total number of commands in pipe */ |
@@ -637,6 +647,53 @@ struct function { | |||
637 | #endif | 647 | #endif |
638 | 648 | ||
639 | 649 | ||
650 | /* set -/+o OPT support. (TODO: make it optional) | ||
651 | * bash supports the following opts: | ||
652 | * allexport off | ||
653 | * braceexpand on | ||
654 | * emacs on | ||
655 | * errexit off | ||
656 | * errtrace off | ||
657 | * functrace off | ||
658 | * hashall on | ||
659 | * histexpand off | ||
660 | * history on | ||
661 | * ignoreeof off | ||
662 | * interactive-comments on | ||
663 | * keyword off | ||
664 | * monitor on | ||
665 | * noclobber off | ||
666 | * noexec off | ||
667 | * noglob off | ||
668 | * nolog off | ||
669 | * notify off | ||
670 | * nounset off | ||
671 | * onecmd off | ||
672 | * physical off | ||
673 | * pipefail off | ||
674 | * posix off | ||
675 | * privileged off | ||
676 | * verbose off | ||
677 | * vi off | ||
678 | * xtrace off | ||
679 | */ | ||
680 | static const char o_opt_strings[] ALIGN1 = | ||
681 | "pipefail\0" | ||
682 | "noexec\0" | ||
683 | #if ENABLE_HUSH_MODE_X | ||
684 | "xtrace\0" | ||
685 | #endif | ||
686 | ; | ||
687 | enum { | ||
688 | OPT_O_PIPEFAIL, | ||
689 | OPT_O_NOEXEC, | ||
690 | #if ENABLE_HUSH_MODE_X | ||
691 | OPT_O_XTRACE, | ||
692 | #endif | ||
693 | NUM_OPT_O | ||
694 | }; | ||
695 | |||
696 | |||
640 | /* "Globals" within this file */ | 697 | /* "Globals" within this file */ |
641 | /* Sorted roughly by size (smaller offsets == smaller code) */ | 698 | /* Sorted roughly by size (smaller offsets == smaller code) */ |
642 | struct globals { | 699 | struct globals { |
@@ -679,6 +736,12 @@ struct globals { | |||
679 | #else | 736 | #else |
680 | # define G_saved_tty_pgrp 0 | 737 | # define G_saved_tty_pgrp 0 |
681 | #endif | 738 | #endif |
739 | char o_opt[NUM_OPT_O]; | ||
740 | #if ENABLE_HUSH_MODE_X | ||
741 | # define G_x_mode (G.o_opt[OPT_O_XTRACE]) | ||
742 | #else | ||
743 | # define G_x_mode 0 | ||
744 | #endif | ||
682 | smallint flag_SIGINT; | 745 | smallint flag_SIGINT; |
683 | #if ENABLE_HUSH_LOOPS | 746 | #if ENABLE_HUSH_LOOPS |
684 | smallint flag_break_continue; | 747 | smallint flag_break_continue; |
@@ -690,13 +753,6 @@ struct globals { | |||
690 | */ | 753 | */ |
691 | smallint flag_return_in_progress; | 754 | smallint flag_return_in_progress; |
692 | #endif | 755 | #endif |
693 | smallint n_mode; | ||
694 | #if ENABLE_HUSH_MODE_X | ||
695 | smallint x_mode; | ||
696 | # define G_x_mode (G.x_mode) | ||
697 | #else | ||
698 | # define G_x_mode 0 | ||
699 | #endif | ||
700 | smallint exiting; /* used to prevent EXIT trap recursion */ | 756 | smallint exiting; /* used to prevent EXIT trap recursion */ |
701 | /* These four support $?, $#, and $1 */ | 757 | /* These four support $?, $#, and $1 */ |
702 | smalluint last_exitcode; | 758 | smalluint last_exitcode; |
@@ -875,7 +931,7 @@ static const struct built_in_command bltins2[] = { | |||
875 | */ | 931 | */ |
876 | #if HUSH_DEBUG | 932 | #if HUSH_DEBUG |
877 | /* prevent disasters with G.debug_indent < 0 */ | 933 | /* prevent disasters with G.debug_indent < 0 */ |
878 | # define indent() fprintf(stderr, "%*s", (G.debug_indent * 2) & 0xff, "") | 934 | # define indent() fdprintf(2, "%*s", (G.debug_indent * 2) & 0xff, "") |
879 | # define debug_enter() (G.debug_indent++) | 935 | # define debug_enter() (G.debug_indent++) |
880 | # define debug_leave() (G.debug_indent--) | 936 | # define debug_leave() (G.debug_indent--) |
881 | #else | 937 | #else |
@@ -885,56 +941,56 @@ static const struct built_in_command bltins2[] = { | |||
885 | #endif | 941 | #endif |
886 | 942 | ||
887 | #ifndef debug_printf | 943 | #ifndef debug_printf |
888 | # define debug_printf(...) (indent(), fprintf(stderr, __VA_ARGS__)) | 944 | # define debug_printf(...) (indent(), fdprintf(2, __VA_ARGS__)) |
889 | #endif | 945 | #endif |
890 | 946 | ||
891 | #ifndef debug_printf_parse | 947 | #ifndef debug_printf_parse |
892 | # define debug_printf_parse(...) (indent(), fprintf(stderr, __VA_ARGS__)) | 948 | # define debug_printf_parse(...) (indent(), fdprintf(2, __VA_ARGS__)) |
893 | #endif | 949 | #endif |
894 | 950 | ||
895 | #ifndef debug_printf_exec | 951 | #ifndef debug_printf_exec |
896 | #define debug_printf_exec(...) (indent(), fprintf(stderr, __VA_ARGS__)) | 952 | #define debug_printf_exec(...) (indent(), fdprintf(2, __VA_ARGS__)) |
897 | #endif | 953 | #endif |
898 | 954 | ||
899 | #ifndef debug_printf_env | 955 | #ifndef debug_printf_env |
900 | # define debug_printf_env(...) (indent(), fprintf(stderr, __VA_ARGS__)) | 956 | # define debug_printf_env(...) (indent(), fdprintf(2, __VA_ARGS__)) |
901 | #endif | 957 | #endif |
902 | 958 | ||
903 | #ifndef debug_printf_jobs | 959 | #ifndef debug_printf_jobs |
904 | # define debug_printf_jobs(...) (indent(), fprintf(stderr, __VA_ARGS__)) | 960 | # define debug_printf_jobs(...) (indent(), fdprintf(2, __VA_ARGS__)) |
905 | # define DEBUG_JOBS 1 | 961 | # define DEBUG_JOBS 1 |
906 | #else | 962 | #else |
907 | # define DEBUG_JOBS 0 | 963 | # define DEBUG_JOBS 0 |
908 | #endif | 964 | #endif |
909 | 965 | ||
910 | #ifndef debug_printf_expand | 966 | #ifndef debug_printf_expand |
911 | # define debug_printf_expand(...) (indent(), fprintf(stderr, __VA_ARGS__)) | 967 | # define debug_printf_expand(...) (indent(), fdprintf(2, __VA_ARGS__)) |
912 | # define DEBUG_EXPAND 1 | 968 | # define DEBUG_EXPAND 1 |
913 | #else | 969 | #else |
914 | # define DEBUG_EXPAND 0 | 970 | # define DEBUG_EXPAND 0 |
915 | #endif | 971 | #endif |
916 | 972 | ||
917 | #ifndef debug_printf_varexp | 973 | #ifndef debug_printf_varexp |
918 | # define debug_printf_varexp(...) (indent(), fprintf(stderr, __VA_ARGS__)) | 974 | # define debug_printf_varexp(...) (indent(), fdprintf(2, __VA_ARGS__)) |
919 | #endif | 975 | #endif |
920 | 976 | ||
921 | #ifndef debug_printf_glob | 977 | #ifndef debug_printf_glob |
922 | # define debug_printf_glob(...) (indent(), fprintf(stderr, __VA_ARGS__)) | 978 | # define debug_printf_glob(...) (indent(), fdprintf(2, __VA_ARGS__)) |
923 | # define DEBUG_GLOB 1 | 979 | # define DEBUG_GLOB 1 |
924 | #else | 980 | #else |
925 | # define DEBUG_GLOB 0 | 981 | # define DEBUG_GLOB 0 |
926 | #endif | 982 | #endif |
927 | 983 | ||
928 | #ifndef debug_printf_list | 984 | #ifndef debug_printf_list |
929 | # define debug_printf_list(...) (indent(), fprintf(stderr, __VA_ARGS__)) | 985 | # define debug_printf_list(...) (indent(), fdprintf(2, __VA_ARGS__)) |
930 | #endif | 986 | #endif |
931 | 987 | ||
932 | #ifndef debug_printf_subst | 988 | #ifndef debug_printf_subst |
933 | # define debug_printf_subst(...) (indent(), fprintf(stderr, __VA_ARGS__)) | 989 | # define debug_printf_subst(...) (indent(), fdprintf(2, __VA_ARGS__)) |
934 | #endif | 990 | #endif |
935 | 991 | ||
936 | #ifndef debug_printf_clean | 992 | #ifndef debug_printf_clean |
937 | # define debug_printf_clean(...) (indent(), fprintf(stderr, __VA_ARGS__)) | 993 | # define debug_printf_clean(...) (indent(), fdprintf(2, __VA_ARGS__)) |
938 | # define DEBUG_CLEAN 1 | 994 | # define DEBUG_CLEAN 1 |
939 | #else | 995 | #else |
940 | # define DEBUG_CLEAN 0 | 996 | # define DEBUG_CLEAN 0 |
@@ -944,9 +1000,9 @@ static const struct built_in_command bltins2[] = { | |||
944 | static void debug_print_strings(const char *prefix, char **vv) | 1000 | static void debug_print_strings(const char *prefix, char **vv) |
945 | { | 1001 | { |
946 | indent(); | 1002 | indent(); |
947 | fprintf(stderr, "%s:\n", prefix); | 1003 | fdprintf(2, "%s:\n", prefix); |
948 | while (*vv) | 1004 | while (*vv) |
949 | fprintf(stderr, " '%s'\n", *vv++); | 1005 | fdprintf(2, " '%s'\n", *vv++); |
950 | } | 1006 | } |
951 | #else | 1007 | #else |
952 | # define debug_print_strings(prefix, vv) ((void)0) | 1008 | # define debug_print_strings(prefix, vv) ((void)0) |
@@ -1378,6 +1434,22 @@ static void hush_exit(int exitcode) | |||
1378 | builtin_eval(argv); | 1434 | builtin_eval(argv); |
1379 | } | 1435 | } |
1380 | 1436 | ||
1437 | #if ENABLE_FEATURE_CLEAN_UP | ||
1438 | { | ||
1439 | struct variable *cur_var; | ||
1440 | if (G.cwd != bb_msg_unknown) | ||
1441 | free((char*)G.cwd); | ||
1442 | cur_var = G.top_var; | ||
1443 | while (cur_var) { | ||
1444 | struct variable *tmp = cur_var; | ||
1445 | if (!cur_var->max_len) | ||
1446 | free(cur_var->varstr); | ||
1447 | cur_var = cur_var->next; | ||
1448 | free(tmp); | ||
1449 | } | ||
1450 | } | ||
1451 | #endif | ||
1452 | |||
1381 | #if ENABLE_HUSH_JOB | 1453 | #if ENABLE_HUSH_JOB |
1382 | fflush_all(); | 1454 | fflush_all(); |
1383 | sigexit(- (exitcode & 0xff)); | 1455 | sigexit(- (exitcode & 0xff)); |
@@ -2120,22 +2192,22 @@ static void debug_print_list(const char *prefix, o_string *o, int n) | |||
2120 | int i = 0; | 2192 | int i = 0; |
2121 | 2193 | ||
2122 | indent(); | 2194 | indent(); |
2123 | fprintf(stderr, "%s: list:%p n:%d string_start:%d length:%d maxlen:%d glob:%d quoted:%d escape:%d\n", | 2195 | fdprintf(2, "%s: list:%p n:%d string_start:%d length:%d maxlen:%d glob:%d quoted:%d escape:%d\n", |
2124 | prefix, list, n, string_start, o->length, o->maxlen, | 2196 | prefix, list, n, string_start, o->length, o->maxlen, |
2125 | !!(o->o_expflags & EXP_FLAG_GLOB), | 2197 | !!(o->o_expflags & EXP_FLAG_GLOB), |
2126 | o->has_quoted_part, | 2198 | o->has_quoted_part, |
2127 | !!(o->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); | 2199 | !!(o->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); |
2128 | while (i < n) { | 2200 | while (i < n) { |
2129 | indent(); | 2201 | indent(); |
2130 | fprintf(stderr, " list[%d]=%d '%s' %p\n", i, (int)list[i], | 2202 | fdprintf(2, " list[%d]=%d '%s' %p\n", i, (int)(uintptr_t)list[i], |
2131 | o->data + (int)list[i] + string_start, | 2203 | o->data + (int)(uintptr_t)list[i] + string_start, |
2132 | o->data + (int)list[i] + string_start); | 2204 | o->data + (int)(uintptr_t)list[i] + string_start); |
2133 | i++; | 2205 | i++; |
2134 | } | 2206 | } |
2135 | if (n) { | 2207 | if (n) { |
2136 | const char *p = o->data + (int)list[n - 1] + string_start; | 2208 | const char *p = o->data + (int)(uintptr_t)list[n - 1] + string_start; |
2137 | indent(); | 2209 | indent(); |
2138 | fprintf(stderr, " total_sz:%ld\n", (long)((p + strlen(p) + 1) - o->data)); | 2210 | fdprintf(2, " total_sz:%ld\n", (long)((p + strlen(p) + 1) - o->data)); |
2139 | } | 2211 | } |
2140 | } | 2212 | } |
2141 | #else | 2213 | #else |
@@ -2583,6 +2655,94 @@ static void free_pipe_list(struct pipe *pi) | |||
2583 | 2655 | ||
2584 | /*** Parsing routines ***/ | 2656 | /*** Parsing routines ***/ |
2585 | 2657 | ||
2658 | #ifndef debug_print_tree | ||
2659 | static void debug_print_tree(struct pipe *pi, int lvl) | ||
2660 | { | ||
2661 | static const char *const PIPE[] = { | ||
2662 | [PIPE_SEQ] = "SEQ", | ||
2663 | [PIPE_AND] = "AND", | ||
2664 | [PIPE_OR ] = "OR" , | ||
2665 | [PIPE_BG ] = "BG" , | ||
2666 | }; | ||
2667 | static const char *RES[] = { | ||
2668 | [RES_NONE ] = "NONE" , | ||
2669 | # if ENABLE_HUSH_IF | ||
2670 | [RES_IF ] = "IF" , | ||
2671 | [RES_THEN ] = "THEN" , | ||
2672 | [RES_ELIF ] = "ELIF" , | ||
2673 | [RES_ELSE ] = "ELSE" , | ||
2674 | [RES_FI ] = "FI" , | ||
2675 | # endif | ||
2676 | # if ENABLE_HUSH_LOOPS | ||
2677 | [RES_FOR ] = "FOR" , | ||
2678 | [RES_WHILE] = "WHILE", | ||
2679 | [RES_UNTIL] = "UNTIL", | ||
2680 | [RES_DO ] = "DO" , | ||
2681 | [RES_DONE ] = "DONE" , | ||
2682 | # endif | ||
2683 | # if ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE | ||
2684 | [RES_IN ] = "IN" , | ||
2685 | # endif | ||
2686 | # if ENABLE_HUSH_CASE | ||
2687 | [RES_CASE ] = "CASE" , | ||
2688 | [RES_CASE_IN ] = "CASE_IN" , | ||
2689 | [RES_MATCH] = "MATCH", | ||
2690 | [RES_CASE_BODY] = "CASE_BODY", | ||
2691 | [RES_ESAC ] = "ESAC" , | ||
2692 | # endif | ||
2693 | [RES_XXXX ] = "XXXX" , | ||
2694 | [RES_SNTX ] = "SNTX" , | ||
2695 | }; | ||
2696 | static const char *const CMDTYPE[] = { | ||
2697 | "{}", | ||
2698 | "()", | ||
2699 | "[noglob]", | ||
2700 | # if ENABLE_HUSH_FUNCTIONS | ||
2701 | "func()", | ||
2702 | # endif | ||
2703 | }; | ||
2704 | |||
2705 | int pin, prn; | ||
2706 | |||
2707 | pin = 0; | ||
2708 | while (pi) { | ||
2709 | fdprintf(2, "%*spipe %d res_word=%s followup=%d %s\n", lvl*2, "", | ||
2710 | pin, RES[pi->res_word], pi->followup, PIPE[pi->followup]); | ||
2711 | prn = 0; | ||
2712 | while (prn < pi->num_cmds) { | ||
2713 | struct command *command = &pi->cmds[prn]; | ||
2714 | char **argv = command->argv; | ||
2715 | |||
2716 | fdprintf(2, "%*s cmd %d assignment_cnt:%d", | ||
2717 | lvl*2, "", prn, | ||
2718 | command->assignment_cnt); | ||
2719 | if (command->group) { | ||
2720 | fdprintf(2, " group %s: (argv=%p)%s%s\n", | ||
2721 | CMDTYPE[command->cmd_type], | ||
2722 | argv | ||
2723 | # if !BB_MMU | ||
2724 | , " group_as_string:", command->group_as_string | ||
2725 | # else | ||
2726 | , "", "" | ||
2727 | # endif | ||
2728 | ); | ||
2729 | debug_print_tree(command->group, lvl+1); | ||
2730 | prn++; | ||
2731 | continue; | ||
2732 | } | ||
2733 | if (argv) while (*argv) { | ||
2734 | fdprintf(2, " '%s'", *argv); | ||
2735 | argv++; | ||
2736 | } | ||
2737 | fdprintf(2, "\n"); | ||
2738 | prn++; | ||
2739 | } | ||
2740 | pi = pi->next; | ||
2741 | pin++; | ||
2742 | } | ||
2743 | } | ||
2744 | #endif /* debug_print_tree */ | ||
2745 | |||
2586 | static struct pipe *new_pipe(void) | 2746 | static struct pipe *new_pipe(void) |
2587 | { | 2747 | { |
2588 | struct pipe *pi; | 2748 | struct pipe *pi; |
@@ -3972,15 +4132,16 @@ static struct pipe *parse_stream(char **pstring, | |||
3972 | goto parse_error; | 4132 | goto parse_error; |
3973 | } | 4133 | } |
3974 | if (ch == '\n') { | 4134 | if (ch == '\n') { |
3975 | #if ENABLE_HUSH_CASE | 4135 | /* Is this a case when newline is simply ignored? |
3976 | /* "case ... in <newline> word) ..." - | 4136 | * Some examples: |
3977 | * newlines are ignored (but ';' wouldn't be) */ | 4137 | * "cmd | <newline> cmd ..." |
3978 | if (ctx.command->argv == NULL | 4138 | * "case ... in <newline> word) ..." |
3979 | && ctx.ctx_res_w == RES_MATCH | 4139 | */ |
4140 | if (IS_NULL_CMD(ctx.command) | ||
4141 | && dest.length == 0 && !dest.has_quoted_part | ||
3980 | ) { | 4142 | ) { |
3981 | continue; | 4143 | continue; |
3982 | } | 4144 | } |
3983 | #endif | ||
3984 | /* Treat newline as a command separator. */ | 4145 | /* Treat newline as a command separator. */ |
3985 | done_pipe(&ctx, PIPE_SEQ); | 4146 | done_pipe(&ctx, PIPE_SEQ); |
3986 | debug_printf_parse("heredoc_cnt:%d\n", heredoc_cnt); | 4147 | debug_printf_parse("heredoc_cnt:%d\n", heredoc_cnt); |
@@ -4112,6 +4273,31 @@ static struct pipe *parse_stream(char **pstring, | |||
4112 | if (parse_redirect(&ctx, redir_fd, redir_style, input)) | 4273 | if (parse_redirect(&ctx, redir_fd, redir_style, input)) |
4113 | goto parse_error; | 4274 | goto parse_error; |
4114 | continue; /* back to top of while (1) */ | 4275 | continue; /* back to top of while (1) */ |
4276 | case '#': | ||
4277 | if (dest.length == 0 && !dest.has_quoted_part) { | ||
4278 | /* skip "#comment" */ | ||
4279 | while (1) { | ||
4280 | ch = i_peek(input); | ||
4281 | if (ch == EOF || ch == '\n') | ||
4282 | break; | ||
4283 | i_getch(input); | ||
4284 | /* note: we do not add it to &ctx.as_string */ | ||
4285 | } | ||
4286 | nommu_addchr(&ctx.as_string, '\n'); | ||
4287 | continue; /* back to top of while (1) */ | ||
4288 | } | ||
4289 | break; | ||
4290 | case '\\': | ||
4291 | if (next == '\n') { | ||
4292 | /* It's "\<newline>" */ | ||
4293 | #if !BB_MMU | ||
4294 | /* Remove trailing '\' from ctx.as_string */ | ||
4295 | ctx.as_string.data[--ctx.as_string.length] = '\0'; | ||
4296 | #endif | ||
4297 | ch = i_getch(input); /* eat it */ | ||
4298 | continue; /* back to top of while (1) */ | ||
4299 | } | ||
4300 | break; | ||
4115 | } | 4301 | } |
4116 | 4302 | ||
4117 | if (dest.o_assignment == MAYBE_ASSIGNMENT | 4303 | if (dest.o_assignment == MAYBE_ASSIGNMENT |
@@ -4126,19 +4312,8 @@ static struct pipe *parse_stream(char **pstring, | |||
4126 | /* Note: nommu_addchr(&ctx.as_string, ch) is already done */ | 4312 | /* Note: nommu_addchr(&ctx.as_string, ch) is already done */ |
4127 | 4313 | ||
4128 | switch (ch) { | 4314 | switch (ch) { |
4129 | case '#': | 4315 | case '#': /* non-comment #: "echo a#b" etc */ |
4130 | if (dest.length == 0) { | 4316 | o_addQchr(&dest, ch); |
4131 | while (1) { | ||
4132 | ch = i_peek(input); | ||
4133 | if (ch == EOF || ch == '\n') | ||
4134 | break; | ||
4135 | i_getch(input); | ||
4136 | /* note: we do not add it to &ctx.as_string */ | ||
4137 | } | ||
4138 | nommu_addchr(&ctx.as_string, '\n'); | ||
4139 | } else { | ||
4140 | o_addQchr(&dest, ch); | ||
4141 | } | ||
4142 | break; | 4317 | break; |
4143 | case '\\': | 4318 | case '\\': |
4144 | if (next == EOF) { | 4319 | if (next == EOF) { |
@@ -4146,21 +4321,14 @@ static struct pipe *parse_stream(char **pstring, | |||
4146 | xfunc_die(); | 4321 | xfunc_die(); |
4147 | } | 4322 | } |
4148 | ch = i_getch(input); | 4323 | ch = i_getch(input); |
4149 | if (ch != '\n') { | 4324 | /* note: ch != '\n' (that case does not reach this place) */ |
4150 | o_addchr(&dest, '\\'); | 4325 | o_addchr(&dest, '\\'); |
4151 | /*nommu_addchr(&ctx.as_string, '\\'); - already done */ | 4326 | /*nommu_addchr(&ctx.as_string, '\\'); - already done */ |
4152 | o_addchr(&dest, ch); | 4327 | o_addchr(&dest, ch); |
4153 | nommu_addchr(&ctx.as_string, ch); | 4328 | nommu_addchr(&ctx.as_string, ch); |
4154 | /* Example: echo Hello \2>file | 4329 | /* Example: echo Hello \2>file |
4155 | * we need to know that word 2 is quoted */ | 4330 | * we need to know that word 2 is quoted */ |
4156 | dest.has_quoted_part = 1; | 4331 | dest.has_quoted_part = 1; |
4157 | } | ||
4158 | #if !BB_MMU | ||
4159 | else { | ||
4160 | /* It's "\<newline>". Remove trailing '\' from ctx.as_string */ | ||
4161 | ctx.as_string.data[--ctx.as_string.length] = '\0'; | ||
4162 | } | ||
4163 | #endif | ||
4164 | break; | 4332 | break; |
4165 | case '$': | 4333 | case '$': |
4166 | if (parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0) != 0) { | 4334 | if (parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0) != 0) { |
@@ -4366,7 +4534,9 @@ static struct pipe *parse_stream(char **pstring, | |||
4366 | expand_string_to_string(str) | 4534 | expand_string_to_string(str) |
4367 | #endif | 4535 | #endif |
4368 | static char *expand_string_to_string(const char *str, int do_unbackslash); | 4536 | static char *expand_string_to_string(const char *str, int do_unbackslash); |
4537 | #if ENABLE_HUSH_TICK | ||
4369 | static int process_command_subs(o_string *dest, const char *s); | 4538 | static int process_command_subs(o_string *dest, const char *s); |
4539 | #endif | ||
4370 | 4540 | ||
4371 | /* expand_strvec_to_strvec() takes a list of strings, expands | 4541 | /* expand_strvec_to_strvec() takes a list of strings, expands |
4372 | * all variable references within and returns a pointer to | 4542 | * all variable references within and returns a pointer to |
@@ -6309,48 +6479,57 @@ static int checkjobs(struct pipe *fg_pipe) | |||
6309 | #endif | 6479 | #endif |
6310 | /* Were we asked to wait for fg pipe? */ | 6480 | /* Were we asked to wait for fg pipe? */ |
6311 | if (fg_pipe) { | 6481 | if (fg_pipe) { |
6312 | for (i = 0; i < fg_pipe->num_cmds; i++) { | 6482 | i = fg_pipe->num_cmds; |
6483 | while (--i >= 0) { | ||
6313 | debug_printf_jobs("check pid %d\n", fg_pipe->cmds[i].pid); | 6484 | debug_printf_jobs("check pid %d\n", fg_pipe->cmds[i].pid); |
6314 | if (fg_pipe->cmds[i].pid != childpid) | 6485 | if (fg_pipe->cmds[i].pid != childpid) |
6315 | continue; | 6486 | continue; |
6316 | if (dead) { | 6487 | if (dead) { |
6488 | int ex; | ||
6317 | fg_pipe->cmds[i].pid = 0; | 6489 | fg_pipe->cmds[i].pid = 0; |
6318 | fg_pipe->alive_cmds--; | 6490 | fg_pipe->alive_cmds--; |
6319 | if (i == fg_pipe->num_cmds - 1) { | 6491 | ex = WEXITSTATUS(status); |
6320 | /* last process gives overall exitstatus */ | 6492 | /* bash prints killer signal's name for *last* |
6321 | rcode = WEXITSTATUS(status); | 6493 | * process in pipe (prints just newline for SIGINT). |
6322 | /* bash prints killer signal's name for *last* | 6494 | * Mimic this. Example: "sleep 5" + (^\ or kill -QUIT) |
6323 | * process in pipe (prints just newline for SIGINT). | 6495 | */ |
6324 | * Mimic this. Example: "sleep 5" + (^\ or kill -QUIT) | 6496 | if (WIFSIGNALED(status)) { |
6325 | */ | 6497 | int sig = WTERMSIG(status); |
6326 | if (WIFSIGNALED(status)) { | 6498 | if (i == fg_pipe->num_cmds-1) |
6327 | int sig = WTERMSIG(status); | ||
6328 | printf("%s\n", sig == SIGINT ? "" : get_signame(sig)); | 6499 | printf("%s\n", sig == SIGINT ? "" : get_signame(sig)); |
6329 | /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here? | 6500 | /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here? |
6330 | * Maybe we need to use sig | 128? */ | 6501 | * Maybe we need to use sig | 128? */ |
6331 | rcode = sig + 128; | 6502 | ex = sig + 128; |
6332 | } | ||
6333 | IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;) | ||
6334 | } | 6503 | } |
6504 | fg_pipe->cmds[i].cmd_exitcode = ex; | ||
6335 | } else { | 6505 | } else { |
6336 | fg_pipe->cmds[i].is_stopped = 1; | 6506 | fg_pipe->cmds[i].is_stopped = 1; |
6337 | fg_pipe->stopped_cmds++; | 6507 | fg_pipe->stopped_cmds++; |
6338 | } | 6508 | } |
6339 | debug_printf_jobs("fg_pipe: alive_cmds %d stopped_cmds %d\n", | 6509 | debug_printf_jobs("fg_pipe: alive_cmds %d stopped_cmds %d\n", |
6340 | fg_pipe->alive_cmds, fg_pipe->stopped_cmds); | 6510 | fg_pipe->alive_cmds, fg_pipe->stopped_cmds); |
6341 | if (fg_pipe->alive_cmds - fg_pipe->stopped_cmds <= 0) { | 6511 | if (fg_pipe->alive_cmds == fg_pipe->stopped_cmds) { |
6342 | /* All processes in fg pipe have exited or stopped */ | 6512 | /* All processes in fg pipe have exited or stopped */ |
6513 | i = fg_pipe->num_cmds; | ||
6514 | while (--i >= 0) { | ||
6515 | rcode = fg_pipe->cmds[i].cmd_exitcode; | ||
6516 | /* usually last process gives overall exitstatus, | ||
6517 | * but with "set -o pipefail", last *failed* process does */ | ||
6518 | if (G.o_opt[OPT_O_PIPEFAIL] == 0 || rcode != 0) | ||
6519 | break; | ||
6520 | } | ||
6521 | IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;) | ||
6343 | /* Note: *non-interactive* bash does not continue if all processes in fg pipe | 6522 | /* Note: *non-interactive* bash does not continue if all processes in fg pipe |
6344 | * are stopped. Testcase: "cat | cat" in a script (not on command line!) | 6523 | * are stopped. Testcase: "cat | cat" in a script (not on command line!) |
6345 | * and "killall -STOP cat" */ | 6524 | * and "killall -STOP cat" */ |
6346 | if (G_interactive_fd) { | 6525 | if (G_interactive_fd) { |
6347 | #if ENABLE_HUSH_JOB | 6526 | #if ENABLE_HUSH_JOB |
6348 | if (fg_pipe->alive_cmds) | 6527 | if (fg_pipe->alive_cmds != 0) |
6349 | insert_bg_job(fg_pipe); | 6528 | insert_bg_job(fg_pipe); |
6350 | #endif | 6529 | #endif |
6351 | return rcode; | 6530 | return rcode; |
6352 | } | 6531 | } |
6353 | if (!fg_pipe->alive_cmds) | 6532 | if (fg_pipe->alive_cmds == 0) |
6354 | return rcode; | 6533 | return rcode; |
6355 | } | 6534 | } |
6356 | /* There are still running processes in the fg pipe */ | 6535 | /* There are still running processes in the fg pipe */ |
@@ -6436,7 +6615,7 @@ static int checkjobs_and_fg_shell(struct pipe *fg_pipe) | |||
6436 | * subshell: ( list ) [&] | 6615 | * subshell: ( list ) [&] |
6437 | */ | 6616 | */ |
6438 | #if !ENABLE_HUSH_MODE_X | 6617 | #if !ENABLE_HUSH_MODE_X |
6439 | #define redirect_and_varexp_helper(new_env_p, old_vars_p, command, squirrel, char argv_expanded) \ | 6618 | #define redirect_and_varexp_helper(new_env_p, old_vars_p, command, squirrel, argv_expanded) \ |
6440 | redirect_and_varexp_helper(new_env_p, old_vars_p, command, squirrel) | 6619 | redirect_and_varexp_helper(new_env_p, old_vars_p, command, squirrel) |
6441 | #endif | 6620 | #endif |
6442 | static int redirect_and_varexp_helper(char ***new_env_p, | 6621 | static int redirect_and_varexp_helper(char ***new_env_p, |
@@ -6821,94 +7000,6 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
6821 | return -1; | 7000 | return -1; |
6822 | } | 7001 | } |
6823 | 7002 | ||
6824 | #ifndef debug_print_tree | ||
6825 | static void debug_print_tree(struct pipe *pi, int lvl) | ||
6826 | { | ||
6827 | static const char *const PIPE[] = { | ||
6828 | [PIPE_SEQ] = "SEQ", | ||
6829 | [PIPE_AND] = "AND", | ||
6830 | [PIPE_OR ] = "OR" , | ||
6831 | [PIPE_BG ] = "BG" , | ||
6832 | }; | ||
6833 | static const char *RES[] = { | ||
6834 | [RES_NONE ] = "NONE" , | ||
6835 | # if ENABLE_HUSH_IF | ||
6836 | [RES_IF ] = "IF" , | ||
6837 | [RES_THEN ] = "THEN" , | ||
6838 | [RES_ELIF ] = "ELIF" , | ||
6839 | [RES_ELSE ] = "ELSE" , | ||
6840 | [RES_FI ] = "FI" , | ||
6841 | # endif | ||
6842 | # if ENABLE_HUSH_LOOPS | ||
6843 | [RES_FOR ] = "FOR" , | ||
6844 | [RES_WHILE] = "WHILE", | ||
6845 | [RES_UNTIL] = "UNTIL", | ||
6846 | [RES_DO ] = "DO" , | ||
6847 | [RES_DONE ] = "DONE" , | ||
6848 | # endif | ||
6849 | # if ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE | ||
6850 | [RES_IN ] = "IN" , | ||
6851 | # endif | ||
6852 | # if ENABLE_HUSH_CASE | ||
6853 | [RES_CASE ] = "CASE" , | ||
6854 | [RES_CASE_IN ] = "CASE_IN" , | ||
6855 | [RES_MATCH] = "MATCH", | ||
6856 | [RES_CASE_BODY] = "CASE_BODY", | ||
6857 | [RES_ESAC ] = "ESAC" , | ||
6858 | # endif | ||
6859 | [RES_XXXX ] = "XXXX" , | ||
6860 | [RES_SNTX ] = "SNTX" , | ||
6861 | }; | ||
6862 | static const char *const CMDTYPE[] = { | ||
6863 | "{}", | ||
6864 | "()", | ||
6865 | "[noglob]", | ||
6866 | # if ENABLE_HUSH_FUNCTIONS | ||
6867 | "func()", | ||
6868 | # endif | ||
6869 | }; | ||
6870 | |||
6871 | int pin, prn; | ||
6872 | |||
6873 | pin = 0; | ||
6874 | while (pi) { | ||
6875 | fprintf(stderr, "%*spipe %d res_word=%s followup=%d %s\n", lvl*2, "", | ||
6876 | pin, RES[pi->res_word], pi->followup, PIPE[pi->followup]); | ||
6877 | prn = 0; | ||
6878 | while (prn < pi->num_cmds) { | ||
6879 | struct command *command = &pi->cmds[prn]; | ||
6880 | char **argv = command->argv; | ||
6881 | |||
6882 | fprintf(stderr, "%*s cmd %d assignment_cnt:%d", | ||
6883 | lvl*2, "", prn, | ||
6884 | command->assignment_cnt); | ||
6885 | if (command->group) { | ||
6886 | fprintf(stderr, " group %s: (argv=%p)%s%s\n", | ||
6887 | CMDTYPE[command->cmd_type], | ||
6888 | argv | ||
6889 | # if !BB_MMU | ||
6890 | , " group_as_string:", command->group_as_string | ||
6891 | # else | ||
6892 | , "", "" | ||
6893 | # endif | ||
6894 | ); | ||
6895 | debug_print_tree(command->group, lvl+1); | ||
6896 | prn++; | ||
6897 | continue; | ||
6898 | } | ||
6899 | if (argv) while (*argv) { | ||
6900 | fprintf(stderr, " '%s'", *argv); | ||
6901 | argv++; | ||
6902 | } | ||
6903 | fprintf(stderr, "\n"); | ||
6904 | prn++; | ||
6905 | } | ||
6906 | pi = pi->next; | ||
6907 | pin++; | ||
6908 | } | ||
6909 | } | ||
6910 | #endif /* debug_print_tree */ | ||
6911 | |||
6912 | /* NB: called by pseudo_exec, and therefore must not modify any | 7003 | /* NB: called by pseudo_exec, and therefore must not modify any |
6913 | * global data until exec/_exit (we can be a child after vfork!) */ | 7004 | * global data until exec/_exit (we can be a child after vfork!) */ |
6914 | static int run_list(struct pipe *pi) | 7005 | static int run_list(struct pipe *pi) |
@@ -6938,27 +7029,30 @@ static int run_list(struct pipe *pi) | |||
6938 | 7029 | ||
6939 | #if ENABLE_HUSH_LOOPS | 7030 | #if ENABLE_HUSH_LOOPS |
6940 | /* Check syntax for "for" */ | 7031 | /* Check syntax for "for" */ |
6941 | for (struct pipe *cpipe = pi; cpipe; cpipe = cpipe->next) { | 7032 | { |
6942 | if (cpipe->res_word != RES_FOR && cpipe->res_word != RES_IN) | 7033 | struct pipe *cpipe; |
6943 | continue; | 7034 | for (cpipe = pi; cpipe; cpipe = cpipe->next) { |
6944 | /* current word is FOR or IN (BOLD in comments below) */ | 7035 | if (cpipe->res_word != RES_FOR && cpipe->res_word != RES_IN) |
6945 | if (cpipe->next == NULL) { | 7036 | continue; |
6946 | syntax_error("malformed for"); | 7037 | /* current word is FOR or IN (BOLD in comments below) */ |
6947 | debug_leave(); | 7038 | if (cpipe->next == NULL) { |
6948 | debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level); | 7039 | syntax_error("malformed for"); |
6949 | return 1; | 7040 | debug_leave(); |
6950 | } | 7041 | debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level); |
6951 | /* "FOR v; do ..." and "for v IN a b; do..." are ok */ | 7042 | return 1; |
6952 | if (cpipe->next->res_word == RES_DO) | 7043 | } |
6953 | continue; | 7044 | /* "FOR v; do ..." and "for v IN a b; do..." are ok */ |
6954 | /* next word is not "do". It must be "in" then ("FOR v in ...") */ | 7045 | if (cpipe->next->res_word == RES_DO) |
6955 | if (cpipe->res_word == RES_IN /* "for v IN a b; not_do..."? */ | 7046 | continue; |
6956 | || cpipe->next->res_word != RES_IN /* FOR v not_do_and_not_in..."? */ | 7047 | /* next word is not "do". It must be "in" then ("FOR v in ...") */ |
6957 | ) { | 7048 | if (cpipe->res_word == RES_IN /* "for v IN a b; not_do..."? */ |
6958 | syntax_error("malformed for"); | 7049 | || cpipe->next->res_word != RES_IN /* FOR v not_do_and_not_in..."? */ |
6959 | debug_leave(); | 7050 | ) { |
6960 | debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level); | 7051 | syntax_error("malformed for"); |
6961 | return 1; | 7052 | debug_leave(); |
7053 | debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level); | ||
7054 | return 1; | ||
7055 | } | ||
6962 | } | 7056 | } |
6963 | } | 7057 | } |
6964 | #endif | 7058 | #endif |
@@ -7241,7 +7335,7 @@ static int run_and_free_list(struct pipe *pi) | |||
7241 | { | 7335 | { |
7242 | int rcode = 0; | 7336 | int rcode = 0; |
7243 | debug_printf_exec("run_and_free_list entered\n"); | 7337 | debug_printf_exec("run_and_free_list entered\n"); |
7244 | if (!G.n_mode) { | 7338 | if (!G.o_opt[OPT_O_NOEXEC]) { |
7245 | debug_printf_exec(": run_list: 1st pipe with %d cmds\n", pi->num_cmds); | 7339 | debug_printf_exec(": run_list: 1st pipe with %d cmds\n", pi->num_cmds); |
7246 | rcode = run_list(pi); | 7340 | rcode = run_list(pi); |
7247 | } | 7341 | } |
@@ -7339,13 +7433,41 @@ static void set_fatal_handlers(void) | |||
7339 | } | 7433 | } |
7340 | #endif | 7434 | #endif |
7341 | 7435 | ||
7342 | static int set_mode(const char cstate, const char mode) | 7436 | static int set_mode(int state, char mode, const char *o_opt) |
7343 | { | 7437 | { |
7344 | int state = (cstate == '-' ? 1 : 0); | 7438 | int idx; |
7345 | switch (mode) { | 7439 | switch (mode) { |
7346 | case 'n': G.n_mode = state; break; | 7440 | case 'n': |
7347 | case 'x': IF_HUSH_MODE_X(G_x_mode = state;) break; | 7441 | G.o_opt[OPT_O_NOEXEC] = state; |
7348 | default: return EXIT_FAILURE; | 7442 | break; |
7443 | case 'x': | ||
7444 | IF_HUSH_MODE_X(G_x_mode = state;) | ||
7445 | break; | ||
7446 | case 'o': | ||
7447 | if (!o_opt) { | ||
7448 | /* "set -+o" without parameter. | ||
7449 | * in bash, set -o produces this output: | ||
7450 | * pipefail off | ||
7451 | * and set +o: | ||
7452 | * set +o pipefail | ||
7453 | * We always use the second form. | ||
7454 | */ | ||
7455 | const char *p = o_opt_strings; | ||
7456 | idx = 0; | ||
7457 | while (*p) { | ||
7458 | printf("set %co %s\n", (G.o_opt[idx] ? '-' : '+'), p); | ||
7459 | idx++; | ||
7460 | p += strlen(p) + 1; | ||
7461 | } | ||
7462 | break; | ||
7463 | } | ||
7464 | idx = index_in_strings(o_opt_strings, o_opt); | ||
7465 | if (idx >= 0) { | ||
7466 | G.o_opt[idx] = state; | ||
7467 | break; | ||
7468 | } | ||
7469 | default: | ||
7470 | return EXIT_FAILURE; | ||
7349 | } | 7471 | } |
7350 | return EXIT_SUCCESS; | 7472 | return EXIT_SUCCESS; |
7351 | } | 7473 | } |
@@ -7357,7 +7479,7 @@ int hush_main(int argc, char **argv) | |||
7357 | unsigned builtin_argc; | 7479 | unsigned builtin_argc; |
7358 | char **e; | 7480 | char **e; |
7359 | struct variable *cur_var; | 7481 | struct variable *cur_var; |
7360 | struct variable shell_ver; | 7482 | struct variable *shell_ver; |
7361 | 7483 | ||
7362 | INIT_G(); | 7484 | INIT_G(); |
7363 | if (EXIT_SUCCESS) /* if EXIT_SUCCESS == 0, it is already done */ | 7485 | if (EXIT_SUCCESS) /* if EXIT_SUCCESS == 0, it is already done */ |
@@ -7366,17 +7488,17 @@ int hush_main(int argc, char **argv) | |||
7366 | G.argv0_for_re_execing = argv[0]; | 7488 | G.argv0_for_re_execing = argv[0]; |
7367 | #endif | 7489 | #endif |
7368 | /* Deal with HUSH_VERSION */ | 7490 | /* Deal with HUSH_VERSION */ |
7369 | memset(&shell_ver, 0, sizeof(shell_ver)); | 7491 | shell_ver = xzalloc(sizeof(*shell_ver)); |
7370 | shell_ver.flg_export = 1; | 7492 | shell_ver->flg_export = 1; |
7371 | shell_ver.flg_read_only = 1; | 7493 | shell_ver->flg_read_only = 1; |
7372 | /* Code which handles ${var<op>...} needs writable values for all variables, | 7494 | /* Code which handles ${var<op>...} needs writable values for all variables, |
7373 | * therefore we xstrdup: */ | 7495 | * therefore we xstrdup: */ |
7374 | shell_ver.varstr = xstrdup(hush_version_str), | 7496 | shell_ver->varstr = xstrdup(hush_version_str); |
7375 | G.top_var = &shell_ver; | ||
7376 | /* Create shell local variables from the values | 7497 | /* Create shell local variables from the values |
7377 | * currently living in the environment */ | 7498 | * currently living in the environment */ |
7378 | debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION"); | 7499 | debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION"); |
7379 | unsetenv("HUSH_VERSION"); /* in case it exists in initial env */ | 7500 | unsetenv("HUSH_VERSION"); /* in case it exists in initial env */ |
7501 | G.top_var = shell_ver; | ||
7380 | cur_var = G.top_var; | 7502 | cur_var = G.top_var; |
7381 | e = environ; | 7503 | e = environ; |
7382 | if (e) while (*e) { | 7504 | if (e) while (*e) { |
@@ -7391,8 +7513,8 @@ int hush_main(int argc, char **argv) | |||
7391 | e++; | 7513 | e++; |
7392 | } | 7514 | } |
7393 | /* (Re)insert HUSH_VERSION into env (AFTER we scanned the env!) */ | 7515 | /* (Re)insert HUSH_VERSION into env (AFTER we scanned the env!) */ |
7394 | debug_printf_env("putenv '%s'\n", shell_ver.varstr); | 7516 | debug_printf_env("putenv '%s'\n", shell_ver->varstr); |
7395 | putenv(shell_ver.varstr); | 7517 | putenv(shell_ver->varstr); |
7396 | 7518 | ||
7397 | /* Export PWD */ | 7519 | /* Export PWD */ |
7398 | set_pwd_var(/*exp:*/ 1); | 7520 | set_pwd_var(/*exp:*/ 1); |
@@ -7585,7 +7707,7 @@ int hush_main(int argc, char **argv) | |||
7585 | #endif | 7707 | #endif |
7586 | case 'n': | 7708 | case 'n': |
7587 | case 'x': | 7709 | case 'x': |
7588 | if (set_mode('-', opt) == 0) /* no error */ | 7710 | if (set_mode(1, opt, NULL) == 0) /* no error */ |
7589 | break; | 7711 | break; |
7590 | default: | 7712 | default: |
7591 | #ifndef BB_VER | 7713 | #ifndef BB_VER |
@@ -7752,18 +7874,6 @@ int hush_main(int argc, char **argv) | |||
7752 | parse_and_run_file(stdin); | 7874 | parse_and_run_file(stdin); |
7753 | 7875 | ||
7754 | final_return: | 7876 | final_return: |
7755 | #if ENABLE_FEATURE_CLEAN_UP | ||
7756 | if (G.cwd != bb_msg_unknown) | ||
7757 | free((char*)G.cwd); | ||
7758 | cur_var = G.top_var->next; | ||
7759 | while (cur_var) { | ||
7760 | struct variable *tmp = cur_var; | ||
7761 | if (!cur_var->max_len) | ||
7762 | free(cur_var->varstr); | ||
7763 | cur_var = cur_var->next; | ||
7764 | free(tmp); | ||
7765 | } | ||
7766 | #endif | ||
7767 | hush_exit(G.last_exitcode); | 7877 | hush_exit(G.last_exitcode); |
7768 | } | 7878 | } |
7769 | 7879 | ||
@@ -8375,15 +8485,18 @@ static int FAST_FUNC builtin_set(char **argv) | |||
8375 | } | 8485 | } |
8376 | 8486 | ||
8377 | do { | 8487 | do { |
8378 | if (!strcmp(arg, "--")) { | 8488 | if (strcmp(arg, "--") == 0) { |
8379 | ++argv; | 8489 | ++argv; |
8380 | goto set_argv; | 8490 | goto set_argv; |
8381 | } | 8491 | } |
8382 | if (arg[0] != '+' && arg[0] != '-') | 8492 | if (arg[0] != '+' && arg[0] != '-') |
8383 | break; | 8493 | break; |
8384 | for (n = 1; arg[n]; ++n) | 8494 | for (n = 1; arg[n]; ++n) { |
8385 | if (set_mode(arg[0], arg[n])) | 8495 | if (set_mode((arg[0] == '-'), arg[n], argv[1])) |
8386 | goto error; | 8496 | goto error; |
8497 | if (arg[n] == 'o' && argv[1]) | ||
8498 | argv++; | ||
8499 | } | ||
8387 | } while ((arg = *++argv) != NULL); | 8500 | } while ((arg = *++argv) != NULL); |
8388 | /* Now argv[0] is 1st argument */ | 8501 | /* Now argv[0] is 1st argument */ |
8389 | 8502 | ||
diff --git a/shell/hush_test/hush-misc/assignment3.right b/shell/hush_test/hush-misc/assignment3.right new file mode 100644 index 000000000..0f02d7cbc --- /dev/null +++ b/shell/hush_test/hush-misc/assignment3.right | |||
@@ -0,0 +1,2 @@ | |||
1 | Done:0 | ||
2 | abc=123 | ||
diff --git a/shell/hush_test/hush-misc/assignment3.tests b/shell/hush_test/hush-misc/assignment3.tests new file mode 100755 index 000000000..790129be1 --- /dev/null +++ b/shell/hush_test/hush-misc/assignment3.tests | |||
@@ -0,0 +1,5 @@ | |||
1 | # This must be interpreted as assignments | ||
2 | a=1 b\ | ||
3 | =2 c=3 | ||
4 | echo Done:$? | ||
5 | echo abc=$a$b$c | ||
diff --git a/shell/hush_test/hush-misc/pipefail.right b/shell/hush_test/hush-misc/pipefail.right new file mode 100644 index 000000000..5845d8939 --- /dev/null +++ b/shell/hush_test/hush-misc/pipefail.right | |||
@@ -0,0 +1,40 @@ | |||
1 | Default: | ||
2 | true | true: | ||
3 | 0 | ||
4 | 1 | ||
5 | true | false: | ||
6 | 1 | ||
7 | 0 | ||
8 | false | true: | ||
9 | 0 | ||
10 | 1 | ||
11 | exit 2 | exit 3 | exit 4: | ||
12 | 4 | ||
13 | 0 | ||
14 | Pipefail on: | ||
15 | true | true: | ||
16 | 0 | ||
17 | 1 | ||
18 | true | false: | ||
19 | 1 | ||
20 | 0 | ||
21 | false | true: | ||
22 | 1 | ||
23 | 0 | ||
24 | exit 2 | exit 3 | exit 4: | ||
25 | 4 | ||
26 | 0 | ||
27 | Pipefail off: | ||
28 | true | true: | ||
29 | 0 | ||
30 | 1 | ||
31 | true | false: | ||
32 | 1 | ||
33 | 0 | ||
34 | false | true: | ||
35 | 0 | ||
36 | 1 | ||
37 | exit 2 | exit 3 | exit 4: | ||
38 | 4 | ||
39 | 0 | ||
40 | Done | ||
diff --git a/shell/hush_test/hush-misc/pipefail.tests b/shell/hush_test/hush-misc/pipefail.tests new file mode 100755 index 000000000..9df841861 --- /dev/null +++ b/shell/hush_test/hush-misc/pipefail.tests | |||
@@ -0,0 +1,45 @@ | |||
1 | echo Default: | ||
2 | echo "true | true:" | ||
3 | true | true; echo $? | ||
4 | ! true | true; echo $? | ||
5 | echo "true | false:" | ||
6 | true | false; echo $? | ||
7 | ! true | false; echo $? | ||
8 | echo "false | true:" | ||
9 | false | true; echo $? | ||
10 | ! false | true; echo $? | ||
11 | echo "exit 2 | exit 3 | exit 4:" | ||
12 | exit 2 | exit 3 | exit 4; echo $? | ||
13 | ! exit 2 | exit 3 | exit 4; echo $? | ||
14 | |||
15 | echo Pipefail on: | ||
16 | set -o pipefail | ||
17 | echo "true | true:" | ||
18 | true | true; echo $? | ||
19 | ! true | true; echo $? | ||
20 | echo "true | false:" | ||
21 | true | false; echo $? | ||
22 | ! true | false; echo $? | ||
23 | echo "false | true:" | ||
24 | false | true; echo $? | ||
25 | ! false | true; echo $? | ||
26 | echo "exit 2 | exit 3 | exit 4:" | ||
27 | exit 2 | exit 3 | exit 4; echo $? | ||
28 | ! exit 2 | exit 3 | exit 4; echo $? | ||
29 | |||
30 | echo Pipefail off: | ||
31 | set +o pipefail | ||
32 | echo "true | true:" | ||
33 | true | true; echo $? | ||
34 | ! true | true; echo $? | ||
35 | echo "true | false:" | ||
36 | true | false; echo $? | ||
37 | ! true | false; echo $? | ||
38 | echo "false | true:" | ||
39 | false | true; echo $? | ||
40 | ! false | true; echo $? | ||
41 | echo "exit 2 | exit 3 | exit 4:" | ||
42 | exit 2 | exit 3 | exit 4; echo $? | ||
43 | ! exit 2 | exit 3 | exit 4; echo $? | ||
44 | |||
45 | echo Done | ||
diff --git a/shell/hush_test/hush-parsing/comment1.right b/shell/hush_test/hush-parsing/comment1.right new file mode 100644 index 000000000..a102b1d4e --- /dev/null +++ b/shell/hush_test/hush-parsing/comment1.right | |||
@@ -0,0 +1,2 @@ | |||
1 | Nothing: | ||
2 | String: #should-be-echoed | ||
diff --git a/shell/hush_test/hush-parsing/comment1.tests b/shell/hush_test/hush-parsing/comment1.tests new file mode 100755 index 000000000..d268860ff --- /dev/null +++ b/shell/hush_test/hush-parsing/comment1.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | echo Nothing: #should-not-be-echoed | ||
2 | echo String: ""#should-be-echoed | ||
diff --git a/shell/hush_test/hush-parsing/eol1.right b/shell/hush_test/hush-parsing/eol1.right new file mode 100644 index 000000000..31c896f62 --- /dev/null +++ b/shell/hush_test/hush-parsing/eol1.right | |||
@@ -0,0 +1 @@ | |||
Done:0 | |||
diff --git a/shell/hush_test/hush-parsing/eol1.tests b/shell/hush_test/hush-parsing/eol1.tests new file mode 100755 index 000000000..f1b55e8b8 --- /dev/null +++ b/shell/hush_test/hush-parsing/eol1.tests | |||
@@ -0,0 +1,18 @@ | |||
1 | # bug was that we treated <newline> as ';' in this line: | ||
2 | true || echo foo | | ||
3 | echo BAD1 | cat | ||
4 | |||
5 | # variation on the same theme | ||
6 | true || echo foo | | ||
7 | # comment | ||
8 | echo BAD2 | cat | ||
9 | |||
10 | # variation on the same theme | ||
11 | true || echo foo | | ||
12 | |||
13 | echo BAD3 | cat | ||
14 | |||
15 | # this should error out, but currently works in hush: | ||
16 | #true || echo foo |; | ||
17 | |||
18 | echo Done:$? | ||