| [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 | } |
|---|