Previously run-command was unable to report errors happening in exec call. Change it to pass errno from failed exec to errno value at return. The errno value passing can be done by opening close-on-exec pipe and piping the error code through in case of failure. In case of success, close-on-exec closes the pipe on successful exec and parent process gets end of file on read. Signed-off-by: Ilari Liusvaara <ilari.liusvaara@xxxxxxxxxxx> --- run-command.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 69 insertions(+), 3 deletions(-) diff --git a/run-command.c b/run-command.c index cf2d8f7..d334d0f 100644 --- a/run-command.c +++ b/run-command.c @@ -76,9 +76,60 @@ fail_pipe: trace_argv_printf(cmd->argv, "trace: run_command:"); #ifndef WIN32 +{ + int report_pipe[2] = {-1, -1}; + + if (pipe(report_pipe) < 0) + warning("Can't open pipe for exec status report: %s\n", + strerror(errno)); + fflush(NULL); cmd->pid = fork(); - if (!cmd->pid) { + if (cmd->pid > 0) { + int r = 0, ret; + while(close(report_pipe[1]) < 0 && errno != EBADF); +read_again: + if (report_pipe[0] > 0) + r = read(report_pipe[0], &ret, sizeof(ret)); + if (r < 0 && (errno == EAGAIN || errno == EINTR || + errno == EWOULDBLOCK)) + goto read_again; + else if (r < 0) + warning("Can't read exec status report: %s\n", + strerror(errno)); + else if (r == 0) + ; + else if (r < sizeof(ret)) + warning("Received incomplete exec status report.\n"); + else { + failed_errno = ret; + /* + * Clean up the process that did the failed execution + * so no zombies remain. + */ +wait_again: + r = waitpid(cmd->pid, &ret, 0); + if (r < 0 && errno != ECHILD) + goto wait_again; + cmd->pid = -1; + } + } else if (!cmd->pid) { + int r = 0; + int flags; + while(close(report_pipe[0]) < 0 && errno != EBADF); + + flags = fcntl(report_pipe[1], F_GETFD); + if (flags < 0) + r = -1; + flags |= FD_CLOEXEC; + r = (r || fcntl(report_pipe[1], F_SETFD, flags)); + if (r) { + warning("Can't FD_CLOEXEC pipe for exec status " + "report: %s\n", strerror(errno)); + while(close(report_pipe[1]) < 0 && errno != EBADF); + report_pipe[1] = -1; + } + if (cmd->no_stdin) dup_devnull(0); else if (need_in) { @@ -126,13 +177,28 @@ fail_pipe: } else { execvp(cmd->argv[0], (char *const*) cmd->argv); } + failed_errno = errno; + trace_printf("trace: exec '%s' failed: %s\n", cmd->argv[0], strerror(errno)); + + r = 0; +write_again: + if (report_pipe[1] >= 0) + r = write(report_pipe[1], &failed_errno, + sizeof(failed_errno)); + if (r < 0 && (errno == EAGAIN || errno == EINTR || + errno == EWOULDBLOCK)) + goto write_again; + else if (r < 0) + warning("Can't write exec status report: %s\n", + strerror(errno)); + exit(127); - } - if (cmd->pid < 0) + } else if (cmd->pid < 0) error("cannot fork() for %s: %s", cmd->argv[0], strerror(failed_errno = errno)); +} #else { int s0 = -1, s1 = -1, s2 = -1; /* backups of stdin, stdout, stderr */ -- 1.6.6.3.gaa2e1 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html