source: filterproc.c @ 06e04a9

release-1.10release-1.9
Last change on this file since 06e04a9 was 97cdbaf5, checked in by David Benjamin <davidben@mit.edu>, 13 years ago
Rewrite call_filter to use g_spawn_async_with_pipes This simplifies the error-handling code. Also fixes a bug where file descriptors get double-closed in call_filter. Also adds a unit test. The separate prog argument is removed to avoid having to deal with G_SPAWN_FILE_AND_ARGV_ZERO, and since we don't really use it anyway.
  • Property mode set to 100644
File size: 2.1 KB
Line 
1#include "owl.h"
2#include <sys/wait.h>
3#include <poll.h>
4
5/* Even in case of error, send_receive is responsible for closing wfd
6 * (to EOF the child) and rfd (for consistency). */
7static int send_receive(int rfd, int wfd, const char *out, char **in)
8{
9  GString *str = g_string_new("");
10  char buf[1024];
11  nfds_t nfds;
12  int err = 0;
13  struct pollfd fds[2];
14
15  fcntl(rfd, F_SETFL, O_NONBLOCK | fcntl(rfd, F_GETFL));
16  fcntl(wfd, F_SETFL, O_NONBLOCK | fcntl(wfd, F_GETFL));
17
18  fds[0].fd = rfd;
19  fds[0].events = POLLIN;
20  fds[1].fd = wfd;
21  fds[1].events = POLLOUT;
22
23  if(!out || !*out) {
24    /* Nothing to write. Close our end so the child doesn't hang waiting. */
25    close(wfd); wfd = -1;
26    out = NULL;
27  }
28
29  while(1) {
30    if(out && *out) {
31      nfds = 2;
32    } else {
33      nfds = 1;
34    }
35    err = poll(fds, nfds, -1);
36    if(err < 0) {
37      break;
38    }
39    if(out && *out) {
40      if(fds[1].revents & POLLOUT) {
41        err = write(wfd, out, strlen(out));
42        if(err > 0) {
43          out += err;
44        }
45        if(err < 0) {
46          out = NULL;
47        }
48      }
49      if(!out || !*out || fds[1].revents & (POLLERR | POLLHUP)) {
50        close(wfd); wfd = -1;
51        out = NULL;
52      }
53    }
54    if(fds[0].revents & POLLIN) {
55      err = read(rfd, buf, sizeof(buf));
56      if(err <= 0) {
57        break;
58      }
59      g_string_append_len(str, buf, err);
60    } else if(fds[0].revents & (POLLHUP | POLLERR)) {
61      err = 0;
62      break;
63    }
64  }
65
66  if (wfd >= 0) close(wfd);
67  close(rfd);
68  *in = g_string_free(str, err < 0);
69  return err;
70}
71
72int call_filter(const char *const *argv, const char *in, char **out, int *status)
73{
74  int err;
75  GPid child_pid;
76  int child_stdin, child_stdout;
77
78  if (!g_spawn_async_with_pipes(NULL, (char**)argv, NULL,
79                                G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
80                                NULL, NULL,
81                                &child_pid, &child_stdin, &child_stdout, NULL,
82                                NULL)) {
83    return 1;
84  }
85
86  err = send_receive(child_stdout, child_stdin, in, out);
87  if (err == 0) {
88    waitpid(child_pid, status, 0);
89  }
90  return err;
91}
Note: See TracBrowser for help on using the repository browser.