Diff options
Diffstat (limited to '')
-rw-r--r--source/filter.c120
1 file changed, 52 insertions, 68 deletions
diff --git a/source/filter.c b/source/filter.c
index f2dfe12..6cc5e80 100644
--- a/source/filter.c
+++ b/source/filter.c
@@ -25,6 +25,31 @@
// The exec filter holding stdout, for cgit_abort_filters to take it back.
static struct cgit_exec_filter *running_exec;
+/*
+ * Each of these returns its argument untouched when the syscall it wraps
+ * succeeded, and dies with the message and errno otherwise.
+ */
+static int die_unless_zero(int result, const char *msg)
+{
+ if (result != 0)
+ die_errno("%s", msg);
+ return result;
+}
+
+static int die_unless_positive(int result, const char *msg)
+{
+ if (result <= 0)
+ die_errno("%s", msg);
+ return result;
+}
+
+static int die_unless_non_negative(int result, const char *msg)
+{
+ if (result < 0)
+ die_errno("%s", msg);
+ return result;
+}
+
static int open_exec_filter(struct cgit_filter *base, va_list ap)
{
struct cgit_exec_filter *filter = (struct cgit_exec_filter *)base;
@@ -34,12 +59,12 @@ static int open_exec_filter(struct cgit_filter *base, va_list ap)
for (i = 0; i < filter->base.argument_count; i++)
filter->argv[i + 1] = va_arg(ap, char *);
- filter->old_stdout = cgit_die_unless_positive(dup(STDOUT_FILENO), "Unable to duplicate stdout");
+ filter->old_stdout = die_unless_positive(dup(STDOUT_FILENO), "Unable to duplicate stdout");
// The child keeps the page's stdout, but not the descriptor the parent
// needs it back from.
fcntl(filter->old_stdout, F_SETFD, FD_CLOEXEC);
- cgit_die_unless_zero(pipe(pipefd), "Unable to create pipe to subprocess");
- filter->pid = cgit_die_unless_non_negative(fork(), "Unable to create subprocess");
+ die_unless_zero(pipe(pipefd), "Unable to create pipe to subprocess");
+ filter->pid = die_unless_non_negative(fork(), "Unable to create subprocess");
if (filter->pid == 0) {
close(pipefd[1]);
if (dup2(pipefd[0], STDIN_FILENO) < 0)
@@ -55,7 +80,7 @@ static int open_exec_filter(struct cgit_filter *base, va_list ap)
_exit(EXEC_FAILED);
}
close(pipefd[0]);
- cgit_die_unless_non_negative(dup2(pipefd[1], STDOUT_FILENO), "Unable to use pipe as stdout");
+ die_unless_non_negative(dup2(pipefd[1], STDOUT_FILENO), "Unable to use pipe as stdout");
close(pipefd[1]);
running_exec = filter;
return 0;
@@ -64,22 +89,16 @@ static int open_exec_filter(struct cgit_filter *base, va_list ap)
static int close_exec_filter(struct cgit_filter *base)
{
struct cgit_exec_filter *filter = (struct cgit_exec_filter *)base;
- int i, exit_status = 0;
+ int exit_status = 0;
running_exec = NULL;
- cgit_die_unless_non_negative(dup2(filter->old_stdout, STDOUT_FILENO), "Unable to restore stdout");
+ die_unless_non_negative(dup2(filter->old_stdout, STDOUT_FILENO), "Unable to restore stdout");
close(filter->old_stdout);
- if (filter->pid < 0)
- goto done;
waitpid(filter->pid, &exit_status, 0);
if (!WIFEXITED(exit_status))
die("Subprocess %s exited abnormally", filter->cmd);
if (WEXITSTATUS(exit_status) == EXEC_FAILED)
die("Unable to run filter %s", filter->cmd);
-
-done:
- for (i = 0; i < filter->base.argument_count; i++)
- filter->argv[i + 1] = NULL;
return WEXITSTATUS(exit_status);
}
@@ -103,16 +122,13 @@ static void cleanup_exec_filter(struct cgit_filter *base)
static struct cgit_filter *new_exec_filter(const char *cmd, int argument_count)
{
struct cgit_exec_filter *filter;
- int argv_size;
filter = xmalloc(sizeof(*filter));
cgit_exec_filter_init(filter, cgit_strdup_first_line(cmd), NULL);
filter->base.argument_count = argument_count;
// argv is the command, then a slot per argument, then the NULL that
// execvp needs to find the end.
- argv_size = (2 + argument_count) * sizeof(char *);
- filter->argv = xmalloc(argv_size);
- memset(filter->argv, 0, argv_size);
+ filter->argv = xcalloc(2 + argument_count, sizeof(char *));
filter->argv[0] = filter->cmd;
return &filter->base;
}
@@ -126,15 +142,8 @@ void cgit_exec_filter_init(struct cgit_exec_filter *filter, const char *cmd, con
filter->base.cleanup = cleanup_exec_filter;
filter->cmd = cmd;
filter->argv = argv;
- filter->base.argument_count = 0;
}
-#ifdef NO_LUA
-void cgit_init_filters(void)
-{
-}
-#endif
-
#ifndef NO_LUA
struct lua_filter {
struct cgit_filter base;
@@ -279,19 +288,9 @@ static int script_html_url_arg(lua_State *lua_state)
return emit_unfiltered(lua_state, html_url_arg);
}
-/*
- * html_include returns whether it found the file, and calling it through a
- * pointer that claims it returns nothing would be undefined, so the result is
- * dropped in a wrapper of the right shape.
- */
-static void include_and_discard_result(const char *filename)
-{
- html_include(filename);
-}
-
static int script_html_include(lua_State *lua_state)
{
- return emit_unfiltered(lua_state, include_and_discard_result);
+ return emit_unfiltered(lua_state, html_include);
}
static const struct {
@@ -383,8 +382,7 @@ static struct cgit_filter *new_lua_filter(const char *cmd, int argument_count)
{
struct lua_filter *filter;
- filter = xmalloc(sizeof(*filter));
- memset(filter, 0, sizeof(*filter));
+ filter = xcalloc(1, sizeof(*filter));
filter->base.open = open_lua_filter;
filter->base.close = close_lua_filter;
filter->base.fprintfp = fprintf_lua_filter;
@@ -394,6 +392,10 @@ static struct cgit_filter *new_lua_filter(const char *cmd, int argument_count)
return &filter->base;
}
+#else
+void cgit_init_filters(void)
+{
+}
#endif
int cgit_open_filter(struct cgit_filter *filter, ...)
@@ -477,35 +479,14 @@ int cgit_filter_holds_stdout(void)
return running_exec != NULL;
}
-static const struct {
- const char *prefix;
- struct cgit_filter *(*create)(const char *cmd, int argument_count);
-} filter_specs[] = {
- { "exec", new_exec_filter },
-#ifndef NO_LUA
- { "lua", new_lua_filter },
-#endif
-};
-
struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype)
{
- const char *colon;
- size_t i;
- size_t len;
+ const char *colon, *arg;
int argument_count;
if (!cmd || !cmd[0])
return NULL;
- colon = strchr(cmd, ':');
- // Measured only once there is a colon to measure against, because
- // subtracting from a null pointer is not something C defines.
- len = colon ? (size_t)(colon - cmd) : 0;
- // A single letter before the colon is a Windows drive letter, not a
- // filter prefix.
- if (len == 1)
- colon = NULL;
-
switch (filtertype) {
case AUTH:
argument_count = 12;
@@ -526,17 +507,20 @@ struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype)
break;
}
- if (!colon)
- 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].create(colon + 1, argument_count);
- }
-
+ if (skip_prefix(cmd, "exec:", &arg))
+ return new_exec_filter(arg, argument_count);
+ if (skip_prefix(cmd, "lua:", &arg)) {
#ifdef NO_LUA
- if (len == 3 && !strncmp("lua", cmd, len))
die("Built without Lua, cannot run filter %s", cmd);
+#else
+ return new_lua_filter(arg, argument_count);
#endif
- die("Invalid filter type: %.*s", (int)len, cmd);
+ }
+
+ // A single letter before the colon is a Windows drive letter, not a
+ // filter prefix.
+ colon = strchr(cmd, ':');
+ if (!colon || colon - cmd == 1)
+ return new_exec_filter(cmd, argument_count);
+ die("Invalid filter type: %.*s", (int)(colon - cmd), cmd);
}