Show useful errors when posix_spawn() doesn't do so

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.
This commit is contained in:
Paul Smith 2019-09-03 16:17:50 -04:00
parent 76b6e668a6
commit 005a251689
2 changed files with 35 additions and 0 deletions

View file

@ -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);
}
@ -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 */
}

View file

@ -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. */