diff --git a/run-command.c b/run-command.c
index 7e779d33ee9ea5f7d2e6aedc8c3a0a0476e87135..44100a749b09439121073e32e7a3143b54185d31 100644 (file)
--- a/run-command.c
+++ b/run-command.c
int start_command(struct child_process *cmd)
{
int start_command(struct child_process *cmd)
{
- int need_in, need_out;
- int fdin[2], fdout[2];
+ int need_in, need_out, need_err;
+ int fdin[2], fdout[2], fderr[2];
+
+ /*
+ * In case of errors we must keep the promise to close FDs
+ * that have been passed in via ->in and ->out.
+ */
need_in = !cmd->no_stdin && cmd->in < 0;
if (need_in) {
need_in = !cmd->no_stdin && cmd->in < 0;
if (need_in) {
- if (pipe(fdin) < 0)
+ if (pipe(fdin) < 0) {
+ if (cmd->out > 0)
+ close(cmd->out);
return -ERR_RUN_COMMAND_PIPE;
return -ERR_RUN_COMMAND_PIPE;
+ }
cmd->in = fdin[1];
cmd->in = fdin[1];
- cmd->close_in = 1;
}
need_out = !cmd->no_stdout
}
need_out = !cmd->no_stdout
if (pipe(fdout) < 0) {
if (need_in)
close_pair(fdin);
if (pipe(fdout) < 0) {
if (need_in)
close_pair(fdin);
+ else if (cmd->in)
+ close(cmd->in);
return -ERR_RUN_COMMAND_PIPE;
}
cmd->out = fdout[0];
return -ERR_RUN_COMMAND_PIPE;
}
cmd->out = fdout[0];
- cmd->close_out = 1;
+ }
+
+ need_err = !cmd->no_stderr && cmd->err < 0;
+ if (need_err) {
+ if (pipe(fderr) < 0) {
+ if (need_in)
+ close_pair(fdin);
+ else if (cmd->in)
+ close(cmd->in);
+ if (need_out)
+ close_pair(fdout);
+ else if (cmd->out)
+ close(cmd->out);
+ return -ERR_RUN_COMMAND_PIPE;
+ }
+ cmd->err = fderr[0];
}
cmd->pid = fork();
if (cmd->pid < 0) {
if (need_in)
close_pair(fdin);
}
cmd->pid = fork();
if (cmd->pid < 0) {
if (need_in)
close_pair(fdin);
+ else if (cmd->in)
+ close(cmd->in);
if (need_out)
close_pair(fdout);
if (need_out)
close_pair(fdout);
+ else if (cmd->out)
+ close(cmd->out);
+ if (need_err)
+ close_pair(fderr);
return -ERR_RUN_COMMAND_FORK;
}
return -ERR_RUN_COMMAND_FORK;
}
close(cmd->in);
}
close(cmd->in);
}
+ if (cmd->no_stderr)
+ dup_devnull(2);
+ else if (need_err) {
+ dup2(fderr[1], 2);
+ close_pair(fderr);
+ }
+
if (cmd->no_stdout)
dup_devnull(1);
else if (cmd->stdout_to_stderr)
if (cmd->no_stdout)
dup_devnull(1);
else if (cmd->stdout_to_stderr)
if (need_out)
close(fdout[1]);
if (need_out)
close(fdout[1]);
- else if (cmd->out > 1)
+ else if (cmd->out)
close(cmd->out);
close(cmd->out);
+ if (need_err)
+ close(fderr[1]);
+
return 0;
}
return 0;
}
-int finish_command(struct child_process *cmd)
+static int wait_or_whine(pid_t pid)
{
{
- if (cmd->close_in)
- close(cmd->in);
- if (cmd->close_out)
- close(cmd->out);
-
for (;;) {
int status, code;
for (;;) {
int status, code;
- pid_t waiting = waitpid(cmd->pid, &status, 0);
+ pid_t waiting = waitpid(pid, &status, 0);
if (waiting < 0) {
if (errno == EINTR)
if (waiting < 0) {
if (errno == EINTR)
error("waitpid failed (%s)", strerror(errno));
return -ERR_RUN_COMMAND_WAITPID;
}
error("waitpid failed (%s)", strerror(errno));
return -ERR_RUN_COMMAND_WAITPID;
}
- if (waiting != cmd->pid)
+ if (waiting != pid)
return -ERR_RUN_COMMAND_WAITPID_WRONG_PID;
if (WIFSIGNALED(status))
return -ERR_RUN_COMMAND_WAITPID_SIGNAL;
return -ERR_RUN_COMMAND_WAITPID_WRONG_PID;
if (WIFSIGNALED(status))
return -ERR_RUN_COMMAND_WAITPID_SIGNAL;
}
}
}
}
+int finish_command(struct child_process *cmd)
+{
+ return wait_or_whine(cmd->pid);
+}
+
int run_command(struct child_process *cmd)
{
int code = start_command(cmd);
int run_command(struct child_process *cmd)
{
int code = start_command(cmd);
@@ -178,3 +218,34 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const
cmd.env = env;
return run_command(&cmd);
}
cmd.env = env;
return run_command(&cmd);
}
+
+int start_async(struct async *async)
+{
+ int pipe_out[2];
+
+ if (pipe(pipe_out) < 0)
+ return error("cannot create pipe: %s", strerror(errno));
+
+ async->pid = fork();
+ if (async->pid < 0) {
+ error("fork (async) failed: %s", strerror(errno));
+ close_pair(pipe_out);
+ return -1;
+ }
+ if (!async->pid) {
+ close(pipe_out[0]);
+ exit(!!async->proc(pipe_out[1], async->data));
+ }
+ async->out = pipe_out[0];
+ close(pipe_out[1]);
+ return 0;
+}
+
+int finish_async(struct async *async)
+{
+ int ret = 0;
+
+ if (wait_or_whine(async->pid))
+ ret = error("waitpid (async) failed");
+ return ret;
+}