diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | procps/fuser.c | 2 | ||||
-rwxr-xr-x | scripts/mkconfigs | 4 | ||||
-rw-r--r-- | shell/hush.c | 82 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/while3.right | 1 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/while3.tests | 4 |
6 files changed, 62 insertions, 33 deletions
@@ -1,6 +1,6 @@ | |||
1 | VERSION = 1 | 1 | VERSION = 1 |
2 | PATCHLEVEL = 18 | 2 | PATCHLEVEL = 18 |
3 | SUBLEVEL = 4 | 3 | SUBLEVEL = 5 |
4 | EXTRAVERSION = | 4 | EXTRAVERSION = |
5 | NAME = Unnamed | 5 | NAME = Unnamed |
6 | 6 | ||
diff --git a/procps/fuser.c b/procps/fuser.c index addf1a7d8..be19098dd 100644 --- a/procps/fuser.c +++ b/procps/fuser.c | |||
@@ -271,7 +271,7 @@ Find processes which use FILEs or PORTs | |||
271 | if (sscanf(*pp, "%u/%4s", &port, tproto) != 2) | 271 | if (sscanf(*pp, "%u/%4s", &port, tproto) != 2) |
272 | goto file; | 272 | goto file; |
273 | sprintf(path, "/proc/net/%s", tproto); | 273 | sprintf(path, "/proc/net/%s", tproto); |
274 | if (access(path, R_OK) != 0) { /* PORT/PROTO */ | 274 | if (access(path, R_OK) == 0) { /* PORT/PROTO */ |
275 | scan_proc_net(path, port); | 275 | scan_proc_net(path, port); |
276 | } else { /* FILE */ | 276 | } else { /* FILE */ |
277 | file: | 277 | file: |
diff --git a/scripts/mkconfigs b/scripts/mkconfigs index 47ac53330..db94fcc44 100755 --- a/scripts/mkconfigs +++ b/scripts/mkconfigs | |||
@@ -42,7 +42,7 @@ echo "\ | |||
42 | */ | 42 | */ |
43 | static const char bbconfig_config[] ALIGN1 =" | 43 | static const char bbconfig_config[] ALIGN1 =" |
44 | 44 | ||
45 | grep '^#\? \?CONFIG_' "$config" \ | 45 | grep -e '^# CONFIG_' -e '^CONFIG_' "$config" \ |
46 | | sed -e 's/\"/\\\"/g' -e 's/^/"/' -e 's/$/\\n"/' | 46 | | sed -e 's/\"/\\\"/g' -e 's/^/"/' -e 's/$/\\n"/' |
47 | 47 | ||
48 | echo ";" | 48 | echo ";" |
@@ -63,7 +63,7 @@ echo "\ | |||
63 | */ | 63 | */ |
64 | static const char bbconfig_config_bz2[] ALIGN1 = {" | 64 | static const char bbconfig_config_bz2[] ALIGN1 = {" |
65 | 65 | ||
66 | grep '^#\? \?CONFIG_' "$config" \ | 66 | grep -e '^# CONFIG_' -e '^CONFIG_' "$config" \ |
67 | | bzip2 -1 | dd bs=2 skip=1 2>/dev/null \ | 67 | | bzip2 -1 | dd bs=2 skip=1 2>/dev/null \ |
68 | | od -v -t x1 \ | 68 | | od -v -t x1 \ |
69 | | sed -e 's/^[^ ]*//' \ | 69 | | sed -e 's/^[^ ]*//' \ |
diff --git a/shell/hush.c b/shell/hush.c index 58d2c11a9..f0a0d85a3 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -427,6 +427,15 @@ enum { | |||
427 | /* Used for initialization: o_string foo = NULL_O_STRING; */ | 427 | /* Used for initialization: o_string foo = NULL_O_STRING; */ |
428 | #define NULL_O_STRING { NULL } | 428 | #define NULL_O_STRING { NULL } |
429 | 429 | ||
430 | #ifndef debug_printf_parse | ||
431 | static const char *const assignment_flag[] = { | ||
432 | "MAYBE_ASSIGNMENT", | ||
433 | "DEFINITELY_ASSIGNMENT", | ||
434 | "NOT_ASSIGNMENT", | ||
435 | "WORD_IS_KEYWORD", | ||
436 | }; | ||
437 | #endif | ||
438 | |||
430 | /* I can almost use ordinary FILE*. Is open_memstream() universally | 439 | /* I can almost use ordinary FILE*. Is open_memstream() universally |
431 | * available? Where is it documented? */ | 440 | * available? Where is it documented? */ |
432 | typedef struct in_str { | 441 | typedef struct in_str { |
@@ -2885,24 +2894,24 @@ static const struct reserved_combo* match_reserved_word(o_string *word) | |||
2885 | */ | 2894 | */ |
2886 | static const struct reserved_combo reserved_list[] = { | 2895 | static const struct reserved_combo reserved_list[] = { |
2887 | # if ENABLE_HUSH_IF | 2896 | # if ENABLE_HUSH_IF |
2888 | { "!", RES_NONE, NOT_ASSIGNMENT , 0 }, | 2897 | { "!", RES_NONE, NOT_ASSIGNMENT , 0 }, |
2889 | { "if", RES_IF, WORD_IS_KEYWORD, FLAG_THEN | FLAG_START }, | 2898 | { "if", RES_IF, MAYBE_ASSIGNMENT, FLAG_THEN | FLAG_START }, |
2890 | { "then", RES_THEN, WORD_IS_KEYWORD, FLAG_ELIF | FLAG_ELSE | FLAG_FI }, | 2899 | { "then", RES_THEN, MAYBE_ASSIGNMENT, FLAG_ELIF | FLAG_ELSE | FLAG_FI }, |
2891 | { "elif", RES_ELIF, WORD_IS_KEYWORD, FLAG_THEN }, | 2900 | { "elif", RES_ELIF, MAYBE_ASSIGNMENT, FLAG_THEN }, |
2892 | { "else", RES_ELSE, WORD_IS_KEYWORD, FLAG_FI }, | 2901 | { "else", RES_ELSE, MAYBE_ASSIGNMENT, FLAG_FI }, |
2893 | { "fi", RES_FI, NOT_ASSIGNMENT , FLAG_END }, | 2902 | { "fi", RES_FI, NOT_ASSIGNMENT , FLAG_END }, |
2894 | # endif | 2903 | # endif |
2895 | # if ENABLE_HUSH_LOOPS | 2904 | # if ENABLE_HUSH_LOOPS |
2896 | { "for", RES_FOR, NOT_ASSIGNMENT , FLAG_IN | FLAG_DO | FLAG_START }, | 2905 | { "for", RES_FOR, NOT_ASSIGNMENT , FLAG_IN | FLAG_DO | FLAG_START }, |
2897 | { "while", RES_WHILE, WORD_IS_KEYWORD, FLAG_DO | FLAG_START }, | 2906 | { "while", RES_WHILE, MAYBE_ASSIGNMENT, FLAG_DO | FLAG_START }, |
2898 | { "until", RES_UNTIL, WORD_IS_KEYWORD, FLAG_DO | FLAG_START }, | 2907 | { "until", RES_UNTIL, MAYBE_ASSIGNMENT, FLAG_DO | FLAG_START }, |
2899 | { "in", RES_IN, NOT_ASSIGNMENT , FLAG_DO }, | 2908 | { "in", RES_IN, NOT_ASSIGNMENT , FLAG_DO }, |
2900 | { "do", RES_DO, WORD_IS_KEYWORD, FLAG_DONE }, | 2909 | { "do", RES_DO, MAYBE_ASSIGNMENT, FLAG_DONE }, |
2901 | { "done", RES_DONE, NOT_ASSIGNMENT , FLAG_END }, | 2910 | { "done", RES_DONE, NOT_ASSIGNMENT , FLAG_END }, |
2902 | # endif | 2911 | # endif |
2903 | # if ENABLE_HUSH_CASE | 2912 | # if ENABLE_HUSH_CASE |
2904 | { "case", RES_CASE, NOT_ASSIGNMENT , FLAG_MATCH | FLAG_START }, | 2913 | { "case", RES_CASE, NOT_ASSIGNMENT , FLAG_MATCH | FLAG_START }, |
2905 | { "esac", RES_ESAC, NOT_ASSIGNMENT , FLAG_END }, | 2914 | { "esac", RES_ESAC, NOT_ASSIGNMENT , FLAG_END }, |
2906 | # endif | 2915 | # endif |
2907 | }; | 2916 | }; |
2908 | const struct reserved_combo *r; | 2917 | const struct reserved_combo *r; |
@@ -2968,6 +2977,7 @@ static int reserved_word(o_string *word, struct parse_context *ctx) | |||
2968 | ctx->ctx_res_w = r->res; | 2977 | ctx->ctx_res_w = r->res; |
2969 | ctx->old_flag = r->flag; | 2978 | ctx->old_flag = r->flag; |
2970 | word->o_assignment = r->assignment_flag; | 2979 | word->o_assignment = r->assignment_flag; |
2980 | debug_printf_parse("word->o_assignment='%s'\n", assignment_flag[word->o_assignment]); | ||
2971 | 2981 | ||
2972 | if (ctx->old_flag & FLAG_END) { | 2982 | if (ctx->old_flag & FLAG_END) { |
2973 | struct parse_context *old; | 2983 | struct parse_context *old; |
@@ -3034,18 +3044,6 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
3034 | debug_printf_parse("word stored in rd_filename: '%s'\n", word->data); | 3044 | debug_printf_parse("word stored in rd_filename: '%s'\n", word->data); |
3035 | ctx->pending_redirect = NULL; | 3045 | ctx->pending_redirect = NULL; |
3036 | } else { | 3046 | } else { |
3037 | /* If this word wasn't an assignment, next ones definitely | ||
3038 | * can't be assignments. Even if they look like ones. */ | ||
3039 | if (word->o_assignment != DEFINITELY_ASSIGNMENT | ||
3040 | && word->o_assignment != WORD_IS_KEYWORD | ||
3041 | ) { | ||
3042 | word->o_assignment = NOT_ASSIGNMENT; | ||
3043 | } else { | ||
3044 | if (word->o_assignment == DEFINITELY_ASSIGNMENT) | ||
3045 | command->assignment_cnt++; | ||
3046 | word->o_assignment = MAYBE_ASSIGNMENT; | ||
3047 | } | ||
3048 | |||
3049 | #if HAS_KEYWORDS | 3047 | #if HAS_KEYWORDS |
3050 | # if ENABLE_HUSH_CASE | 3048 | # if ENABLE_HUSH_CASE |
3051 | if (ctx->ctx_dsemicolon | 3049 | if (ctx->ctx_dsemicolon |
@@ -3065,8 +3063,9 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
3065 | && ctx->ctx_res_w != RES_CASE | 3063 | && ctx->ctx_res_w != RES_CASE |
3066 | # endif | 3064 | # endif |
3067 | ) { | 3065 | ) { |
3068 | debug_printf_parse("checking '%s' for reserved-ness\n", word->data); | 3066 | int reserved = reserved_word(word, ctx); |
3069 | if (reserved_word(word, ctx)) { | 3067 | debug_printf_parse("checking for reserved-ness: %d\n", reserved); |
3068 | if (reserved) { | ||
3070 | o_reset_to_empty_unquoted(word); | 3069 | o_reset_to_empty_unquoted(word); |
3071 | debug_printf_parse("done_word return %d\n", | 3070 | debug_printf_parse("done_word return %d\n", |
3072 | (ctx->ctx_res_w == RES_SNTX)); | 3071 | (ctx->ctx_res_w == RES_SNTX)); |
@@ -3087,6 +3086,23 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
3087 | "groups and arglists don't mix\n"); | 3086 | "groups and arglists don't mix\n"); |
3088 | return 1; | 3087 | return 1; |
3089 | } | 3088 | } |
3089 | |||
3090 | /* If this word wasn't an assignment, next ones definitely | ||
3091 | * can't be assignments. Even if they look like ones. */ | ||
3092 | if (word->o_assignment != DEFINITELY_ASSIGNMENT | ||
3093 | && word->o_assignment != WORD_IS_KEYWORD | ||
3094 | ) { | ||
3095 | word->o_assignment = NOT_ASSIGNMENT; | ||
3096 | } else { | ||
3097 | if (word->o_assignment == DEFINITELY_ASSIGNMENT) { | ||
3098 | command->assignment_cnt++; | ||
3099 | debug_printf_parse("++assignment_cnt=%d\n", command->assignment_cnt); | ||
3100 | } | ||
3101 | debug_printf_parse("word->o_assignment was:'%s'\n", assignment_flag[word->o_assignment]); | ||
3102 | word->o_assignment = MAYBE_ASSIGNMENT; | ||
3103 | } | ||
3104 | debug_printf_parse("word->o_assignment='%s'\n", assignment_flag[word->o_assignment]); | ||
3105 | |||
3090 | if (word->has_quoted_part | 3106 | if (word->has_quoted_part |
3091 | /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */ | 3107 | /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */ |
3092 | && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL) | 3108 | && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL) |
@@ -4105,6 +4121,7 @@ static struct pipe *parse_stream(char **pstring, | |||
4105 | && is_well_formed_var_name(dest.data, '=') | 4121 | && is_well_formed_var_name(dest.data, '=') |
4106 | ) { | 4122 | ) { |
4107 | dest.o_assignment = DEFINITELY_ASSIGNMENT; | 4123 | dest.o_assignment = DEFINITELY_ASSIGNMENT; |
4124 | debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); | ||
4108 | } | 4125 | } |
4109 | continue; | 4126 | continue; |
4110 | } | 4127 | } |
@@ -4154,6 +4171,7 @@ static struct pipe *parse_stream(char **pstring, | |||
4154 | heredoc_cnt = 0; | 4171 | heredoc_cnt = 0; |
4155 | } | 4172 | } |
4156 | dest.o_assignment = MAYBE_ASSIGNMENT; | 4173 | dest.o_assignment = MAYBE_ASSIGNMENT; |
4174 | debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); | ||
4157 | ch = ';'; | 4175 | ch = ';'; |
4158 | /* note: if (is_blank) continue; | 4176 | /* note: if (is_blank) continue; |
4159 | * will still trigger for us */ | 4177 | * will still trigger for us */ |
@@ -4203,6 +4221,7 @@ static struct pipe *parse_stream(char **pstring, | |||
4203 | } | 4221 | } |
4204 | done_pipe(&ctx, PIPE_SEQ); | 4222 | done_pipe(&ctx, PIPE_SEQ); |
4205 | dest.o_assignment = MAYBE_ASSIGNMENT; | 4223 | dest.o_assignment = MAYBE_ASSIGNMENT; |
4224 | debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); | ||
4206 | /* Do we sit outside of any if's, loops or case's? */ | 4225 | /* Do we sit outside of any if's, loops or case's? */ |
4207 | if (!HAS_KEYWORDS | 4226 | if (!HAS_KEYWORDS |
4208 | IF_HAS_KEYWORDS(|| (ctx.ctx_res_w == RES_NONE && ctx.old_flag == 0)) | 4227 | IF_HAS_KEYWORDS(|| (ctx.ctx_res_w == RES_NONE && ctx.old_flag == 0)) |
@@ -4309,6 +4328,7 @@ static struct pipe *parse_stream(char **pstring, | |||
4309 | /* ch is a special char and thus this word | 4328 | /* ch is a special char and thus this word |
4310 | * cannot be an assignment */ | 4329 | * cannot be an assignment */ |
4311 | dest.o_assignment = NOT_ASSIGNMENT; | 4330 | dest.o_assignment = NOT_ASSIGNMENT; |
4331 | debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); | ||
4312 | } | 4332 | } |
4313 | 4333 | ||
4314 | /* Note: nommu_addchr(&ctx.as_string, ch) is already done */ | 4334 | /* Note: nommu_addchr(&ctx.as_string, ch) is already done */ |
@@ -4406,6 +4426,7 @@ static struct pipe *parse_stream(char **pstring, | |||
4406 | /* We just finished a cmd. New one may start | 4426 | /* We just finished a cmd. New one may start |
4407 | * with an assignment */ | 4427 | * with an assignment */ |
4408 | dest.o_assignment = MAYBE_ASSIGNMENT; | 4428 | dest.o_assignment = MAYBE_ASSIGNMENT; |
4429 | debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); | ||
4409 | break; | 4430 | break; |
4410 | case '&': | 4431 | case '&': |
4411 | if (done_word(&dest, &ctx)) { | 4432 | if (done_word(&dest, &ctx)) { |
@@ -7292,7 +7313,10 @@ static int run_list(struct pipe *pi) | |||
7292 | #endif | 7313 | #endif |
7293 | #if ENABLE_HUSH_LOOPS | 7314 | #if ENABLE_HUSH_LOOPS |
7294 | /* Beware of "while false; true; do ..."! */ | 7315 | /* Beware of "while false; true; do ..."! */ |
7295 | if (pi->next && pi->next->res_word == RES_DO) { | 7316 | if (pi->next |
7317 | && (pi->next->res_word == RES_DO || pi->next->res_word == RES_DONE) | ||
7318 | /* (the second check above is needed for "while ...; do \n done" case) */ | ||
7319 | ) { | ||
7296 | if (rword == RES_WHILE) { | 7320 | if (rword == RES_WHILE) { |
7297 | if (rcode) { | 7321 | if (rcode) { |
7298 | /* "while false; do...done" - exitcode 0 */ | 7322 | /* "while false; do...done" - exitcode 0 */ |
diff --git a/shell/hush_test/hush-misc/while3.right b/shell/hush_test/hush-misc/while3.right new file mode 100644 index 000000000..7c4d7beb0 --- /dev/null +++ b/shell/hush_test/hush-misc/while3.right | |||
@@ -0,0 +1 @@ | |||
OK:0 | |||
diff --git a/shell/hush_test/hush-misc/while3.tests b/shell/hush_test/hush-misc/while3.tests new file mode 100755 index 000000000..9132b5f4d --- /dev/null +++ b/shell/hush_test/hush-misc/while3.tests | |||
@@ -0,0 +1,4 @@ | |||
1 | while false; do | ||
2 | # bash will require at least ":" here... | ||
3 | done | ||
4 | echo OK:$? | ||