aboutsummaryrefslogtreecommitdiffstats
path: root/filter.c
diff options
context:
space:
mode:
Diffstat (limited to 'filter.c')
-rw-r--r--filter.c81
1 files changed, 60 insertions, 21 deletions
diff --git a/filter.c b/filter.c
index 30bc74b..f5a5992 100644
--- a/filter.c
+++ b/filter.c
@@ -12,6 +12,11 @@
12#include <unistd.h> 12#include <unistd.h>
13#include <string.h> 13#include <string.h>
14#include <stdlib.h> 14#include <stdlib.h>
15#include <dlfcn.h>
16
17static ssize_t (*libc_write)(int fd, const void *buf, size_t count);
18static ssize_t (*filter_write)(struct cgit_filter *base, const void *buf, size_t count) = NULL;
19static struct cgit_filter *current_write_filter = NULL;
15 20
16static inline void reap_filter(struct cgit_filter *filter) 21static inline void reap_filter(struct cgit_filter *filter)
17{ 22{
@@ -32,12 +37,43 @@ void cgit_cleanup_filters(void)
32 } 37 }
33} 38}
34 39
40void cgit_init_filters(void)
41{
42 libc_write = dlsym(RTLD_NEXT, "write");
43 if (!libc_write)
44 die("Could not locate libc's write function");
45}
46
47ssize_t write(int fd, const void *buf, size_t count)
48{
49 if (fd != STDOUT_FILENO || !filter_write)
50 return libc_write(fd, buf, count);
51 return filter_write(current_write_filter, buf, count);
52}
53
54static inline void hook_write(struct cgit_filter *filter, ssize_t (*new_write)(struct cgit_filter *base, const void *buf, size_t count))
55{
56 /* We want to avoid buggy nested patterns. */
57 assert(filter_write == NULL);
58 assert(current_write_filter == NULL);
59 current_write_filter = filter;
60 filter_write = new_write;
61}
62
63static inline void unhook_write()
64{
65 assert(filter_write != NULL);
66 assert(current_write_filter != NULL);
67 filter_write = NULL;
68 current_write_filter = NULL;
69}
70
35static int open_exec_filter(struct cgit_filter *base, va_list ap) 71static int open_exec_filter(struct cgit_filter *base, va_list ap)
36{ 72{
37 struct cgit_exec_filter *filter = (struct cgit_exec_filter *) base; 73 struct cgit_exec_filter *filter = (struct cgit_exec_filter *) base;
38 int i; 74 int i;
39 75
40 for (i = 0; i < filter->extra_args; i++) 76 for (i = 0; i < filter->base.argument_count; i++)
41 filter->argv[i+1] = va_arg(ap, char *); 77 filter->argv[i+1] = va_arg(ap, char *);
42 78
43 filter->old_stdout = chk_positive(dup(STDOUT_FILENO), 79 filter->old_stdout = chk_positive(dup(STDOUT_FILENO),
@@ -74,7 +110,7 @@ static int close_exec_filter(struct cgit_filter *base)
74 die("Subprocess %s exited abnormally", filter->cmd); 110 die("Subprocess %s exited abnormally", filter->cmd);
75 111
76done: 112done:
77 for (i = 0; i < filter->extra_args; i++) 113 for (i = 0; i < filter->base.argument_count; i++)
78 filter->argv[i+1] = NULL; 114 filter->argv[i+1] = NULL;
79 return 0; 115 return 0;
80 116
@@ -99,7 +135,7 @@ static void cleanup_exec_filter(struct cgit_filter *base)
99 } 135 }
100} 136}
101 137
102static struct cgit_filter *new_exec_filter(const char *cmd, filter_type filtertype) 138static struct cgit_filter *new_exec_filter(const char *cmd, int argument_count)
103{ 139{
104 struct cgit_exec_filter *f; 140 struct cgit_exec_filter *f;
105 int args_size = 0; 141 int args_size = 0;
@@ -107,20 +143,8 @@ static struct cgit_filter *new_exec_filter(const char *cmd, filter_type filterty
107 f = xmalloc(sizeof(*f)); 143 f = xmalloc(sizeof(*f));
108 /* We leave argv for now and assign it below. */ 144 /* We leave argv for now and assign it below. */
109 cgit_exec_filter_init(f, xstrdup(cmd), NULL); 145 cgit_exec_filter_init(f, xstrdup(cmd), NULL);
110 146 f->base.argument_count = argument_count;
111 switch (filtertype) { 147 args_size = (2 + argument_count) * sizeof(char *);
112 case SOURCE:
113 case ABOUT:
114 f->extra_args = 1;
115 break;
116
117 case COMMIT:
118 default:
119 f->extra_args = 0;
120 break;
121 }
122
123 args_size = (2 + f->extra_args) * sizeof(char *);
124 f->argv = xmalloc(args_size); 148 f->argv = xmalloc(args_size);
125 memset(f->argv, 0, args_size); 149 memset(f->argv, 0, args_size);
126 f->argv[0] = f->cmd; 150 f->argv[0] = f->cmd;
@@ -136,6 +160,8 @@ void cgit_exec_filter_init(struct cgit_exec_filter *filter, char *cmd, char **ar
136 filter->base.cleanup = cleanup_exec_filter; 160 filter->base.cleanup = cleanup_exec_filter;
137 filter->cmd = cmd; 161 filter->cmd = cmd;
138 filter->argv = argv; 162 filter->argv = argv;
163 /* The argument count for open_filter is zero by default, unless called from new_filter, above. */
164 filter->base.argument_count = 0;
139} 165}
140 166
141int cgit_open_filter(struct cgit_filter *filter, ...) 167int cgit_open_filter(struct cgit_filter *filter, ...)
@@ -162,7 +188,7 @@ void cgit_fprintf_filter(struct cgit_filter *filter, FILE *f, const char *prefix
162 188
163static const struct { 189static const struct {
164 const char *prefix; 190 const char *prefix;
165 struct cgit_filter *(*ctor)(const char *cmd, filter_type filtertype); 191 struct cgit_filter *(*ctor)(const char *cmd, int argument_count);
166} filter_specs[] = { 192} filter_specs[] = {
167 { "exec", new_exec_filter }, 193 { "exec", new_exec_filter },
168}; 194};
@@ -172,6 +198,8 @@ struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype)
172 char *colon; 198 char *colon;
173 int i; 199 int i;
174 size_t len; 200 size_t len;
201 int argument_count;
202
175 if (!cmd || !cmd[0]) 203 if (!cmd || !cmd[0])
176 return NULL; 204 return NULL;
177 205
@@ -184,16 +212,27 @@ struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype)
184 if (len == 1) 212 if (len == 1)
185 colon = NULL; 213 colon = NULL;
186 214
215 switch (filtertype) {
216 case SOURCE:
217 case ABOUT:
218 argument_count = 1;
219 break;
220
221 case COMMIT:
222 default:
223 argument_count = 0;
224 break;
225 }
226
187 /* If no prefix is given, exec filter is the default. */ 227 /* If no prefix is given, exec filter is the default. */
188 if (!colon) 228 if (!colon)
189 return new_exec_filter(cmd, filtertype); 229 return new_exec_filter(cmd, argument_count);
190 230
191 for (i = 0; i < ARRAY_SIZE(filter_specs); i++) { 231 for (i = 0; i < ARRAY_SIZE(filter_specs); i++) {
192 if (len == strlen(filter_specs[i].prefix) && 232 if (len == strlen(filter_specs[i].prefix) &&
193 !strncmp(filter_specs[i].prefix, cmd, len)) 233 !strncmp(filter_specs[i].prefix, cmd, len))
194 return filter_specs[i].ctor(colon + 1, filtertype); 234 return filter_specs[i].ctor(colon + 1, argument_count);
195 } 235 }
196 236
197 die("Invalid filter type: %.*s", (int) len, cmd); 237 die("Invalid filter type: %.*s", (int) len, cmd);
198} 238}
199