aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cgit.c2
-rw-r--r--cgit.h3
-rw-r--r--cgit.mk4
-rw-r--r--filter.c81
4 files changed, 67 insertions, 23 deletions
diff --git a/cgit.c b/cgit.c
index 4f31e58..725fd65 100644
--- a/cgit.c
+++ b/cgit.c
@@ -904,6 +904,8 @@ int main(int argc, const char **argv)
904 const char *path; 904 const char *path;
905 int err, ttl; 905 int err, ttl;
906 906
907 cgit_init_filters();
908
907 prepare_context(&ctx); 909 prepare_context(&ctx);
908 cgit_repolist.length = 0; 910 cgit_repolist.length = 0;
909 cgit_repolist.count = 0; 911 cgit_repolist.count = 0;
diff --git a/cgit.h b/cgit.h
index 893c38f..519d2af 100644
--- a/cgit.h
+++ b/cgit.h
@@ -61,13 +61,13 @@ struct cgit_filter {
61 int (*close)(struct cgit_filter *); 61 int (*close)(struct cgit_filter *);
62 void (*fprintf)(struct cgit_filter *, FILE *, const char *prefix); 62 void (*fprintf)(struct cgit_filter *, FILE *, const char *prefix);
63 void (*cleanup)(struct cgit_filter *); 63 void (*cleanup)(struct cgit_filter *);
64 int argument_count;
64}; 65};
65 66
66struct cgit_exec_filter { 67struct cgit_exec_filter {
67 struct cgit_filter base; 68 struct cgit_filter base;
68 char *cmd; 69 char *cmd;
69 char **argv; 70 char **argv;
70 int extra_args;
71 int old_stdout; 71 int old_stdout;
72 int pipe_fh[2]; 72 int pipe_fh[2];
73 int pid; 73 int pid;
@@ -357,6 +357,7 @@ extern void cgit_fprintf_filter(struct cgit_filter *filter, FILE *f, const char
357extern void cgit_exec_filter_init(struct cgit_exec_filter *filter, char *cmd, char **argv); 357extern void cgit_exec_filter_init(struct cgit_exec_filter *filter, char *cmd, char **argv);
358extern struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype); 358extern struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype);
359extern void cgit_cleanup_filters(void); 359extern void cgit_cleanup_filters(void);
360extern void cgit_init_filters(void);
360 361
361extern void cgit_prepare_repo_env(struct cgit_repo * repo); 362extern void cgit_prepare_repo_env(struct cgit_repo * repo);
362 363
diff --git a/cgit.mk b/cgit.mk
index 19a76e7..9d6dea8 100644
--- a/cgit.mk
+++ b/cgit.mk
@@ -61,6 +61,8 @@ $(CGIT_VERSION_OBJS): $(CGIT_PREFIX)VERSION
61$(CGIT_VERSION_OBJS): EXTRA_CPPFLAGS = \ 61$(CGIT_VERSION_OBJS): EXTRA_CPPFLAGS = \
62 -DCGIT_VERSION='"$(CGIT_VERSION)"' 62 -DCGIT_VERSION='"$(CGIT_VERSION)"'
63 63
64CGIT_LIBS += -ldl
65
64 66
65# Git handles dependencies using ":=" so dependencies in CGIT_OBJ are not 67# Git handles dependencies using ":=" so dependencies in CGIT_OBJ are not
66# handled by that and we must handle them ourselves. 68# handled by that and we must handle them ourselves.
@@ -88,4 +90,4 @@ $(CGIT_OBJS): %.o: %.c GIT-CFLAGS $(CGIT_PREFIX)CGIT-CFLAGS $(missing_dep_dirs)
88 $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $(CGIT_CFLAGS) $< 90 $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $(CGIT_CFLAGS) $<
89 91
90$(CGIT_PREFIX)cgit: $(CGIT_OBJS) GIT-LDFLAGS $(GITLIBS) 92$(CGIT_PREFIX)cgit: $(CGIT_OBJS) GIT-LDFLAGS $(GITLIBS)
91 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) 93 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) $(CGIT_LIBS)
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