]>
git.cameronkatri.com Git - cgit.git/blob - filter.c
1 /* filter.c: filter framework functions
3 * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text)
18 static inline void reap_filter(struct cgit_filter
*filter
)
20 if (filter
&& filter
->cleanup
)
21 filter
->cleanup(filter
);
24 void cgit_cleanup_filters(void)
27 reap_filter(ctx
.cfg
.about_filter
);
28 reap_filter(ctx
.cfg
.commit_filter
);
29 reap_filter(ctx
.cfg
.source_filter
);
30 reap_filter(ctx
.cfg
.email_filter
);
31 reap_filter(ctx
.cfg
.owner_filter
);
32 reap_filter(ctx
.cfg
.auth_filter
);
33 for (i
= 0; i
< cgit_repolist
.count
; ++i
) {
34 reap_filter(cgit_repolist
.repos
[i
].about_filter
);
35 reap_filter(cgit_repolist
.repos
[i
].commit_filter
);
36 reap_filter(cgit_repolist
.repos
[i
].source_filter
);
37 reap_filter(cgit_repolist
.repos
[i
].email_filter
);
38 reap_filter(cgit_repolist
.repos
[i
].owner_filter
);
42 static int open_exec_filter(struct cgit_filter
*base
, va_list ap
)
44 struct cgit_exec_filter
*filter
= (struct cgit_exec_filter
*)base
;
47 for (i
= 0; i
< filter
->base
.argument_count
; i
++)
48 filter
->argv
[i
+ 1] = va_arg(ap
, char *);
50 filter
->old_stdout
= chk_positive(dup(STDOUT_FILENO
),
51 "Unable to duplicate STDOUT");
52 chk_zero(pipe(filter
->pipe_fh
), "Unable to create pipe to subprocess");
53 filter
->pid
= chk_non_negative(fork(), "Unable to create subprocess");
54 if (filter
->pid
== 0) {
55 close(filter
->pipe_fh
[1]);
56 chk_non_negative(dup2(filter
->pipe_fh
[0], STDIN_FILENO
),
57 "Unable to use pipe as STDIN");
58 execvp(filter
->cmd
, filter
->argv
);
59 die_errno("Unable to exec subprocess %s", filter
->cmd
);
61 close(filter
->pipe_fh
[0]);
62 chk_non_negative(dup2(filter
->pipe_fh
[1], STDOUT_FILENO
),
63 "Unable to use pipe as STDOUT");
64 close(filter
->pipe_fh
[1]);
68 static int close_exec_filter(struct cgit_filter
*base
)
70 struct cgit_exec_filter
*filter
= (struct cgit_exec_filter
*)base
;
71 int i
, exit_status
= 0;
73 chk_non_negative(dup2(filter
->old_stdout
, STDOUT_FILENO
),
74 "Unable to restore STDOUT");
75 close(filter
->old_stdout
);
78 waitpid(filter
->pid
, &exit_status
, 0);
79 if (WIFEXITED(exit_status
))
81 die("Subprocess %s exited abnormally", filter
->cmd
);
84 for (i
= 0; i
< filter
->base
.argument_count
; i
++)
85 filter
->argv
[i
+ 1] = NULL
;
86 return WEXITSTATUS(exit_status
);
90 static void fprintf_exec_filter(struct cgit_filter
*base
, FILE *f
, const char *prefix
)
92 struct cgit_exec_filter
*filter
= (struct cgit_exec_filter
*)base
;
93 fprintf(f
, "%sexec:%s\n", prefix
, filter
->cmd
);
96 static void cleanup_exec_filter(struct cgit_filter
*base
)
98 struct cgit_exec_filter
*filter
= (struct cgit_exec_filter
*)base
;
109 static struct cgit_filter
*new_exec_filter(const char *cmd
, int argument_count
)
111 struct cgit_exec_filter
*f
;
114 f
= xmalloc(sizeof(*f
));
115 /* We leave argv for now and assign it below. */
116 cgit_exec_filter_init(f
, xstrdup(cmd
), NULL
);
117 f
->base
.argument_count
= argument_count
;
118 args_size
= (2 + argument_count
) * sizeof(char *);
119 f
->argv
= xmalloc(args_size
);
120 memset(f
->argv
, 0, args_size
);
125 void cgit_exec_filter_init(struct cgit_exec_filter
*filter
, char *cmd
, char **argv
)
127 memset(filter
, 0, sizeof(*filter
));
128 filter
->base
.open
= open_exec_filter
;
129 filter
->base
.close
= close_exec_filter
;
130 filter
->base
.fprintf
= fprintf_exec_filter
;
131 filter
->base
.cleanup
= cleanup_exec_filter
;
134 /* The argument count for open_filter is zero by default, unless called from new_filter, above. */
135 filter
->base
.argument_count
= 0;
139 void cgit_init_filters(void)
145 static ssize_t (*libc_write
)(int fd
, const void *buf
, size_t count
);
146 static ssize_t (*filter_write
)(struct cgit_filter
*base
, const void *buf
, size_t count
) = NULL
;
147 static struct cgit_filter
*current_write_filter
= NULL
;
149 void cgit_init_filters(void)
151 libc_write
= dlsym(RTLD_NEXT
, "write");
153 die("Could not locate libc's write function");
156 ssize_t
write(int fd
, const void *buf
, size_t count
)
158 if (fd
!= STDOUT_FILENO
|| !filter_write
)
159 return libc_write(fd
, buf
, count
);
160 return filter_write(current_write_filter
, buf
, count
);
163 static inline void hook_write(struct cgit_filter
*filter
, ssize_t (*new_write
)(struct cgit_filter
*base
, const void *buf
, size_t count
))
165 /* We want to avoid buggy nested patterns. */
166 assert(filter_write
== NULL
);
167 assert(current_write_filter
== NULL
);
168 current_write_filter
= filter
;
169 filter_write
= new_write
;
172 static inline void unhook_write(void)
174 assert(filter_write
!= NULL
);
175 assert(current_write_filter
!= NULL
);
177 current_write_filter
= NULL
;
181 struct cgit_filter base
;
183 lua_State
*lua_state
;
186 static void error_lua_filter(struct lua_filter
*filter
)
188 die("Lua error in %s: %s", filter
->script_file
, lua_tostring(filter
->lua_state
, -1));
189 lua_pop(filter
->lua_state
, 1);
192 static ssize_t
write_lua_filter(struct cgit_filter
*base
, const void *buf
, size_t count
)
194 struct lua_filter
*filter
= (struct lua_filter
*)base
;
196 lua_getglobal(filter
->lua_state
, "filter_write");
197 lua_pushlstring(filter
->lua_state
, buf
, count
);
198 if (lua_pcall(filter
->lua_state
, 1, 0, 0)) {
199 error_lua_filter(filter
);
206 static inline int hook_lua_filter(lua_State
*lua_state
, void (*fn
)(const char *txt
))
209 ssize_t (*save_filter_write
)(struct cgit_filter
*base
, const void *buf
, size_t count
);
210 struct cgit_filter
*save_filter
;
212 str
= lua_tostring(lua_state
, 1);
216 save_filter_write
= filter_write
;
217 save_filter
= current_write_filter
;
220 hook_write(save_filter
, save_filter_write
);
225 static int html_lua_filter(lua_State
*lua_state
)
227 return hook_lua_filter(lua_state
, html
);
230 static int html_txt_lua_filter(lua_State
*lua_state
)
232 return hook_lua_filter(lua_state
, html_txt
);
235 static int html_attr_lua_filter(lua_State
*lua_state
)
237 return hook_lua_filter(lua_state
, html_attr
);
240 static int html_url_path_lua_filter(lua_State
*lua_state
)
242 return hook_lua_filter(lua_state
, html_url_path
);
245 static int html_url_arg_lua_filter(lua_State
*lua_state
)
247 return hook_lua_filter(lua_state
, html_url_arg
);
250 static int html_include_lua_filter(lua_State
*lua_state
)
252 return hook_lua_filter(lua_state
, (void (*)(const char *))html_include
);
255 static void cleanup_lua_filter(struct cgit_filter
*base
)
257 struct lua_filter
*filter
= (struct lua_filter
*)base
;
259 if (!filter
->lua_state
)
262 lua_close(filter
->lua_state
);
263 filter
->lua_state
= NULL
;
264 if (filter
->script_file
) {
265 free(filter
->script_file
);
266 filter
->script_file
= NULL
;
270 static int init_lua_filter(struct lua_filter
*filter
)
272 if (filter
->lua_state
)
275 if (!(filter
->lua_state
= luaL_newstate()))
278 luaL_openlibs(filter
->lua_state
);
280 lua_pushcfunction(filter
->lua_state
, html_lua_filter
);
281 lua_setglobal(filter
->lua_state
, "html");
282 lua_pushcfunction(filter
->lua_state
, html_txt_lua_filter
);
283 lua_setglobal(filter
->lua_state
, "html_txt");
284 lua_pushcfunction(filter
->lua_state
, html_attr_lua_filter
);
285 lua_setglobal(filter
->lua_state
, "html_attr");
286 lua_pushcfunction(filter
->lua_state
, html_url_path_lua_filter
);
287 lua_setglobal(filter
->lua_state
, "html_url_path");
288 lua_pushcfunction(filter
->lua_state
, html_url_arg_lua_filter
);
289 lua_setglobal(filter
->lua_state
, "html_url_arg");
290 lua_pushcfunction(filter
->lua_state
, html_include_lua_filter
);
291 lua_setglobal(filter
->lua_state
, "html_include");
293 if (luaL_dofile(filter
->lua_state
, filter
->script_file
)) {
294 error_lua_filter(filter
);
295 lua_close(filter
->lua_state
);
296 filter
->lua_state
= NULL
;
302 static int open_lua_filter(struct cgit_filter
*base
, va_list ap
)
304 struct lua_filter
*filter
= (struct lua_filter
*)base
;
307 if (init_lua_filter(filter
))
310 hook_write(base
, write_lua_filter
);
312 lua_getglobal(filter
->lua_state
, "filter_open");
313 for (i
= 0; i
< filter
->base
.argument_count
; ++i
)
314 lua_pushstring(filter
->lua_state
, va_arg(ap
, char *));
315 if (lua_pcall(filter
->lua_state
, filter
->base
.argument_count
, 0, 0)) {
316 error_lua_filter(filter
);
322 static int close_lua_filter(struct cgit_filter
*base
)
324 struct lua_filter
*filter
= (struct lua_filter
*)base
;
327 lua_getglobal(filter
->lua_state
, "filter_close");
328 if (lua_pcall(filter
->lua_state
, 0, 1, 0)) {
329 error_lua_filter(filter
);
332 ret
= lua_tonumber(filter
->lua_state
, -1);
333 lua_pop(filter
->lua_state
, 1);
340 static void fprintf_lua_filter(struct cgit_filter
*base
, FILE *f
, const char *prefix
)
342 struct lua_filter
*filter
= (struct lua_filter
*)base
;
343 fprintf(f
, "%slua:%s\n", prefix
, filter
->script_file
);
347 static struct cgit_filter
*new_lua_filter(const char *cmd
, int argument_count
)
349 struct lua_filter
*filter
;
351 filter
= xmalloc(sizeof(*filter
));
352 memset(filter
, 0, sizeof(*filter
));
353 filter
->base
.open
= open_lua_filter
;
354 filter
->base
.close
= close_lua_filter
;
355 filter
->base
.fprintf
= fprintf_lua_filter
;
356 filter
->base
.cleanup
= cleanup_lua_filter
;
357 filter
->base
.argument_count
= argument_count
;
358 filter
->script_file
= xstrdup(cmd
);
360 return &filter
->base
;
366 int cgit_open_filter(struct cgit_filter
*filter
, ...)
372 va_start(ap
, filter
);
373 result
= filter
->open(filter
, ap
);
378 int cgit_close_filter(struct cgit_filter
*filter
)
382 return filter
->close(filter
);
385 void cgit_fprintf_filter(struct cgit_filter
*filter
, FILE *f
, const char *prefix
)
387 filter
->fprintf(filter
, f
, prefix
);
392 static const struct {
394 struct cgit_filter
*(*ctor
)(const char *cmd
, int argument_count
);
396 { "exec", new_exec_filter
},
398 { "lua", new_lua_filter
},
402 struct cgit_filter
*cgit_new_filter(const char *cmd
, filter_type filtertype
)
412 colon
= strchr(cmd
, ':');
415 * In case we're running on Windows, don't allow a single letter before
421 switch (filtertype
) {
445 /* If no prefix is given, exec filter is the default. */
447 return new_exec_filter(cmd
, argument_count
);
449 for (i
= 0; i
< ARRAY_SIZE(filter_specs
); i
++) {
450 if (len
== strlen(filter_specs
[i
].prefix
) &&
451 !strncmp(filter_specs
[i
].prefix
, cmd
, len
))
452 return filter_specs
[i
].ctor(colon
+ 1, argument_count
);
455 die("Invalid filter type: %.*s", (int) len
, cmd
);