aboutsummaryrefslogtreecommitdiff
path: root/filter.c
diff options
context:
space:
mode:
authorChristian Neukirchen <chneukirchen@gmail.com>2016-07-29 15:15:57 +0200
committerChristian Neukirchen <chneukirchen@gmail.com>2016-07-29 15:15:57 +0200
commitbe2ca1ba42029b80cffff78afee77abf9831131a (patch)
treebaa0e210bac2a1fbc863bf8ee2c45b70eb0e6c93 /filter.c
parent5d1266b38f35916d3ce48cc07052c459c802a7d3 (diff)
downloadmblaze-be2ca1ba42029b80cffff78afee77abf9831131a.tar.gz
mshow: actually filter the parts
Diffstat (limited to 'filter.c')
-rw-r--r--filter.c124
1 files changed, 124 insertions, 0 deletions
diff --git a/filter.c b/filter.c
new file mode 100644
index 0000000..3996dfd
--- /dev/null
+++ b/filter.c
@@ -0,0 +1,124 @@
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+int
+filter(char *input, size_t inlen, char *cmd, char **outputo, size_t *outleno)
+{
+ char *output;
+ size_t outlen;
+ ssize_t outalloc = 4096;
+ pid_t pid;
+
+ output = malloc(outalloc);
+ outlen = 0;
+
+ int pipe0[2];
+ int pipe1[2];
+
+ if (pipe(pipe0) != 0 || pipe(pipe1) != 0)
+ goto fail;
+
+ char *argv[] = { "/bin/sh", "-c", cmd, (char *)0 };
+
+ if (!(pid = fork())) {
+ dup2(pipe0[0], 0);
+ close(pipe0[1]);
+ close(pipe0[0]);
+
+ dup2(pipe1[1], 1);
+ close(pipe1[0]);
+ close(pipe1[1]);
+
+ execvp(argv[0], argv);
+ exit(-1);
+ }
+ close(pipe0[0]);
+ close(pipe1[1]);
+
+ if (pid < 0) {
+ close(pipe0[1]);
+ close(pipe1[0]);
+ goto fail;
+ }
+
+ struct pollfd fds[2];
+
+ fds[0].fd = pipe1[0];
+ fds[0].events = POLLIN;
+ fds[1].fd = pipe0[1];
+ fds[1].events = POLLOUT;
+
+ while ((fds[0].fd >= 0 || fds[1].fd >= 0) &&
+ poll(fds, sizeof fds / sizeof fds[0], -1) >= 0) {
+ if (fds[0].revents & POLLIN) {
+ if (outlen + 512 > outalloc) {
+ outalloc *= 2;
+ if (outalloc < 0)
+ exit(-1);
+ output = realloc(output, outalloc);
+ if (!output)
+ exit(-1);
+ }
+ ssize_t ret = read(fds[0].fd, output + outlen, 512);
+ if (ret > 0)
+ outlen += ret;
+ else if (ret < 0)
+ close(fds[0].fd);
+ } else if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
+ fds[0].fd = -1;
+ }
+
+ if (fds[1].revents & POLLOUT) {
+ ssize_t ret = write(fds[1].fd, input, inlen);
+ if (ret > 0) {
+ input += ret;
+ inlen -= ret;
+ }
+ if (ret <= 0 || inlen == 0)
+ close(fds[1].fd);
+ } else if (fds[1].revents & (POLLERR | POLLHUP | POLLNVAL)) {
+ fds[1].fd = -1;
+ }
+ }
+
+ // ok to fail when closed already
+ close(pipe0[1]);
+ close(pipe1[0]);
+
+ int status;
+ waitpid(pid, &status, 0);
+
+ *outputo = output;
+ *outleno = outlen;
+
+ return WEXITSTATUS(status);
+
+fail:
+ *outputo = 0;
+ *outleno = 0;
+
+ return -1;
+}
+
+#ifdef TEST
+int
+main()
+{
+ char *input = "foo\nbar\nbaz";
+ int e;
+
+ char *output;
+ size_t outlen;
+
+ e = filter(input, strlen(input), "rev;exit 2", &output, &outlen);
+
+ fwrite(output, 1, outlen, stdout);
+ printf("%ld -> %d\n", outlen, e);
+
+ return 0;
+}
+#endif