aboutsummaryrefslogtreecommitdiffstats
path: root/libexec_vrun.c
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2024-05-05 10:24:40 +0200
committerMattias Andrée <maandree@kth.se>2024-05-05 10:24:40 +0200
commit3dfd6c11ed5599ab8baf4a6114f4ccb34150de6e (patch)
treeb7717583b99f29028c85c3423cf43b104dfa8943 /libexec_vrun.c
downloadlibexec-3dfd6c11ed5599ab8baf4a6114f4ccb34150de6e.tar.gz
libexec-3dfd6c11ed5599ab8baf4a6114f4ccb34150de6e.tar.bz2
libexec-3dfd6c11ed5599ab8baf4a6114f4ccb34150de6e.tar.xz
First commit
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to 'libexec_vrun.c')
-rw-r--r--libexec_vrun.c307
1 files changed, 307 insertions, 0 deletions
diff --git a/libexec_vrun.c b/libexec_vrun.c
new file mode 100644
index 0000000..99822c2
--- /dev/null
+++ b/libexec_vrun.c
@@ -0,0 +1,307 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+
+int
+libexec_vrun(struct libexec_result *out, va_list args)
+{
+#define CMD (cmds[ncmds - 1])
+
+ struct libexec_document *doc, **docs = NULL;
+ struct libexec_command **cmds = NULL;
+ size_t ncmds = 0, ndocs = 0, i;
+ const char *fmt, *arg_str1, *arg_str2;
+ char *arg_str_nc;
+ int arg_int1, arg_int2, arg_int3, fd, *exit_statuses = NULL;
+ enum libexec_insert_mode insert_mode;
+ void *new, *arg_voidp1;
+ enum libexec_pipe pipe_how = 0;
+ struct epoll_event ev;
+ int alien_epoll = -1;
+ const sigset_t *sigmask;
+ int (*on_alien_epoll)(int alien_epoll, uint32_t events, void *user);
+ int (*on_alien_child_death)(pid_t pid, void *user);
+ int (*after_fork)(struct libexec_command *cmd, int new_fd, void *user);
+ int (*reap_mutex_control)(int action, void *user);
+ int (*on_interrupt)(void *user);
+ void *on_alien_epoll_user = NULL;
+ void *on_alien_child_death_user = NULL;
+ void *after_fork_user = NULL;
+ void *reap_mutex_control_user = NULL;
+ void *on_interrupt_user = NULL;
+ int ret = -1;
+
+ if (!out) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ memset(&ev, 0, sizeof(ev));
+ memset(out, 0, sizeof(*out));
+ out->exit_statuses = NULL;
+
+new_command:
+ new = realloc(cmds, (ncmds + 1) * sizeof(*cmds));
+ if (!new)
+ goto fail;
+ cmds = new;
+ ncmds += 1;
+ CMD = malloc(sizeof(CMD));
+ if (!CMD)
+ goto fail;
+ libexec_init_command(CMD);
+ fmt = va_arg(args, const char *);
+ if (libexec_vconstruct_command(CMD, fmt, args))
+ goto fail;
+
+ for (;;) {
+ switch (va_arg(args, enum libexec_run_instruction)) {
+ case LIBEXEC_RUN_END:
+ if (ncmds > 1)
+ if (libexec_pipe_commands(pipe_how, cmds[ncmds - 2], cmds[ncmds - 1]))
+ goto fail;
+ goto constructed;
+
+ case LIBEXEC_RUN_END_CIRCULAR_PIPE:
+ if (ncmds > 1)
+ if (libexec_pipe_commands(pipe_how, cmds[ncmds - 2], cmds[ncmds - 1]))
+ goto fail;
+ pipe_how = va_arg(args, enum libexec_pipe);
+ if (libexec_pipe_commands(pipe_how, cmds[ncmds - 1], cmds[0]))
+ goto fail;
+ goto constructed;
+
+ case LIBEXEC_RUN_PIPE:
+ if (ncmds > 1)
+ if (libexec_pipe_commands(pipe_how, cmds[ncmds - 2], cmds[ncmds - 1]))
+ goto fail;
+ pipe_how = va_arg(args, enum libexec_pipe);
+ goto new_command;
+
+ case LIBEXEC_RUN_SET_EXECUTABLE:
+ if (libexec_set_executable(CMD, va_arg(args, const char *)))
+ goto fail;
+ break;
+
+ case LIBEXEC_RUN_SET_REQUIRE_PATH:
+ libexec_set_require_path(CMD, va_arg(args, int));
+ break;
+
+ case LIBEXEC_RUN_SET_EXEC_FD:
+ if (libexec_set_exec_fd(CMD, va_arg(args, int)))
+ goto fail;
+ break;
+
+ case LIBEXEC_RUN_SET_EXEC_PATH:
+ arg_int1 = va_arg(args, int);
+ arg_str1 = va_arg(args, const char *);
+ if (libexec_set_exec_path(CMD, arg_int1, arg_str1))
+ goto fail;
+ break;
+
+ case LIBEXEC_RUN_COPY_ENVIRON:
+ if (libexec_copy_environ(CMD, va_arg(args, const char *const *)))
+ goto fail;
+ break;
+
+ case LIBEXEC_RUN_SET_ENVIRON:
+ libexec_set_environ(CMD, va_arg(args, char **));
+ break;
+
+ case LIBEXEC_RUN_CLEAR_ENVIRON:
+ if (libexec_clear_environ(CMD))
+ goto fail;
+ break;
+
+ case LIBEXEC_RUN_UNSETENV:
+ if (libexec_unsetenv(CMD, va_arg(args, const char *)))
+ goto fail;
+ break;
+
+ case LIBEXEC_RUN_PUTENV:
+ insert_mode = va_arg(args, enum libexec_insert_mode);
+ arg_str1 = va_arg(args, const char *);
+ if (libexec_putenv(CMD, insert_mode, arg_str1))
+ goto fail;
+ break;
+
+ case LIBEXEC_RUN_SETENV:
+ insert_mode = va_arg(args, enum libexec_insert_mode);
+ arg_str1 = va_arg(args, const char *);
+ arg_str2 = va_arg(args, const char *);
+ if (libexec_setenv(CMD, insert_mode, arg_str1, arg_str2))
+ goto fail;
+ break;
+
+ case LIBEXEC_RUN_PUTENVF:
+ insert_mode = va_arg(args, enum libexec_insert_mode);
+ arg_str1 = va_arg(args, const char *);
+ if (libexec_vputenvf(CMD, insert_mode, arg_str1, args))
+ goto fail;
+ break;
+
+ case LIBEXEC_RUN_SETENVF:
+ insert_mode = va_arg(args, enum libexec_insert_mode);
+ arg_str1 = va_arg(args, const char *);
+ arg_str2 = va_arg(args, const char *);
+ if (libexec_vsetenvf(CMD, insert_mode, arg_str1, arg_str2, args))
+ goto fail;
+ break;
+
+ case LIBEXEC_RUN_OPEN:
+ arg_int1 = va_arg(args, int);
+ arg_str1 = va_arg(args, const char *);
+ arg_int2 = va_arg(args, int);
+ if (libexec_open(CMD, arg_int1, arg_str1, arg_int2, va_arg(args, mode_t)))
+ goto fail;
+ break;
+
+ case LIBEXEC_RUN_OPENAT:
+ arg_int1 = va_arg(args, int);
+ arg_int2 = va_arg(args, int);
+ arg_str1 = va_arg(args, const char *);
+ arg_int3 = va_arg(args, int);
+ if (libexec_openat(CMD, arg_int1, arg_int2, arg_str1, arg_int3, va_arg(args, mode_t)))
+ goto fail;
+ break;
+
+ case LIBEXEC_RUN_OPENAT2:
+ arg_int1 = va_arg(args, int);
+ arg_int2 = va_arg(args, int);
+ arg_str1 = va_arg(args, const char *);
+ arg_voidp1 = va_arg(args, void *);
+ if (libexec_openat2(CMD, arg_int1, arg_int2, arg_str1, arg_voidp1, va_arg(args, size_t)))
+ goto fail;
+ break;
+
+ case LIBEXEC_RUN_DUP:
+ arg_int1 = va_arg(args, int);
+ if (libexec_dup(CMD, arg_int1, va_arg(args, int)))
+ goto fail;
+ break;
+
+ case LIBEXEC_RUN_CLOSE:
+ if (libexec_close(CMD, va_arg(args, int)))
+ goto fail;
+ break;
+
+ case LIBEXEC_RUN_RENUMBER_FD:
+ arg_int1 = va_arg(args, int);
+ if (libexec_renumber_fd(CMD, arg_int1, va_arg(args, int)))
+ goto fail;
+ break;
+
+ case LIBEXEC_RUN_INPUT_COPY:
+ arg_int1 = va_arg(args, int);
+ arg_str1 = va_arg(args, const char *);
+ if (libexec_input_data_copy(CMD, arg_int1, arg_str1, va_arg(args, size_t)))
+ goto fail;
+ break;
+
+ case LIBEXEC_RUN_INPUT_GIFT:
+ arg_int1 = va_arg(args, int);
+ arg_str_nc = va_arg(args, char *);
+ if (libexec_input_data_gift(CMD, arg_int1, arg_str_nc, va_arg(args, size_t)))
+ goto fail;
+ break;
+
+ case LIBEXEC_RUN_ADD_OUTPUT_FD:
+ arg_int1 = va_arg(args, int);
+ fd = va_arg(args, int);
+ if (libexec_add_output_fd(CMD, arg_int1, fd))
+ goto fail;
+ if (alien_epoll >= 0) {
+ ev.events = EPOLLIN;
+ ev.data.fd = fd;
+ if (epoll_ctl(alien_epoll, EPOLL_CTL_ADD, fd, &ev))
+ goto fail;
+ }
+ break;
+
+ case LIBEXEC_RUN_ADD_OUTPUT:
+ arg_int1 = va_arg(args, int);
+ doc = va_arg(args, struct libexec_document *);
+ new = realloc(docs, (ndocs + 1) * sizeof(*docs));
+ if (!new)
+ goto fail;
+ docs = new;
+ docs[ndocs++] = doc;
+ if (libexec_add_output_document(CMD, arg_int1, doc, O_CLOEXEC | O_NONBLOCK))
+ goto fail;
+ break;
+
+ case LIBEXEC_RUN_SET_SIGMASK:
+ sigmask = va_arg(args, const sigset_t *);
+ break;
+
+ case LIBEXEC_RUN_SET_FD_CALLBACK:
+ on_alien_epoll = va_arg(args, int (*)(int, uint32_t, void *));
+ on_alien_epoll_user = va_arg(args, void *);
+ alien_epoll = epoll_create1(EPOLL_CLOEXEC);
+ if (alien_epoll < 0)
+ goto fail;
+ break;
+
+ case LIBEXEC_RUN_SET_REAPER:
+ on_alien_child_death = va_arg(args, int (*)(pid_t, void *));
+ on_alien_child_death_user = va_arg(args, void *);
+ break;
+
+ case LIBEXEC_RUN_SET_ATFORK:
+ after_fork = va_arg(args, int (*)(struct libexec_command *, int, void *));
+ after_fork_user = va_arg(args, void *);
+ break;
+
+ case LIBEXEC_RUN_SET_MUTEX:
+ reap_mutex_control = va_arg(args, int (*)(int, void *));
+ reap_mutex_control_user = va_arg(args, void *);
+ break;
+
+ case LIBEXEC_RUN_SET_INTERRUPT_CALLBACK:
+ on_interrupt = va_arg(args, int (*)(void *));
+ on_interrupt_user = va_arg(args, void *);
+ break;
+
+ default:
+ errno = EINVAL;
+ goto fail;
+ }
+ }
+
+constructed:
+ ret = libexec_run_pipeline(on_alien_epoll, alien_epoll, on_alien_epoll_user,
+ on_alien_child_death, on_alien_child_death_user,
+ after_fork, after_fork_user,
+ reap_mutex_control, reap_mutex_control_user,
+ on_interrupt, on_interrupt_user,
+ sigmask, docs, ndocs, 0, cmds, exit_statuses, ncmds);
+ if (!ret) {
+ out->exit_statuses = exit_statuses;
+ out->proc_count = ncmds;
+ for (i = 0; i < ncmds; i++)
+ if (exit_statuses[i])
+ break;
+ out->all_successful = (i == ncmds);
+ exit_statuses = NULL;
+ }
+
+fail:
+ while (ncmds--) {
+ if (cmds[ncmds]) {
+ libexec_destroy_command(cmds[ncmds]);
+ free(cmds[ncmds]);
+ }
+ }
+ free(cmds);
+ free(docs);
+ if (alien_epoll >= 0)
+ close(alien_epoll);
+ free(exit_statuses);
+ return ret;
+}
+
+
+#else
+TESTED_ELSEWHERE /* libexec_run.c */
+#endif