[7155955] | 1 | #include "filterproc.h" |
---|
[d564c3d] | 2 | #include <sys/wait.h> |
---|
[7155955] | 3 | #include <string.h> |
---|
[e8db357] | 4 | #include <glib.h> |
---|
| 5 | |
---|
| 6 | struct filter_data { |
---|
| 7 | const char **in; |
---|
| 8 | const char *in_end; |
---|
| 9 | GString *out_str; |
---|
| 10 | GMainLoop *loop; |
---|
| 11 | int err; |
---|
| 12 | }; |
---|
[d564c3d] | 13 | |
---|
[e8db357] | 14 | static gboolean filter_stdin(GIOChannel *channel, GIOCondition condition, gpointer data_) |
---|
[d564c3d] | 15 | { |
---|
[e8db357] | 16 | struct filter_data *data = data_; |
---|
| 17 | gboolean done = condition & (G_IO_ERR | G_IO_HUP); |
---|
| 18 | |
---|
| 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; |
---|
[1f39ded] | 27 | } |
---|
| 28 | |
---|
[e8db357] | 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; |
---|
[d564c3d] | 51 | } |
---|
| 52 | } |
---|
| 53 | |
---|
[e8db357] | 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; |
---|
[d564c3d] | 62 | } |
---|
| 63 | |
---|
[97cdbaf5] | 64 | int call_filter(const char *const *argv, const char *in, char **out, int *status) |
---|
[d564c3d] | 65 | { |
---|
[97cdbaf5] | 66 | GPid child_pid; |
---|
| 67 | int child_stdin, child_stdout; |
---|
[d564c3d] | 68 | |
---|
[97cdbaf5] | 69 | if (!g_spawn_async_with_pipes(NULL, (char**)argv, NULL, |
---|
| 70 | G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, |
---|
| 71 | NULL, NULL, |
---|
| 72 | &child_pid, &child_stdin, &child_stdout, NULL, |
---|
| 73 | NULL)) { |
---|
[3496369] | 74 | *out = NULL; |
---|
[97cdbaf5] | 75 | return 1; |
---|
[d564c3d] | 76 | } |
---|
| 77 | |
---|
[e8db357] | 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; |
---|
[d564c3d] | 109 | } |
---|