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)  	const char *path;  	int err, ttl; +	cgit_init_filters(); +  	prepare_context(&ctx);  	cgit_repolist.length = 0;  	cgit_repolist.count = 0; @@ -61,13 +61,13 @@ struct cgit_filter {  	int (*close)(struct cgit_filter *);  	void (*fprintf)(struct cgit_filter *, FILE *, const char *prefix);  	void (*cleanup)(struct cgit_filter *); +	int argument_count;  };  struct cgit_exec_filter {  	struct cgit_filter base;  	char *cmd;  	char **argv; -	int extra_args;  	int old_stdout;  	int pipe_fh[2];  	int pid; @@ -357,6 +357,7 @@ extern void cgit_fprintf_filter(struct cgit_filter *filter, FILE *f, const char  extern void cgit_exec_filter_init(struct cgit_exec_filter *filter, char *cmd, char **argv);  extern struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype);  extern void cgit_cleanup_filters(void); +extern void cgit_init_filters(void);  extern void cgit_prepare_repo_env(struct cgit_repo * repo); @@ -61,6 +61,8 @@ $(CGIT_VERSION_OBJS): $(CGIT_PREFIX)VERSION  $(CGIT_VERSION_OBJS): EXTRA_CPPFLAGS = \  	-DCGIT_VERSION='"$(CGIT_VERSION)"' +CGIT_LIBS += -ldl +  # Git handles dependencies using ":=" so dependencies in CGIT_OBJ are not  # 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)  	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $(CGIT_CFLAGS) $<  $(CGIT_PREFIX)cgit: $(CGIT_OBJS) GIT-LDFLAGS $(GITLIBS) -	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) +	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) $(CGIT_LIBS) @@ -12,6 +12,11 @@  #include <unistd.h>  #include <string.h>  #include <stdlib.h> +#include <dlfcn.h> + +static ssize_t (*libc_write)(int fd, const void *buf, size_t count); +static ssize_t (*filter_write)(struct cgit_filter *base, const void *buf, size_t count) = NULL; +static struct cgit_filter *current_write_filter = NULL;  static inline void reap_filter(struct cgit_filter *filter)  { @@ -32,12 +37,43 @@ void cgit_cleanup_filters(void)  	}  } +void cgit_init_filters(void) +{ +	libc_write = dlsym(RTLD_NEXT, "write"); +	if (!libc_write) +		die("Could not locate libc's write function"); +} + +ssize_t write(int fd, const void *buf, size_t count) +{ +	if (fd != STDOUT_FILENO || !filter_write) +		return libc_write(fd, buf, count); +	return filter_write(current_write_filter, buf, count); +} + +static inline void hook_write(struct cgit_filter *filter, ssize_t (*new_write)(struct cgit_filter *base, const void *buf, size_t count)) +{ +	/* We want to avoid buggy nested patterns. */ +	assert(filter_write == NULL); +	assert(current_write_filter == NULL); +	current_write_filter = filter; +	filter_write = new_write; +} + +static inline void unhook_write() +{ +	assert(filter_write != NULL); +	assert(current_write_filter != NULL); +	filter_write = NULL; +	current_write_filter = NULL; +} +  static int open_exec_filter(struct cgit_filter *base, va_list ap)  {  	struct cgit_exec_filter *filter = (struct cgit_exec_filter *) base;  	int i; -	for (i = 0; i < filter->extra_args; i++) +	for (i = 0; i < filter->base.argument_count; i++)  		filter->argv[i+1] = va_arg(ap, char *);  	filter->old_stdout = chk_positive(dup(STDOUT_FILENO), @@ -74,7 +110,7 @@ static int close_exec_filter(struct cgit_filter *base)  	die("Subprocess %s exited abnormally", filter->cmd);  done: -	for (i = 0; i < filter->extra_args; i++) +	for (i = 0; i < filter->base.argument_count; i++)  		filter->argv[i+1] = NULL;  	return 0; @@ -99,7 +135,7 @@ static void cleanup_exec_filter(struct cgit_filter *base)  	}  } -static struct cgit_filter *new_exec_filter(const char *cmd, filter_type filtertype) +static struct cgit_filter *new_exec_filter(const char *cmd, int argument_count)  {  	struct cgit_exec_filter *f;  	int args_size = 0; @@ -107,20 +143,8 @@ static struct cgit_filter *new_exec_filter(const char *cmd, filter_type filterty  	f = xmalloc(sizeof(*f));  	/* We leave argv for now and assign it below. */  	cgit_exec_filter_init(f, xstrdup(cmd), NULL); - -	switch (filtertype) { -		case SOURCE: -		case ABOUT: -			f->extra_args = 1; -			break; - -		case COMMIT: -		default: -			f->extra_args = 0; -			break; -	} - -	args_size = (2 + f->extra_args) * sizeof(char *); +	f->base.argument_count = argument_count; +	args_size = (2 + argument_count) * sizeof(char *);  	f->argv = xmalloc(args_size);  	memset(f->argv, 0, args_size);  	f->argv[0] = f->cmd; @@ -136,6 +160,8 @@ void cgit_exec_filter_init(struct cgit_exec_filter *filter, char *cmd, char **ar  	filter->base.cleanup = cleanup_exec_filter;  	filter->cmd = cmd;  	filter->argv = argv; +	/* The argument count for open_filter is zero by default, unless called from new_filter, above. */ +	filter->base.argument_count = 0;  }  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  static const struct {  	const char *prefix; -	struct cgit_filter *(*ctor)(const char *cmd, filter_type filtertype); +	struct cgit_filter *(*ctor)(const char *cmd, int argument_count);  } filter_specs[] = {  	{ "exec", new_exec_filter },  }; @@ -172,6 +198,8 @@ struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype)  	char *colon;  	int i;  	size_t len; +	int argument_count; +  	if (!cmd || !cmd[0])  		return NULL; @@ -184,16 +212,27 @@ struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype)  	if (len == 1)  		colon = NULL; +	switch (filtertype) { +		case SOURCE: +		case ABOUT: +			argument_count = 1; +			break; + +		case COMMIT: +		default: +			argument_count = 0; +			break; +	} +  	/* If no prefix is given, exec filter is the default. */  	if (!colon) -		return new_exec_filter(cmd, filtertype); +		return new_exec_filter(cmd, argument_count);  	for (i = 0; i < ARRAY_SIZE(filter_specs); i++) {  		if (len == strlen(filter_specs[i].prefix) &&  		    !strncmp(filter_specs[i].prefix, cmd, len)) -			return filter_specs[i].ctor(colon + 1, filtertype); +			return filter_specs[i].ctor(colon + 1, argument_count);  	}  	die("Invalid filter type: %.*s", (int) len, cmd);  } - | 
