]> git.ipfire.org Git - thirdparty/make.git/commitdiff
Show useful errors when posix_spawn() doesn't do so
authorPaul Smith <psmith@gnu.org>
Tue, 3 Sep 2019 20:17:50 +0000 (16:17 -0400)
committerPaul Smith <psmith@gnu.org>
Sat, 7 Sep 2019 22:27:26 +0000 (18:27 -0400)
The posix_spawn() function may not detect that the command to run is
invalid when it's invoked.  Instead, it will run then exit with
error code 127.  If that happens do our best to present the user
with a useful error message.

* src/job.h (struct child): Add cmd_name to hold the command we ran.
* src/job.c (start_job_command): On success, remember the cmd_name.
(reap_children): On exit 127, stat cmd_name and show a useful error.
(free_child): Free cmd_name.

src/job.c
src/job.h

index 34a6e66657e5516b336c444da8a3cbbdcb94da87..f519649363568564dfa977e4bf0cce816f592037 100644 (file)
--- a/src/job.c
+++ b/src/job.c
@@ -907,6 +907,36 @@ reap_children (int block, int err)
         --job_counter;
 
     process_child:
+
+#if defined(USE_POSIX_SPAWN)
+      /* Some versions of posix_spawn() do not detect errors such as command
+         not found until after they fork.  In that case they will exit with a
+         code of 127.  Try to detect that and provide a useful error message.
+         Otherwise we'll just show the error below, as normal.  */
+      if (exit_sig == 0 && exit_code == 127 && c->cmd_name)
+        {
+          const char *e = NULL;
+          struct stat st;
+          int r;
+
+          /* There are various ways that this will show a different error than
+             fork/exec.  To really get the right error we'd have to fall back
+             to fork/exec but I don't want to bother with that.  Just do the
+             best we can.  */
+
+          EINTRLOOP(r, stat(c->cmd_name, &st));
+          if (r < 0)
+            e = strerror (errno);
+          else if (S_ISDIR(st.st_mode) || !(st.st_mode & S_IXUSR))
+            e = strerror (EACCES);
+          else if (st.st_size == 0)
+            e = strerror (ENOEXEC);
+
+          if (e)
+            OSS(error, NILF, "%s: %s", c->cmd_name, e);
+        }
+#endif
+
       /* 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)
@@ -1115,6 +1145,7 @@ free_child (struct child *child)
       free (child->environment);
     }
 
+  free (child->cmd_name);
   free (child);
 }
 \f
@@ -1436,6 +1467,9 @@ start_job_command (struct child *child)
 
       environ = parent_environ; /* Restore value child may have clobbered.  */
       jobserver_post_child (flags & COMMANDS_RECURSE);
+
+      free (child->cmd_name);
+      child->cmd_name = child->pid > 0 ? xstrdup(argv[0]) : NULL;
 #endif /* !VMS */
     }
 
index 54659430239a5034230b845100632c2672a4dd18..339d723268269a98a1feca13662959acc7f0de09 100644 (file)
--- a/src/job.h
+++ b/src/job.h
@@ -29,6 +29,7 @@ struct child
     char *sh_batch_file;        /* Script file for shell commands */
     char **command_lines;       /* Array of variable-expanded cmd lines.  */
     char *command_ptr;          /* Ptr into command_lines[command_line].  */
+    char *cmd_name;             /* Alloced copy of argv[0] that was run.  */
 
     struct output output;       /* Output for this child.  */