/* 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; *CMD = LIBEXEC_COMMAND_INIT; 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