hush: case logic for setting $? was still wrong
authorDenys Vlasenko <vda.linux@googlemail.com>
Fri, 4 Nov 2016 19:14:04 +0000 (20:14 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Fri, 4 Nov 2016 19:14:04 +0000 (20:14 +0100)
Resetting to 0 should happen in "esac". Matched branch must
still see previous $?.

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
shell/hush.c

index 4c2ed6cead72ba0e9f081ef39f758ff043bb0ea9..0bc67ecc9ced55f860a12786b9c50992fc341181 100644 (file)
@@ -7874,14 +7874,14 @@ static int run_list(struct pipe *pi)
 #endif
 #if ENABLE_HUSH_CASE
                if (rword == RES_CASE) {
-                       /* Case which does not match and execute anything still sets $? to 0 */
-                       G.last_exitcode = rcode = EXIT_SUCCESS;
+                       debug_printf_exec("CASE cond_code:%d\n", cond_code);
                        case_word = expand_strvec_to_string(pi->cmds->argv);
                        continue;
                }
                if (rword == RES_MATCH) {
                        char **argv;
 
+                       debug_printf_exec("MATCH cond_code:%d\n", cond_code);
                        if (!case_word) /* "case ... matched_word) ... WORD)": we executed selected branch, stop */
                                break;
                        /* all prev words didn't match, does this one match? */
@@ -7892,8 +7892,8 @@ static int run_list(struct pipe *pi)
                                cond_code = (fnmatch(pattern, case_word, /*flags:*/ 0) != 0);
                                free(pattern);
                                if (cond_code == 0) { /* match! we will execute this branch */
-                                       free(case_word); /* make future "word)" stop */
-                                       case_word = NULL;
+                                       free(case_word);
+                                       case_word = NULL; /* make future "word)" stop */
                                        break;
                                }
                                argv++;
@@ -7901,9 +7901,17 @@ static int run_list(struct pipe *pi)
                        continue;
                }
                if (rword == RES_CASE_BODY) { /* inside of a case branch */
+                       debug_printf_exec("CASE_BODY cond_code:%d\n", cond_code);
                        if (cond_code != 0)
                                continue; /* not matched yet, skip this pipe */
                }
+               if (rword == RES_ESAC) {
+                       debug_printf_exec("ESAC cond_code:%d\n", cond_code);
+                       if (case_word) {
+                               /* "case" did not match anything: still set $? (to 0) */
+                               G.last_exitcode = rcode = EXIT_SUCCESS;
+                       }
+               }
 #endif
                /* Just pressing <enter> in shell should check for jobs.
                 * OTOH, in non-interactive shell this is useless