diff options
-rw-r--r-- | cgit.c | 2 | ||||
-rw-r--r-- | cgit.h | 3 | ||||
-rw-r--r-- | cgit.mk | 4 | ||||
-rw-r--r-- | filter.c | 81 |
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 | ||
66 | struct cgit_exec_filter { | 67 | struct 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 | |||
357 | extern void cgit_exec_filter_init(struct cgit_exec_filter *filter, char *cmd, char **argv); | 357 | extern void cgit_exec_filter_init(struct cgit_exec_filter *filter, char *cmd, char **argv); |
358 | extern struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype); | 358 | extern struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype); |
359 | extern void cgit_cleanup_filters(void); | 359 | extern void cgit_cleanup_filters(void); |
360 | extern void cgit_init_filters(void); | ||
360 | 361 | ||
361 | extern void cgit_prepare_repo_env(struct cgit_repo * repo); | 362 | extern 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 | ||
64 | CGIT_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 | |||
17 | static ssize_t (*libc_write)(int fd, const void *buf, size_t count); | ||
18 | static ssize_t (*filter_write)(struct cgit_filter *base, const void *buf, size_t count) = NULL; | ||
19 | static struct cgit_filter *current_write_filter = NULL; | ||
15 | 20 | ||
16 | static inline void reap_filter(struct cgit_filter *filter) | 21 | static 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 | ||
40 | void 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 | |||
47 | ssize_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 | |||
54 | static 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 | |||
63 | static 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 | |||
35 | static int open_exec_filter(struct cgit_filter *base, va_list ap) | 71 | static 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 | ||
76 | done: | 112 | done: |
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 | ||
102 | static struct cgit_filter *new_exec_filter(const char *cmd, filter_type filtertype) | 138 | static 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 | ||
141 | int cgit_open_filter(struct cgit_filter *filter, ...) | 167 | int 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 | ||
163 | static const struct { | 189 | static 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 | |||