[SV 47151] Exit with 1 when checking recursive make -q

* job.h (struct child): New bit to mark recursive command lines.
* job.c (start_job_command): Set the recursive command line bit.
(reap_children): If the child is a recursive command and it exits
with 1 during question mode, don't print an error and exit with 1.
* tests/scripts/options/dash-q: Add a regression test.
diff --git a/job.c b/job.c
index bbc304a..45a433f 100644
--- a/job.c
+++ b/job.c
@@ -819,8 +819,6 @@
           break;
         }
 
-      child_failed = exit_sig != 0 || exit_code != 0;
-
       /* Search for a child matching the deceased one.  */
       lastc = 0;
       for (c = children; c != 0; lastc = c, c = c->next)
@@ -832,6 +830,15 @@
            Ignore it; it was inherited from our invoker.  */
         continue;
 
+      /* Determine the failure status: 0 for success, 1 for updating target in
+         question mode, 2 for anything else.  */
+      if (exit_sig == 0 && exit_code == 0)
+        child_failed = MAKE_SUCCESS;
+      else if (exit_sig == 0 && exit_code == 1 && question_flag && c->recursive)
+        child_failed = MAKE_TROUBLE;
+      else
+        child_failed = MAKE_FAILURE;
+
       DB (DB_JOBS, (child_failed
                     ? _("Reaping losing child %p PID %s %s\n")
                     : _("Reaping winning child %p PID %s %s\n"),
@@ -867,10 +874,10 @@
              delete non-precious targets, and abort.  */
           static int delete_on_error = -1;
 
-          if (!dontcare)
+          if (!dontcare && child_failed == MAKE_FAILURE)
             child_error (c, exit_code, exit_sig, coredump, 0);
 
-          c->file->update_status = us_failed;
+          c->file->update_status = child_failed == MAKE_FAILURE ? us_failed : us_question;
           if (delete_on_error == -1)
             {
               struct file *f = lookup_file (".DELETE_ON_ERROR");
@@ -982,7 +989,7 @@
       if (!err && child_failed && !dontcare && !keep_going_flag &&
           /* fatal_error_signal will die with the right signal.  */
           !handling_fatal_signal)
-        die (MAKE_FAILURE);
+        die (child_failed);
 
       /* Only block for one child.  */
       block = 0;
@@ -1188,14 +1195,15 @@
       ++p;
     }
 
+  child->recursive = ((flags & COMMANDS_RECURSE) != 0);
+
   /* Update the file's command flags with any new ones we found.  We only
      keep the COMMANDS_RECURSE setting.  Even this isn't 100% correct; we are
      now marking more commands recursive than should be in the case of
      multiline define/endef scripts where only one line is marked "+".  In
      order to really fix this, we'll have to keep a lines_flags for every
      actual line, after expansion.  */
-  child->file->cmds->lines_flags[child->command_line - 1]
-    |= flags & COMMANDS_RECURSE;
+  child->file->cmds->lines_flags[child->command_line - 1] |= flags & COMMANDS_RECURSE;
 
   /* POSIX requires that a recipe prefix after a backslash-newline should
      be ignored.  Remove it now so the output is correct.  */
diff --git a/job.h b/job.h
index 0243cdd..0beff73 100644
--- a/job.h
+++ b/job.h
@@ -109,6 +109,7 @@
     unsigned int  noerror:1;    /* Nonzero if commands contained a '-'.  */
     unsigned int  good_stdin:1; /* Nonzero if this child has a good stdin.  */
     unsigned int  deleted:1;    /* Nonzero if targets have been deleted.  */
+    unsigned int  recursive:1;  /* Nonzero for recursive command ('+' etc.)  */
     unsigned int  dontcare:1;   /* Saved dontcare flag.  */
   };
 
diff --git a/tests/scripts/options/dash-q b/tests/scripts/options/dash-q
index 194588d..e67b55d 100644
--- a/tests/scripts/options/dash-q
+++ b/tests/scripts/options/dash-q
@@ -74,4 +74,13 @@
 ',
               '-q build-y', "#MAKE#: *** No rule to make target 'build-stamp-2', needed by 'build-arch'.  Stop.\n", 512);
 
+# TEST 9 : Savannah bug # 47151
+# Make sure we exit with 1 when invoking a recursive make
+run_make_test('
+foo: bar ; echo foo
+bar: ; @$(MAKE) -f #MAKEFILE# baz
+baz: ; echo baz
+',
+              '-q foo', '', 256);
+
 1;