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:$? | ||
