/* 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