aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
authorEgor Tensin <Egor.Tensin@gmail.com>2022-08-26 05:07:32 +0200
committerEgor Tensin <Egor.Tensin@gmail.com>2022-08-26 05:07:32 +0200
commita593789a46ceb27d26186db7b3215b2a046ff865 (patch)
tree978ac4dbf25e1b9fb7da8299d1abb9514017420a /src
parentadd some more code (diff)
downloadcimple-a593789a46ceb27d26186db7b3215b2a046ff865.tar.gz
cimple-a593789a46ceb27d26186db7b3215b2a046ff865.zip
worker: capture process output
Diffstat (limited to 'src')
-rw-r--r--src/ci.c30
-rw-r--r--src/ci.h11
-rw-r--r--src/file.c38
-rw-r--r--src/file.h4
-rw-r--r--src/process.c84
-rw-r--r--src/process.h15
-rw-r--r--src/worker.c18
7 files changed, 163 insertions, 37 deletions
diff --git a/src/ci.c b/src/ci.c
index 1932008..ffc298a 100644
--- a/src/ci.c
+++ b/src/ci.c
@@ -18,30 +18,23 @@ static const char *ci_scripts[] = {
};
/* clang-format on */
-static run_result ci_run_script(const char *script, int *ec)
+static int ci_run_script(const char *script, struct proc_output *result)
{
const char *args[] = {script, NULL};
- int ret = 0;
-
- ret = proc_spawn(args, ec);
- if (ret < 0)
- return RUN_ERROR;
- if (*ec)
- return RUN_FAILURE;
- return RUN_SUCCESS;
+ return proc_capture(args, result);
}
-run_result ci_run(int *ec)
+int ci_run(struct proc_output *result)
{
for (const char **script = ci_scripts; *script; ++script) {
if (!file_exists(*script))
continue;
print_log("Going to run: %s\n", *script);
- return ci_run_script(*script, ec);
+ return ci_run_script(*script, result);
}
print_log("Couldn't find any CI scripts to run\n");
- return RUN_NO;
+ return -1;
}
static void ci_cleanup_git_repo(git_repository *repo)
@@ -60,21 +53,20 @@ static int ci_prepare_git_repo(git_repository **repo, const char *url, const cha
ret = libgit_checkout(*repo, rev);
if (ret < 0)
- goto free_repo;
+ goto cleanup_repo;
return ret;
-free_repo:
+cleanup_repo:
ci_cleanup_git_repo(*repo);
return ret;
}
-run_result ci_run_git_repo(const char *url, const char *rev, int *ec)
+int ci_run_git_repo(const char *url, const char *rev, struct proc_output *output)
{
char *oldpwd;
git_repository *repo;
- run_result result = RUN_ERROR;
int ret = 0;
ret = ci_prepare_git_repo(&repo, url, rev);
@@ -85,8 +77,8 @@ run_result ci_run_git_repo(const char *url, const char *rev, int *ec)
if (ret < 0)
goto free_repo;
- result = ci_run(ec);
- if (result < 0)
+ ret = ci_run(output);
+ if (ret < 0)
goto oldpwd;
oldpwd:
@@ -97,5 +89,5 @@ free_repo:
ci_cleanup_git_repo(repo);
exit:
- return result;
+ return ret;
}
diff --git a/src/ci.h b/src/ci.h
index 4267b89..f890796 100644
--- a/src/ci.h
+++ b/src/ci.h
@@ -1,14 +1,9 @@
#ifndef __CI_H__
#define __CI_H__
-typedef enum {
- RUN_ERROR = -1,
- RUN_SUCCESS,
- RUN_FAILURE,
- RUN_NO,
-} run_result;
+#include "process.h"
-run_result ci_run(int *ec);
+int ci_run(struct proc_output *);
/*
* This is a high-level function. It's basically equivalent to the following
@@ -23,6 +18,6 @@ run_result ci_run(int *ec);
* rm -rf "$dir"
*
*/
-run_result ci_run_git_repo(const char *url, const char *rev, int *ec);
+int ci_run_git_repo(const char *url, const char *rev, struct proc_output *);
#endif
diff --git a/src/file.c b/src/file.c
index ede640b..0273e71 100644
--- a/src/file.c
+++ b/src/file.c
@@ -59,3 +59,41 @@ int file_exists(const char *path)
int ret = lstat(path, &stat);
return !ret && S_ISREG(stat.st_mode);
}
+
+int file_read(int fd, char **output, size_t *len)
+{
+ char buf[128];
+ size_t buf_len = sizeof(buf) / sizeof(buf[0]);
+ int ret = 0;
+
+ *output = NULL;
+ *len = 0;
+
+ while (1) {
+ ssize_t read_now = read(fd, buf, buf_len);
+
+ if (read_now < 0) {
+ print_errno("read");
+ ret = read_now;
+ goto free_output;
+ }
+
+ if (!read_now)
+ goto exit;
+
+ *output = realloc(*output, *len + read_now + 1);
+ if (!*output) {
+ print_errno("realloc");
+ return -1;
+ }
+ memcpy(*output + *len, buf, read_now);
+ *len += read_now;
+ *(*output + *len) = '\0';
+ }
+
+free_output:
+ free(*output);
+
+exit:
+ return ret;
+}
diff --git a/src/file.h b/src/file.h
index b89fca1..03d5e9a 100644
--- a/src/file.h
+++ b/src/file.h
@@ -1,10 +1,14 @@
#ifndef __FILE_H__
#define __FILE_H__
+#include <stddef.h>
+
int rm_rf(const char *dir);
int my_chdir(const char *dir, char **old);
int file_exists(const char *path);
+int file_read(int fd, char **output, size_t *len);
+
#endif
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;
}
diff --git a/src/process.h b/src/process.h
index da0c421..455d4ec 100644
--- a/src/process.h
+++ b/src/process.h
@@ -1,6 +1,21 @@
#ifndef __PROCESS_H__
#define __PROCESS_H__
+#include <stddef.h>
+
+struct proc_output {
+ int ec;
+ char *output;
+ size_t output_len;
+};
+
+/* The exit code is only valid if the functions returns a non-negative number. */
int proc_spawn(const char *args[], int *ec);
+/* Similarly, the contents of the proc_output structure is only valid if the function returns a
+ * non-negative number.
+ *
+ * In that case, you'll need to free the output. */
+int proc_capture(const char *args[], struct proc_output *result);
+
#endif
diff --git a/src/worker.c b/src/worker.c
index 687e647..0dc64d3 100644
--- a/src/worker.c
+++ b/src/worker.c
@@ -4,6 +4,7 @@
#include "log.h"
#include "msg.h"
#include "net.h"
+#include "process.h"
#include <errno.h>
#include <pthread.h>
@@ -82,9 +83,22 @@ static int msg_body_ci_run(const struct msg *msg)
{
const char *url = msg->argv[1];
const char *rev = msg->argv[2];
- int ec = 0;
+ struct proc_output result;
+ int ret = 0;
- return ci_run_git_repo(url, rev, &ec);
+ ret = ci_run_git_repo(url, rev, &result);
+ if (ret < 0) {
+ print_error("Run failed with an error\n");
+ return ret;
+ }
+
+ print_log("Process exit code: %d\n", result.ec);
+ print_log("Process output:\n%s", result.output);
+ if (!result.output || !result.output_len || result.output[result.output_len - 1] != '\n')
+ print_log("\n");
+ free(result.output);
+
+ return ret;
}
typedef worker_task_body (*worker_msg_parser)(const struct msg *);