Warmcat homepage andy@warmcat.com
libwebsockets
{"schema":"libjg2-1", "vpath":"/git/", "avatar":"/git/avatar/", "alang":"", "gen_ut":1754239334, "reponame":"cgit", "desc":"CGI gitweb", "owner": { "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },"url":"https://warmcat.com/repo/cgit", "f":3, "items": [ {"schema":"libjg2-1", "cid":"e5c8e5ed42136623da0ec038f8e156a5", "commit": {"type":"commit", "time": 1389661207, "time_ofs": 60, "oid_tree": { "oid": "695797e4de7c7e413730f7ab66246327e6fa0046", "alias": []}, "oid":{ "oid": "e83b51b4f6bd53efea0c772e6ecdf1c5605ca611", "alias": []}, "msg": "filter: basic write hooking infrastructure", "sig_commit": { "git_time": { "time": 1389661207, "offset": 60 }, "name": "Jason A. Donenfeld", "email": "Jason@zx2c4.com", "md5": "689e78dac56e3d77d7f74984912487d3" }, "sig_author": { "git_time": { "time": 1389618978, "offset": 60 }, "name": "Jason A. Donenfeld", "email": "Jason@zx2c4.com", "md5": "689e78dac56e3d77d7f74984912487d3" }}, "body": "filter: basic write hooking infrastructure\n\nFilters can now call hook_write and unhook_write if they want to\nredirect writing to stdout to a different function. This saves us from\npotential file descriptor pipes and other less efficient mechanisms.\n\nWe do this instead of replacing the call in html_raw because some places\nstdlib's printf functions are used (ui-patch or within git itself),\nwhich has its own internal buffering, which makes it difficult to\ninterlace our function calls. So, we dlsym libc's write and then\noverride it in the link stage.\n\nWhile we're at it, we move considerations of argument count into the\ngeneric new filter handler.\n\nSigned-off-by: Jason A. Donenfeld \u003cJason@zx2c4.com\u003e\n" , "diff": "diff --git a/cgit.c b/cgit.c\nindex 4f31e58..725fd65 100644\n--- a/cgit.c\n+++ b/cgit.c\n@@ -904,6 +904,8 @@ int main(int argc, const char **argv)\n \tconst char *path;\n \tint err, ttl;\n \n+\tcgit_init_filters();\n+\n \tprepare_context(\u0026ctx);\n \tcgit_repolist.length \u003d 0;\n \tcgit_repolist.count \u003d 0;\ndiff --git a/cgit.h b/cgit.h\nindex 893c38f..519d2af 100644\n--- a/cgit.h\n+++ b/cgit.h\n@@ -61,13 +61,13 @@ struct cgit_filter {\n \tint (*close)(struct cgit_filter *);\n \tvoid (*fprintf)(struct cgit_filter *, FILE *, const char *prefix);\n \tvoid (*cleanup)(struct cgit_filter *);\n+\tint argument_count;\n };\n \n struct cgit_exec_filter {\n \tstruct cgit_filter base;\n \tchar *cmd;\n \tchar **argv;\n-\tint extra_args;\n \tint old_stdout;\n \tint pipe_fh[2];\n \tint pid;\n@@ -357,6 +357,7 @@ extern void cgit_fprintf_filter(struct cgit_filter *filter, FILE *f, const char \n extern void cgit_exec_filter_init(struct cgit_exec_filter *filter, char *cmd, char **argv);\n extern struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype);\n extern void cgit_cleanup_filters(void);\n+extern void cgit_init_filters(void);\n \n extern void cgit_prepare_repo_env(struct cgit_repo * repo);\n \ndiff --git a/cgit.mk b/cgit.mk\nindex 19a76e7..9d6dea8 100644\n--- a/cgit.mk\n+++ b/cgit.mk\n@@ -61,6 +61,8 @@ $(CGIT_VERSION_OBJS): $(CGIT_PREFIX)VERSION\n $(CGIT_VERSION_OBJS): EXTRA_CPPFLAGS \u003d \u005c\n \t-DCGIT_VERSION\u003d'\u0022$(CGIT_VERSION)\u0022'\n \n+CGIT_LIBS +\u003d -ldl\n+\n \n # Git handles dependencies using \u0022:\u003d\u0022 so dependencies in CGIT_OBJ are not\n # handled by that and we must handle them ourselves.\n@@ -88,4 +90,4 @@ $(CGIT_OBJS): %.o: %.c GIT-CFLAGS $(CGIT_PREFIX)CGIT-CFLAGS $(missing_dep_dirs)\n \t$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $(CGIT_CFLAGS) $\u003c\n \n $(CGIT_PREFIX)cgit: $(CGIT_OBJS) GIT-LDFLAGS $(GITLIBS)\n-\t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)\n+\t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) $(CGIT_LIBS)\ndiff --git a/filter.c b/filter.c\nindex 30bc74b..f5a5992 100644\n--- a/filter.c\n+++ b/filter.c\n@@ -12,6 +12,11 @@\n #include \u003cunistd.h\u003e\n #include \u003cstring.h\u003e\n #include \u003cstdlib.h\u003e\n+#include \u003cdlfcn.h\u003e\n+\n+static ssize_t (*libc_write)(int fd, const void *buf, size_t count);\n+static ssize_t (*filter_write)(struct cgit_filter *base, const void *buf, size_t count) \u003d NULL;\n+static struct cgit_filter *current_write_filter \u003d NULL;\n \n static inline void reap_filter(struct cgit_filter *filter)\n {\n@@ -32,12 +37,43 @@ void cgit_cleanup_filters(void)\n \t}\n }\n \n+void cgit_init_filters(void)\n+{\n+\tlibc_write \u003d dlsym(RTLD_NEXT, \u0022write\u0022);\n+\tif (!libc_write)\n+\t\tdie(\u0022Could not locate libc's write function\u0022);\n+}\n+\n+ssize_t write(int fd, const void *buf, size_t count)\n+{\n+\tif (fd !\u003d STDOUT_FILENO || !filter_write)\n+\t\treturn libc_write(fd, buf, count);\n+\treturn filter_write(current_write_filter, buf, count);\n+}\n+\n+static inline void hook_write(struct cgit_filter *filter, ssize_t (*new_write)(struct cgit_filter *base, const void *buf, size_t count))\n+{\n+\t/* We want to avoid buggy nested patterns. */\n+\tassert(filter_write \u003d\u003d NULL);\n+\tassert(current_write_filter \u003d\u003d NULL);\n+\tcurrent_write_filter \u003d filter;\n+\tfilter_write \u003d new_write;\n+}\n+\n+static inline void unhook_write()\n+{\n+\tassert(filter_write !\u003d NULL);\n+\tassert(current_write_filter !\u003d NULL);\n+\tfilter_write \u003d NULL;\n+\tcurrent_write_filter \u003d NULL;\n+}\n+\n static int open_exec_filter(struct cgit_filter *base, va_list ap)\n {\n \tstruct cgit_exec_filter *filter \u003d (struct cgit_exec_filter *) base;\n \tint i;\n \n-\tfor (i \u003d 0; i \u003c filter-\u003eextra_args; i++)\n+\tfor (i \u003d 0; i \u003c filter-\u003ebase.argument_count; i++)\n \t\tfilter-\u003eargv[i+1] \u003d va_arg(ap, char *);\n \n \tfilter-\u003eold_stdout \u003d chk_positive(dup(STDOUT_FILENO),\n@@ -74,7 +110,7 @@ static int close_exec_filter(struct cgit_filter *base)\n \tdie(\u0022Subprocess %s exited abnormally\u0022, filter-\u003ecmd);\n \n done:\n-\tfor (i \u003d 0; i \u003c filter-\u003eextra_args; i++)\n+\tfor (i \u003d 0; i \u003c filter-\u003ebase.argument_count; i++)\n \t\tfilter-\u003eargv[i+1] \u003d NULL;\n \treturn 0;\n \n@@ -99,7 +135,7 @@ static void cleanup_exec_filter(struct cgit_filter *base)\n \t}\n }\n \n-static struct cgit_filter *new_exec_filter(const char *cmd, filter_type filtertype)\n+static struct cgit_filter *new_exec_filter(const char *cmd, int argument_count)\n {\n \tstruct cgit_exec_filter *f;\n \tint args_size \u003d 0;\n@@ -107,20 +143,8 @@ static struct cgit_filter *new_exec_filter(const char *cmd, filter_type filterty\n \tf \u003d xmalloc(sizeof(*f));\n \t/* We leave argv for now and assign it below. */\n \tcgit_exec_filter_init(f, xstrdup(cmd), NULL);\n-\n-\tswitch (filtertype) {\n-\t\tcase SOURCE:\n-\t\tcase ABOUT:\n-\t\t\tf-\u003eextra_args \u003d 1;\n-\t\t\tbreak;\n-\n-\t\tcase COMMIT:\n-\t\tdefault:\n-\t\t\tf-\u003eextra_args \u003d 0;\n-\t\t\tbreak;\n-\t}\n-\n-\targs_size \u003d (2 + f-\u003eextra_args) * sizeof(char *);\n+\tf-\u003ebase.argument_count \u003d argument_count;\n+\targs_size \u003d (2 + argument_count) * sizeof(char *);\n \tf-\u003eargv \u003d xmalloc(args_size);\n \tmemset(f-\u003eargv, 0, args_size);\n \tf-\u003eargv[0] \u003d f-\u003ecmd;\n@@ -136,6 +160,8 @@ void cgit_exec_filter_init(struct cgit_exec_filter *filter, char *cmd, char **ar\n \tfilter-\u003ebase.cleanup \u003d cleanup_exec_filter;\n \tfilter-\u003ecmd \u003d cmd;\n \tfilter-\u003eargv \u003d argv;\n+\t/* The argument count for open_filter is zero by default, unless called from new_filter, above. */\n+\tfilter-\u003ebase.argument_count \u003d 0;\n }\n \n int cgit_open_filter(struct cgit_filter *filter, ...)\n@@ -162,7 +188,7 @@ void cgit_fprintf_filter(struct cgit_filter *filter, FILE *f, const char *prefix\n \n static const struct {\n \tconst char *prefix;\n-\tstruct cgit_filter *(*ctor)(const char *cmd, filter_type filtertype);\n+\tstruct cgit_filter *(*ctor)(const char *cmd, int argument_count);\n } filter_specs[] \u003d {\n \t{ \u0022exec\u0022, new_exec_filter },\n };\n@@ -172,6 +198,8 @@ struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype)\n \tchar *colon;\n \tint i;\n \tsize_t len;\n+\tint argument_count;\n+\n \tif (!cmd || !cmd[0])\n \t\treturn NULL;\n \n@@ -184,16 +212,27 @@ struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype)\n \tif (len \u003d\u003d 1)\n \t\tcolon \u003d NULL;\n \n+\tswitch (filtertype) {\n+\t\tcase SOURCE:\n+\t\tcase ABOUT:\n+\t\t\targument_count \u003d 1;\n+\t\t\tbreak;\n+\n+\t\tcase COMMIT:\n+\t\tdefault:\n+\t\t\targument_count \u003d 0;\n+\t\t\tbreak;\n+\t}\n+\n \t/* If no prefix is given, exec filter is the default. */\n \tif (!colon)\n-\t\treturn new_exec_filter(cmd, filtertype);\n+\t\treturn new_exec_filter(cmd, argument_count);\n \n \tfor (i \u003d 0; i \u003c ARRAY_SIZE(filter_specs); i++) {\n \t\tif (len \u003d\u003d strlen(filter_specs[i].prefix) \u0026\u0026\n \t\t !strncmp(filter_specs[i].prefix, cmd, len))\n-\t\t\treturn filter_specs[i].ctor(colon + 1, filtertype);\n+\t\t\treturn filter_specs[i].ctor(colon + 1, argument_count);\n \t}\n \n \tdie(\u0022Invalid filter type: %.*s\u0022, (int) len, cmd);\n }\n-\n","s":{"c":1754239334,"u": 2129}} ],"g": 4176,"chitpc": 0,"ehitpc": 0,"indexed":0 , "ab": 0, "si": 0, "db":0, "di":0, "sat":0, "lfc": "0000"}