diff options
Diffstat (limited to '')
-rw-r--r-- | libexec_pipe_commandsvn.c | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/libexec_pipe_commandsvn.c b/libexec_pipe_commandsvn.c new file mode 100644 index 0000000..d6aa1d5 --- /dev/null +++ b/libexec_pipe_commandsvn.c @@ -0,0 +1,106 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + + +static void +remove_last_pluming(struct libexec_command *cmd) +{ + if (!cmd->nplumings || !cmd->plumings) + abort(); + if (cmd->plumings[--cmd->nplumings].type != LIBEXEC_PLUMING_PIPE) + abort(); + close(cmd->plumings[cmd->nplumings].target.fd); + if (!cmd->nplumings) { + free(cmd->plumings); + cmd->plumings = NULL; + } +} + + +static int +pipe_two_commands(enum libexec_pipe how, struct libexec_command *left, struct libexec_command *right) +{ + int fds[2], r; + struct libexec_pluming tmp; + + if (!left || !right) { + einval: + errno = EINVAL; + return -1; + } + + if (how == LIBEXEC_PIPE) + r = pipe(fds); + else if (how == LIBEXEC_SOCK_STREAM) + r = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); + else if (how == LIBEXEC_SOCK_SEQPACKET) + r = socketpair(PF_UNIX, SOCK_SEQPACKET, 0, fds); + else if (how == LIBEXEC_SOCK_DGRAM) + r = socketpair(PF_UNIX, SOCK_DGRAM, 0, fds); + else if (how == LIBEXEC_DIRECT_PIPE) + r = pipe2(fds, O_DIRECT); + else + goto einval; + if (r) + return -1; + + if (libexec_dup(left, STDOUT_FILENO, fds[1])) { + close(fds[0]); + close(fds[1]); + return -1; + } + left->plumings[left->nplumings - 1].type = LIBEXEC_PLUMING_PIPE; + + if (libexec_dup(right, STDIN_FILENO, fds[0])) { + remove_last_pluming(left); + close(fds[0]); + return -1; + } + right->plumings[right->nplumings - 1].type = LIBEXEC_PLUMING_PIPE; + + /* pluming shall be at the front */ + tmp = left->plumings[left->nplumings - 1]; + memcpy(&left->plumings[1], &left->plumings[0], (left->nplumings - 1) * sizeof(*left->plumings)); + left->plumings[0] = tmp; + tmp = right->plumings[right->nplumings - 1]; + memcpy(&right->plumings[1], &right->plumings[0], (right->nplumings - 1) * sizeof(*right->plumings)); + right->plumings[0] = tmp; + + return 0; +} + + +int +libexec_pipe_commandsvn(enum libexec_pipe how, struct libexec_command *const *cmds, size_t n) +{ + enum libexec_pipe circular; + size_t i; + + circular = how; + circular &= LIBEXEC_PIPE_CIRCULARLY; + how ^= circular; + + for (i = 1; i < n; i++) + if (pipe_two_commands(how, cmds[i - 1], cmds[i])) + goto fail; + + if (circular && n) + if (pipe_two_commands(how, cmds[n - 1], cmds[0])) + goto fail; + + return 0; + +fail: + i -= 1; + while (i) { + remove_last_pluming(cmds[i--]); + remove_last_pluming(cmds[i]); + } + return -1; +} + + +#else +LIBEXEC_CONST__ int main(void) {return 0;} /* TODO test */ +#endif |