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
| @@ -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; |
| @@ -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 | ||
| @@ -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) |
| @@ -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 | |||
