Changeset 39caad0 for filterproc.c
- Timestamp:
- Mar 15, 2016, 10:39:46 PM (9 years ago)
- Branches:
- master, release-1.10
- Children:
- 4ced41e
- Parents:
- 0f5af62 (diff), e8db357 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
filterproc.c
r7155955 re8db357 1 1 #include "filterproc.h" 2 2 #include <sys/wait.h> 3 #include < fcntl.h>3 #include <string.h> 4 4 #include <glib.h> 5 #include <poll.h>6 #include <string.h>7 #include <unistd.h>8 5 9 /* Even in case of error, send_receive is responsible for closing wfd 10 * (to EOF the child) and rfd (for consistency). */ 11 static int send_receive(int rfd, int wfd, const char *out, char **in) 6 struct filter_data { 7 const char **in; 8 const char *in_end; 9 GString *out_str; 10 GMainLoop *loop; 11 int err; 12 }; 13 14 static gboolean filter_stdin(GIOChannel *channel, GIOCondition condition, gpointer data_) 12 15 { 13 GString *str = g_string_new(""); 14 char buf[1024]; 15 nfds_t nfds; 16 int err = 0; 17 struct pollfd fds[2]; 16 struct filter_data *data = data_; 17 gboolean done = condition & (G_IO_ERR | G_IO_HUP); 18 18 19 fcntl(rfd, F_SETFL, O_NONBLOCK | fcntl(rfd, F_GETFL)); 20 fcntl(wfd, F_SETFL, O_NONBLOCK | fcntl(wfd, F_GETFL)); 21 22 fds[0].fd = rfd; 23 fds[0].events = POLLIN; 24 fds[1].fd = wfd; 25 fds[1].events = POLLOUT; 26 27 if(!out || !*out) { 28 /* Nothing to write. Close our end so the child doesn't hang waiting. */ 29 close(wfd); wfd = -1; 30 out = NULL; 19 if (condition & G_IO_OUT) { 20 gsize n; 21 GIOStatus ret = g_io_channel_write_chars(channel, *data->in, data->in_end - *data->in, &n, NULL); 22 *data->in += n; 23 if (ret == G_IO_STATUS_ERROR) 24 data->err = 1; 25 if (ret == G_IO_STATUS_ERROR || *data->in == data->in_end) 26 done = TRUE; 31 27 } 32 28 33 while(1) { 34 if(out && *out) { 35 nfds = 2; 36 } else { 37 nfds = 1; 38 } 39 err = poll(fds, nfds, -1); 40 if(err < 0) { 41 break; 42 } 43 if(out && *out) { 44 if(fds[1].revents & POLLOUT) { 45 err = write(wfd, out, strlen(out)); 46 if(err > 0) { 47 out += err; 48 } 49 if(err < 0) { 50 out = NULL; 51 } 52 } 53 if(!out || !*out || fds[1].revents & (POLLERR | POLLHUP)) { 54 close(wfd); wfd = -1; 55 out = NULL; 56 } 57 } 58 if(fds[0].revents & POLLIN) { 59 err = read(rfd, buf, sizeof(buf)); 60 if(err <= 0) { 61 break; 62 } 63 g_string_append_len(str, buf, err); 64 } else if(fds[0].revents & (POLLHUP | POLLERR)) { 65 err = 0; 66 break; 29 if (condition & G_IO_ERR) 30 data->err = 1; 31 32 if (done) 33 g_io_channel_shutdown(channel, TRUE, NULL); 34 return !done; 35 } 36 37 static gboolean filter_stdout(GIOChannel *channel, GIOCondition condition, gpointer data_) 38 { 39 struct filter_data *data = data_; 40 gboolean done = condition & (G_IO_ERR | G_IO_HUP); 41 42 if (condition & (G_IO_IN | G_IO_HUP)) { 43 gchar *buf; 44 gsize n; 45 GIOStatus ret = g_io_channel_read_to_end(channel, &buf, &n, NULL); 46 g_string_append_len(data->out_str, buf, n); 47 g_free(buf); 48 if (ret == G_IO_STATUS_ERROR) { 49 data->err = 1; 50 done = TRUE; 67 51 } 68 52 } 69 53 70 if (wfd >= 0) close(wfd); 71 close(rfd); 72 *in = g_string_free(str, err < 0); 73 return err; 54 if (condition & G_IO_ERR) 55 data->err = 1; 56 57 if (done) { 58 g_io_channel_shutdown(channel, TRUE, NULL); 59 g_main_loop_quit(data->loop); 60 } 61 return !done; 74 62 } 75 63 76 64 int call_filter(const char *const *argv, const char *in, char **out, int *status) 77 65 { 78 int err;79 66 GPid child_pid; 80 67 int child_stdin, child_stdout; … … 89 76 } 90 77 91 err = send_receive(child_stdout, child_stdin, in, out); 92 if (err == 0) { 93 waitpid(child_pid, status, 0); 94 } 95 return err; 78 if (in == NULL) in = ""; 79 GMainContext *context = g_main_context_new(); 80 struct filter_data data = {&in, in + strlen(in), g_string_new(""), g_main_loop_new(context, FALSE), 0}; 81 82 GIOChannel *channel = g_io_channel_unix_new(child_stdin); 83 g_io_channel_set_encoding(channel, NULL, NULL); 84 g_io_channel_set_flags(channel, g_io_channel_get_flags(channel) | G_IO_FLAG_NONBLOCK, NULL); 85 GSource *source = g_io_create_watch(channel, G_IO_OUT | G_IO_ERR | G_IO_HUP); 86 g_io_channel_unref(channel); 87 g_source_set_callback(source, (GSourceFunc)filter_stdin, &data, NULL); 88 g_source_attach(source, context); 89 g_source_unref(source); 90 91 channel = g_io_channel_unix_new(child_stdout); 92 g_io_channel_set_encoding(channel, NULL, NULL); 93 g_io_channel_set_flags(channel, g_io_channel_get_flags(channel) | G_IO_FLAG_NONBLOCK, NULL); 94 source = g_io_create_watch(channel, G_IO_IN | G_IO_ERR | G_IO_HUP); 95 g_io_channel_unref(channel); 96 g_source_set_callback(source, (GSourceFunc)filter_stdout, &data, NULL); 97 g_source_attach(source, context); 98 g_source_unref(source); 99 100 g_main_loop_run(data.loop); 101 102 g_main_loop_unref(data.loop); 103 g_main_context_unref(context); 104 105 waitpid(child_pid, status, 0); 106 g_spawn_close_pid(child_pid); 107 *out = g_string_free(data.out_str, data.err); 108 return data.err; 96 109 }
Note: See TracChangeset
for help on using the changeset viewer.