forked from barnowl/barnowl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
filterproc.c
118 lines (106 loc) · 2.26 KB
/
filterproc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include <signal.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <poll.h>
#include <fcntl.h>
#include <string.h>
#include <glib.h>
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];
struct sigaction sig = {.sa_handler = SIG_IGN}, old;
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;
sigaction(SIGPIPE, &sig, &old);
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);
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;
}
}
*in = g_string_free(str, err < 0);
sigaction(SIGPIPE, &old, NULL);
return err;
}
int call_filter(const char *prog, const char *const *argv, const char *in, char **out, int *status)
{
int err = 0;
pid_t pid;
int rfd[2];
int wfd[2];
if((err = pipe(rfd))) goto out;
if((err = pipe(wfd))) goto out_close_rfd;
pid = fork();
if(pid < 0) {
err = pid;
goto out_close_all;
}
if(pid) {
/* parent */
close(rfd[1]);
close(wfd[0]);
err = send_receive(rfd[0], wfd[1], in, out);
if(err == 0) {
waitpid(pid, status, 0);
}
} else {
/* child */
close(rfd[0]);
close(wfd[1]);
dup2(rfd[1], 1);
dup2(wfd[0], 0);
close(rfd[1]);
close(wfd[0]);
if(execvp(prog, (char *const *)argv)) {
_exit(-1);
}
}
out_close_all:
close(wfd[0]);
close(wfd[1]);
out_close_rfd:
close(rfd[0]);
close(rfd[1]);
out:
return err;
}