]>
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)
10 #include <sys/types.h>
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
;
21 static inline void reap_filter(struct cgit_filter
*filter
)
23 if (filter
&& filter
->cleanup
)
24 filter
->cleanup(filter
);
27 void cgit_cleanup_filters(void)
30 reap_filter(ctx
.cfg
.about_filter
);
31 reap_filter(ctx
.cfg
.commit_filter
);
32 reap_filter(ctx
.cfg
.source_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
);
40 void cgit_init_filters(void)
42 libc_write
= dlsym(RTLD_NEXT
, "write");
44 die("Could not locate libc's write function");
47 ssize_t
write(int fd
, const void *buf
, size_t count
)
49 if (fd
!= STDOUT_FILENO
|| !filter_write
)
50 return libc_write(fd
, buf
, count
);
51 return filter_write(current_write_filter
, buf
, count
);
54 static inline void hook_write(struct cgit_filter
*filter
, ssize_t (*new_write
)(struct cgit_filter
*base
, const void *buf
, size_t count
))
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
;
63 static inline void unhook_write()
65 assert(filter_write
!= NULL
);
66 assert(current_write_filter
!= NULL
);
68 current_write_filter
= NULL
;
71 static int open_exec_filter(struct cgit_filter
*base
, va_list ap
)
73 struct cgit_exec_filter
*filter
= (struct cgit_exec_filter
*) base
;
76 for (i
= 0; i
< filter
->base
.argument_count
; i
++)
77 filter
->argv
[i
+1] = va_arg(ap
, char *);
79 filter
->old_stdout
= chk_positive(dup(STDOUT_FILENO
),
80 "Unable to duplicate STDOUT");
81 chk_zero(pipe(filter
->pipe_fh
), "Unable to create pipe to subprocess");
82 filter
->pid
= chk_non_negative(fork(), "Unable to create subprocess");
83 if (filter
->pid
== 0) {
84 close(filter
->pipe_fh
[1]);
85 chk_non_negative(dup2(filter
->pipe_fh
[0], STDIN_FILENO
),
86 "Unable to use pipe as STDIN");
87 execvp(filter
->cmd
, filter
->argv
);
88 die_errno("Unable to exec subprocess %s", filter
->cmd
);
90 close(filter
->pipe_fh
[0]);
91 chk_non_negative(dup2(filter
->pipe_fh
[1], STDOUT_FILENO
),
92 "Unable to use pipe as STDOUT");
93 close(filter
->pipe_fh
[1]);
97 static int close_exec_filter(struct cgit_filter
*base
)
99 struct cgit_exec_filter
*filter
= (struct cgit_exec_filter
*) base
;
102 chk_non_negative(dup2(filter
->old_stdout
, STDOUT_FILENO
),
103 "Unable to restore STDOUT");
104 close(filter
->old_stdout
);
107 waitpid(filter
->pid
, &exit_status
, 0);
108 if (WIFEXITED(exit_status
) && !WEXITSTATUS(exit_status
))
110 die("Subprocess %s exited abnormally", filter
->cmd
);
113 for (i
= 0; i
< filter
->base
.argument_count
; i
++)
114 filter
->argv
[i
+1] = NULL
;
119 static void fprintf_exec_filter(struct cgit_filter
*base
, FILE *f
, const char *prefix
)
121 struct cgit_exec_filter
*filter
= (struct cgit_exec_filter
*) base
;
122 fprintf(f
, "%sexec:%s\n", prefix
, filter
->cmd
);
125 static void cleanup_exec_filter(struct cgit_filter
*base
)
127 struct cgit_exec_filter
*filter
= (struct cgit_exec_filter
*) base
;
138 static struct cgit_filter
*new_exec_filter(const char *cmd
, int argument_count
)
140 struct cgit_exec_filter
*f
;
143 f
= xmalloc(sizeof(*f
));
144 /* We leave argv for now and assign it below. */
145 cgit_exec_filter_init(f
, xstrdup(cmd
), NULL
);
146 f
->base
.argument_count
= argument_count
;
147 args_size
= (2 + argument_count
) * sizeof(char *);
148 f
->argv
= xmalloc(args_size
);
149 memset(f
->argv
, 0, args_size
);
154 void cgit_exec_filter_init(struct cgit_exec_filter
*filter
, char *cmd
, char **argv
)
156 memset(filter
, 0, sizeof(*filter
));
157 filter
->base
.open
= open_exec_filter
;
158 filter
->base
.close
= close_exec_filter
;
159 filter
->base
.fprintf
= fprintf_exec_filter
;
160 filter
->base
.cleanup
= cleanup_exec_filter
;
163 /* The argument count for open_filter is zero by default, unless called from new_filter, above. */
164 filter
->base
.argument_count
= 0;
167 int cgit_open_filter(struct cgit_filter
*filter
, ...)
171 va_start(ap
, filter
);
172 result
= filter
->open(filter
, ap
);
177 int cgit_close_filter(struct cgit_filter
*filter
)
179 return filter
->close(filter
);
182 void cgit_fprintf_filter(struct cgit_filter
*filter
, FILE *f
, const char *prefix
)
184 filter
->fprintf(filter
, f
, prefix
);
189 static const struct {
191 struct cgit_filter
*(*ctor
)(const char *cmd
, int argument_count
);
193 { "exec", new_exec_filter
},
196 struct cgit_filter
*cgit_new_filter(const char *cmd
, filter_type filtertype
)
206 colon
= strchr(cmd
, ':');
209 * In case we're running on Windows, don't allow a single letter before
215 switch (filtertype
) {
227 /* If no prefix is given, exec filter is the default. */
229 return new_exec_filter(cmd
, argument_count
);
231 for (i
= 0; i
< ARRAY_SIZE(filter_specs
); i
++) {
232 if (len
== strlen(filter_specs
[i
].prefix
) &&
233 !strncmp(filter_specs
[i
].prefix
, cmd
, len
))
234 return filter_specs
[i
].ctor(colon
+ 1, argument_count
);
237 die("Invalid filter type: %.*s", (int) len
, cmd
);