aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/process.c')
-rw-r--r--src/process.c84
1 files changed, 76 insertions, 8 deletions
diff --git a/src/process.c b/src/process.c
index 9d95037..7d62a88 100644
--- a/src/process.c
+++ b/src/process.c
@@ -1,10 +1,23 @@
#include "process.h"
+#include "file.h"
#include "log.h"
+#include <fcntl.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
+static int exec_child(const char *args[])
+{
+ int ret = execv(args[0], (char *const *)args);
+ if (ret < 0) {
+ print_errno("execv");
+ return ret;
+ }
+
+ return ret;
+}
+
static int wait_for_child(pid_t pid, int *ec)
{
int status;
@@ -25,22 +38,77 @@ static int wait_for_child(pid_t pid, int *ec)
int proc_spawn(const char *args[], int *ec)
{
- int ret = 0;
-
pid_t child_pid = fork();
if (child_pid < 0) {
print_errno("fork");
return child_pid;
}
- if (child_pid)
- return wait_for_child(child_pid, ec);
+ if (!child_pid)
+ exit(exec_child(args));
+
+ return wait_for_child(child_pid, ec);
+}
+
+static int redirect_and_exec_child(int pipe_fds[2], const char *args[])
+{
+ int ret = 0;
+
+ close(pipe_fds[0]);
- ret = execv(args[0], (char *const *)args);
+ ret = dup2(pipe_fds[1], STDOUT_FILENO);
if (ret < 0) {
- print_errno("execv");
- exit(ret);
+ print_errno("dup2");
+ return ret;
}
- return 0;
+ ret = dup2(pipe_fds[1], STDERR_FILENO);
+ if (ret < 0) {
+ print_errno("dup2");
+ return ret;
+ }
+
+ return exec_child(args);
+}
+
+int proc_capture(const char *args[], struct proc_output *result)
+{
+ int pipe_fds[2];
+ int ret = 0;
+
+ ret = pipe2(pipe_fds, O_CLOEXEC);
+ if (ret < 0) {
+ print_errno("pipe2");
+ return -1;
+ }
+
+ pid_t child_pid = fork();
+ if (child_pid < 0) {
+ print_errno("fork");
+ goto close_pipe;
+ }
+
+ if (!child_pid)
+ exit(redirect_and_exec_child(pipe_fds, args));
+
+ close(pipe_fds[1]);
+
+ ret = file_read(pipe_fds[0], &result->output, &result->output_len);
+ if (ret < 0)
+ goto close_pipe;
+
+ ret = wait_for_child(child_pid, &result->ec);
+ if (ret < 0)
+ goto free_output;
+
+ goto close_pipe;
+
+free_output:
+ free(result->output);
+
+close_pipe:
+ close(pipe_fds[0]);
+ close(pipe_fds[1]);
+
+ return ret;
}