#include "owl.h" #include #include /* Even in case of error, send_receive is responsible for closing wfd * (to EOF the child) and rfd (for consistency). */ static int send_receive(int rfd, int wfd, const char *out, char **in) { GString *str = g_string_new(""); char buf[1024]; nfds_t nfds; int err = 0; struct pollfd fds[2]; fcntl(rfd, F_SETFL, O_NONBLOCK | fcntl(rfd, F_GETFL)); fcntl(wfd, F_SETFL, O_NONBLOCK | fcntl(wfd, F_GETFL)); fds[0].fd = rfd; fds[0].events = POLLIN; fds[1].fd = wfd; fds[1].events = POLLOUT; if(!out || !*out) { /* Nothing to write. Close our end so the child doesn't hang waiting. */ close(wfd); wfd = -1; out = NULL; } while(1) { if(out && *out) { nfds = 2; } else { nfds = 1; } err = poll(fds, nfds, -1); if(err < 0) { break; } if(out && *out) { if(fds[1].revents & POLLOUT) { err = write(wfd, out, strlen(out)); if(err > 0) { out += err; } if(err < 0) { out = NULL; } } if(!out || !*out || fds[1].revents & (POLLERR | POLLHUP)) { close(wfd); wfd = -1; out = NULL; } } if(fds[0].revents & POLLIN) { err = read(rfd, buf, sizeof(buf)); if(err <= 0) { break; } g_string_append_len(str, buf, err); } else if(fds[0].revents & (POLLHUP | POLLERR)) { err = 0; break; } } if (wfd >= 0) close(wfd); close(rfd); *in = g_string_free(str, err < 0); return err; } int call_filter(const char *const *argv, const char *in, char **out, int *status) { int err; GPid child_pid; int child_stdin, child_stdout; if (!g_spawn_async_with_pipes(NULL, (char**)argv, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &child_pid, &child_stdin, &child_stdout, NULL, NULL)) { return 1; } err = send_receive(child_stdout, child_stdin, in, out); if (err == 0) { waitpid(child_pid, status, 0); } return err; }