From 3dfd6c11ed5599ab8baf4a6114f4ccb34150de6e Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sun, 5 May 2024 10:24:40 +0200 Subject: First commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- libexec_vrun.c | 307 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100644 libexec_vrun.c (limited to 'libexec_vrun.c') 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 -- cgit v1.2.3-70-g09d2