diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-06 14:11:13 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-06 14:11:13 +0000 |
commit | a2b11e33950d7e0a352005fec6cfff9bdeb7c668 (patch) | |
tree | f9e6cf316f7c678bcac3a4cbacc45cc2a5d4979d /shell | |
parent | 0969a49c081aee3c53241e2f53ebc89d14070a39 (diff) | |
download | busybox-w32-a2b11e33950d7e0a352005fec6cfff9bdeb7c668.tar.gz busybox-w32-a2b11e33950d7e0a352005fec6cfff9bdeb7c668.tar.bz2 busybox-w32-a2b11e33950d7e0a352005fec6cfff9bdeb7c668.zip |
hush: fix "false && echo yes || echo no" bug 265
function old new delta
run_list 1159 1189 +30
Diffstat (limited to '')
-rw-r--r-- | shell/hush.c | 100 |
1 files changed, 55 insertions, 45 deletions
diff --git a/shell/hush.c b/shell/hush.c index 3eb03e50b..227e73507 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -271,13 +271,6 @@ static const struct { | |||
271 | { O_RDWR, 1, "<>" } | 271 | { O_RDWR, 1, "<>" } |
272 | }; | 272 | }; |
273 | 273 | ||
274 | typedef enum pipe_style { | ||
275 | PIPE_SEQ = 1, | ||
276 | PIPE_AND = 2, | ||
277 | PIPE_OR = 3, | ||
278 | PIPE_BG = 4, | ||
279 | } pipe_style; | ||
280 | |||
281 | typedef enum reserved_style { | 274 | typedef enum reserved_style { |
282 | RES_NONE = 0, | 275 | RES_NONE = 0, |
283 | #if ENABLE_HUSH_IF | 276 | #if ENABLE_HUSH_IF |
@@ -395,6 +388,12 @@ struct pipe { | |||
395 | IF_HAS_KEYWORDS(smallint pi_inverted;) /* "! cmd | cmd" */ | 388 | IF_HAS_KEYWORDS(smallint pi_inverted;) /* "! cmd | cmd" */ |
396 | IF_HAS_KEYWORDS(smallint res_word;) /* needed for if, for, while, until... */ | 389 | IF_HAS_KEYWORDS(smallint res_word;) /* needed for if, for, while, until... */ |
397 | }; | 390 | }; |
391 | typedef enum pipe_style { | ||
392 | PIPE_SEQ = 1, | ||
393 | PIPE_AND = 2, | ||
394 | PIPE_OR = 3, | ||
395 | PIPE_BG = 4, | ||
396 | } pipe_style; | ||
398 | 397 | ||
399 | /* This holds pointers to the various results of parsing */ | 398 | /* This holds pointers to the various results of parsing */ |
400 | struct parse_context { | 399 | struct parse_context { |
@@ -2158,7 +2157,7 @@ static void free_pipe_list(struct pipe *head, int indent) | |||
2158 | 2157 | ||
2159 | for (pi = head; pi; pi = next) { | 2158 | for (pi = head; pi; pi = next) { |
2160 | #if HAS_KEYWORDS | 2159 | #if HAS_KEYWORDS |
2161 | debug_printf_clean("%s pipe reserved mode %d\n", indenter(indent), pi->res_word); | 2160 | debug_printf_clean("%s pipe reserved word %d\n", indenter(indent), pi->res_word); |
2162 | #endif | 2161 | #endif |
2163 | free_pipe(pi, indent); | 2162 | free_pipe(pi, indent); |
2164 | debug_printf_clean("%s pipe followup code %d\n", indenter(indent), pi->followup); | 2163 | debug_printf_clean("%s pipe followup code %d\n", indenter(indent), pi->followup); |
@@ -2182,7 +2181,7 @@ typedef struct nommu_save_t { | |||
2182 | pseudo_exec(command, argv_expanded) | 2181 | pseudo_exec(command, argv_expanded) |
2183 | #endif | 2182 | #endif |
2184 | 2183 | ||
2185 | /* Called after [v]fork() in run_pipe(), or from builtin_exec(). | 2184 | /* Called after [v]fork() in run_pipe, or from builtin_exec. |
2186 | * Never returns. | 2185 | * Never returns. |
2187 | * XXX no exit() here. If you don't exec, use _exit instead. | 2186 | * XXX no exit() here. If you don't exec, use _exit instead. |
2188 | * The at_exit handlers apparently confuse the calling process, | 2187 | * The at_exit handlers apparently confuse the calling process, |
@@ -2389,7 +2388,7 @@ static void clean_up_after_re_execute(void) | |||
2389 | 2388 | ||
2390 | static int run_list(struct pipe *pi); | 2389 | static int run_list(struct pipe *pi); |
2391 | 2390 | ||
2392 | /* Called after [v]fork() in run_pipe() | 2391 | /* Called after [v]fork() in run_pipe |
2393 | */ | 2392 | */ |
2394 | static void pseudo_exec(nommu_save_t *nommu_save, | 2393 | static void pseudo_exec(nommu_save_t *nommu_save, |
2395 | struct command *command, | 2394 | struct command *command, |
@@ -3032,15 +3031,15 @@ static int run_list(struct pipe *pi) | |||
3032 | char **for_lcur = NULL; | 3031 | char **for_lcur = NULL; |
3033 | char **for_list = NULL; | 3032 | char **for_list = NULL; |
3034 | #endif | 3033 | #endif |
3035 | smallint flag_skip = 1; | 3034 | smallint last_followup; |
3036 | smalluint rcode = 0; /* probably just for compiler */ | 3035 | smalluint rcode; |
3037 | #if ENABLE_HUSH_IF || ENABLE_HUSH_CASE | 3036 | #if ENABLE_HUSH_IF || ENABLE_HUSH_CASE |
3038 | smalluint cond_code = 0; | 3037 | smalluint cond_code = 0; |
3039 | #else | 3038 | #else |
3040 | enum { cond_code = 0, }; | 3039 | enum { cond_code = 0 }; |
3041 | #endif | 3040 | #endif |
3042 | /*enum reserved_style*/ smallint rword = RES_NONE; | 3041 | /*enum reserved_style*/ smallint rword; |
3043 | /*enum reserved_style*/ smallint skip_more_for_this_rword = RES_XXXX; | 3042 | /*enum reserved_style*/ smallint last_rword; |
3044 | 3043 | ||
3045 | debug_printf_exec("run_list start lvl %d\n", G.run_list_level + 1); | 3044 | debug_printf_exec("run_list start lvl %d\n", G.run_list_level + 1); |
3046 | 3045 | ||
@@ -3119,6 +3118,11 @@ static int run_list(struct pipe *pi) | |||
3119 | } | 3118 | } |
3120 | #endif /* JOB */ | 3119 | #endif /* JOB */ |
3121 | 3120 | ||
3121 | rcode = G.last_return_code; | ||
3122 | rword = RES_NONE; | ||
3123 | last_rword = RES_XXXX; | ||
3124 | last_followup = PIPE_SEQ; | ||
3125 | |||
3122 | /* Go through list of pipes, (maybe) executing them. */ | 3126 | /* Go through list of pipes, (maybe) executing them. */ |
3123 | for (; pi; pi = USE_HUSH_LOOPS(rword == RES_DONE ? loop_top : ) pi->next) { | 3127 | for (; pi; pi = USE_HUSH_LOOPS(rword == RES_DONE ? loop_top : ) pi->next) { |
3124 | if (G.flag_SIGINT) | 3128 | if (G.flag_SIGINT) |
@@ -3126,8 +3130,8 @@ static int run_list(struct pipe *pi) | |||
3126 | 3130 | ||
3127 | IF_HAS_KEYWORDS(rword = pi->res_word;) | 3131 | IF_HAS_KEYWORDS(rword = pi->res_word;) |
3128 | IF_HAS_NO_KEYWORDS(rword = RES_NONE;) | 3132 | IF_HAS_NO_KEYWORDS(rword = RES_NONE;) |
3129 | debug_printf_exec(": rword=%d cond_code=%d skip_more=%d\n", | 3133 | debug_printf_exec(": rword=%d cond_code=%d last_rword=%d\n", |
3130 | rword, cond_code, skip_more_for_this_rword); | 3134 | rword, cond_code, last_rword); |
3131 | #if ENABLE_HUSH_LOOPS | 3135 | #if ENABLE_HUSH_LOOPS |
3132 | if ((rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR) | 3136 | if ((rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR) |
3133 | && loop_top == NULL /* avoid bumping G.depth_of_loop twice */ | 3137 | && loop_top == NULL /* avoid bumping G.depth_of_loop twice */ |
@@ -3137,15 +3141,20 @@ static int run_list(struct pipe *pi) | |||
3137 | G.depth_of_loop++; | 3141 | G.depth_of_loop++; |
3138 | } | 3142 | } |
3139 | #endif | 3143 | #endif |
3140 | if (rword == skip_more_for_this_rword && flag_skip) { | 3144 | /* Still in the same "if...", "then..." or "do..." branch? */ |
3141 | if (pi->followup == PIPE_SEQ) | 3145 | if (rword == last_rword) { |
3142 | flag_skip = 0; | 3146 | if ((rcode == 0 && last_followup == PIPE_OR) |
3143 | /* it is "<false> && CMD" or "<true> || CMD" | 3147 | || (rcode != 0 && last_followup == PIPE_AND) |
3144 | * and we should not execute CMD */ | 3148 | ) { |
3145 | continue; | 3149 | /* It is "<true> || CMD" or "<false> && CMD" |
3150 | * and we should not execute CMD */ | ||
3151 | debug_printf_exec("skipped cmd because of || or &&\n"); | ||
3152 | last_followup = pi->followup; | ||
3153 | continue; | ||
3154 | } | ||
3146 | } | 3155 | } |
3147 | flag_skip = 1; | 3156 | last_followup = pi->followup; |
3148 | skip_more_for_this_rword = RES_XXXX; | 3157 | last_rword = rword; |
3149 | #if ENABLE_HUSH_IF | 3158 | #if ENABLE_HUSH_IF |
3150 | if (cond_code) { | 3159 | if (cond_code) { |
3151 | if (rword == RES_THEN) { | 3160 | if (rword == RES_THEN) { |
@@ -3176,8 +3185,11 @@ static int run_list(struct pipe *pi) | |||
3176 | vals = (char**)encoded_dollar_at_argv; | 3185 | vals = (char**)encoded_dollar_at_argv; |
3177 | if (pi->next->res_word == RES_IN) { | 3186 | if (pi->next->res_word == RES_IN) { |
3178 | /* if no variable values after "in" we skip "for" */ | 3187 | /* if no variable values after "in" we skip "for" */ |
3179 | if (!pi->next->cmds[0].argv) | 3188 | if (!pi->next->cmds[0].argv) { |
3189 | G.last_return_code = rcode = EXIT_SUCCESS; | ||
3190 | debug_printf_exec(": null FOR: exitcode EXIT_SUCCESS\n"); | ||
3180 | break; | 3191 | break; |
3192 | } | ||
3181 | vals = pi->next->cmds[0].argv; | 3193 | vals = pi->next->cmds[0].argv; |
3182 | } /* else: "for var; do..." -> assume "$@" list */ | 3194 | } /* else: "for var; do..." -> assume "$@" list */ |
3183 | /* create list of variable values */ | 3195 | /* create list of variable values */ |
@@ -3197,7 +3209,7 @@ static int run_list(struct pipe *pi) | |||
3197 | pi->cmds[0].argv[0] = for_varname; | 3209 | pi->cmds[0].argv[0] = for_varname; |
3198 | break; | 3210 | break; |
3199 | } | 3211 | } |
3200 | /* insert next value from for_lcur */ | 3212 | /* Insert next value from for_lcur */ |
3201 | //TODO: does it need escaping? | 3213 | //TODO: does it need escaping? |
3202 | pi->cmds[0].argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++); | 3214 | pi->cmds[0].argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++); |
3203 | pi->cmds[0].assignment_cnt = 1; | 3215 | pi->cmds[0].assignment_cnt = 1; |
@@ -3251,7 +3263,7 @@ static int run_list(struct pipe *pi) | |||
3251 | 3263 | ||
3252 | /* After analyzing all keywords and conditions, we decided | 3264 | /* After analyzing all keywords and conditions, we decided |
3253 | * to execute this pipe. NB: have to do checkjobs(NULL) | 3265 | * to execute this pipe. NB: have to do checkjobs(NULL) |
3254 | * after run_pipe() to collect any background children, | 3266 | * after run_pipe to collect any background children, |
3255 | * even if list execution is to be stopped. */ | 3267 | * even if list execution is to be stopped. */ |
3256 | debug_printf_exec(": run_pipe with %d members\n", pi->num_cmds); | 3268 | debug_printf_exec(": run_pipe with %d members\n", pi->num_cmds); |
3257 | { | 3269 | { |
@@ -3261,14 +3273,16 @@ static int run_list(struct pipe *pi) | |||
3261 | #endif | 3273 | #endif |
3262 | rcode = r = run_pipe(pi); /* NB: rcode is a smallint */ | 3274 | rcode = r = run_pipe(pi); /* NB: rcode is a smallint */ |
3263 | if (r != -1) { | 3275 | if (r != -1) { |
3264 | /* we only ran a builtin: rcode is already known | 3276 | /* We only ran a builtin: rcode is already known |
3265 | * and we don't need to wait for anything. */ | 3277 | * and we don't need to wait for anything. */ |
3278 | G.last_return_code = rcode; | ||
3279 | debug_printf_exec(": builtin exitcode %d\n", rcode); | ||
3266 | check_and_run_traps(0); | 3280 | check_and_run_traps(0); |
3267 | #if ENABLE_HUSH_LOOPS | 3281 | #if ENABLE_HUSH_LOOPS |
3268 | /* was it "break" or "continue"? */ | 3282 | /* Was it "break" or "continue"? */ |
3269 | if (G.flag_break_continue) { | 3283 | if (G.flag_break_continue) { |
3270 | smallint fbc = G.flag_break_continue; | 3284 | smallint fbc = G.flag_break_continue; |
3271 | /* we might fall into outer *loop*, | 3285 | /* We might fall into outer *loop*, |
3272 | * don't want to break it too */ | 3286 | * don't want to break it too */ |
3273 | if (loop_top) { | 3287 | if (loop_top) { |
3274 | G.depth_break_continue--; | 3288 | G.depth_break_continue--; |
@@ -3284,7 +3298,7 @@ static int run_list(struct pipe *pi) | |||
3284 | } | 3298 | } |
3285 | #endif | 3299 | #endif |
3286 | } else if (pi->followup == PIPE_BG) { | 3300 | } else if (pi->followup == PIPE_BG) { |
3287 | /* what does bash do with attempts to background builtins? */ | 3301 | /* What does bash do with attempts to background builtins? */ |
3288 | /* even bash 3.2 doesn't do that well with nested bg: | 3302 | /* even bash 3.2 doesn't do that well with nested bg: |
3289 | * try "{ { sleep 10; echo DEEP; } & echo HERE; } &". | 3303 | * try "{ { sleep 10; echo DEEP; } & echo HERE; } &". |
3290 | * I'm NOT treating inner &'s as jobs */ | 3304 | * I'm NOT treating inner &'s as jobs */ |
@@ -3293,25 +3307,26 @@ static int run_list(struct pipe *pi) | |||
3293 | if (G.run_list_level == 1) | 3307 | if (G.run_list_level == 1) |
3294 | insert_bg_job(pi); | 3308 | insert_bg_job(pi); |
3295 | #endif | 3309 | #endif |
3296 | rcode = 0; /* EXIT_SUCCESS */ | 3310 | rcode = EXIT_SUCCESS; |
3311 | G.last_return_code = EXIT_SUCCESS; | ||
3312 | debug_printf_exec(": cmd&: exitcode EXIT_SUCCESS\n"); | ||
3297 | } else { | 3313 | } else { |
3298 | #if ENABLE_HUSH_JOB | 3314 | #if ENABLE_HUSH_JOB |
3299 | if (G.run_list_level == 1 && G_interactive_fd) { | 3315 | if (G.run_list_level == 1 && G_interactive_fd) { |
3300 | /* waits for completion, then fg's main shell */ | 3316 | /* Waits for completion, then fg's main shell */ |
3301 | rcode = checkjobs_and_fg_shell(pi); | 3317 | rcode = checkjobs_and_fg_shell(pi); |
3318 | debug_printf_exec(": checkjobs_and_fg_shell exitcode %d\n", rcode); | ||
3302 | check_and_run_traps(0); | 3319 | check_and_run_traps(0); |
3303 | debug_printf_exec(": checkjobs_and_fg_shell returned %d\n", rcode); | ||
3304 | } else | 3320 | } else |
3305 | #endif | 3321 | #endif |
3306 | { /* this one just waits for completion */ | 3322 | { /* This one just waits for completion */ |
3307 | rcode = checkjobs(pi); | 3323 | rcode = checkjobs(pi); |
3324 | debug_printf_exec(": checkjobs exitcode %d\n", rcode); | ||
3308 | check_and_run_traps(0); | 3325 | check_and_run_traps(0); |
3309 | debug_printf_exec(": checkjobs returned %d\n", rcode); | ||
3310 | } | 3326 | } |
3327 | G.last_return_code = rcode; | ||
3311 | } | 3328 | } |
3312 | } | 3329 | } |
3313 | debug_printf_exec(": setting last_return_code=%d\n", rcode); | ||
3314 | G.last_return_code = rcode; | ||
3315 | 3330 | ||
3316 | /* Analyze how result affects subsequent commands */ | 3331 | /* Analyze how result affects subsequent commands */ |
3317 | #if ENABLE_HUSH_IF | 3332 | #if ENABLE_HUSH_IF |
@@ -3333,11 +3348,6 @@ static int run_list(struct pipe *pi) | |||
3333 | } | 3348 | } |
3334 | } | 3349 | } |
3335 | #endif | 3350 | #endif |
3336 | if ((rcode == 0 && pi->followup == PIPE_OR) | ||
3337 | || (rcode != 0 && pi->followup == PIPE_AND) | ||
3338 | ) { | ||
3339 | skip_more_for_this_rword = rword; | ||
3340 | } | ||
3341 | 3351 | ||
3342 | check_jobs_and_continue: | 3352 | check_jobs_and_continue: |
3343 | checkjobs(NULL); | 3353 | checkjobs(NULL); |
@@ -3375,7 +3385,7 @@ static int run_and_free_list(struct pipe *pi) | |||
3375 | int rcode = 0; | 3385 | int rcode = 0; |
3376 | debug_printf_exec("run_and_free_list entered\n"); | 3386 | debug_printf_exec("run_and_free_list entered\n"); |
3377 | if (!G.fake_mode) { | 3387 | if (!G.fake_mode) { |
3378 | debug_printf_exec(": run_list with %d members\n", pi->num_cmds); | 3388 | debug_printf_exec(": run_list: 1st pipe with %d cmds\n", pi->num_cmds); |
3379 | rcode = run_list(pi); | 3389 | rcode = run_list(pi); |
3380 | } | 3390 | } |
3381 | /* free_pipe_list has the side effect of clearing memory. | 3391 | /* free_pipe_list has the side effect of clearing memory. |