all repos — cgit @ 7bd90b8048fd6937766dff7474947dd80205ea7e

a hyperfast web frontend for git written in c

filter.c (view raw)

  1/* filter.c: filter framework functions
  2 *
  3 * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
  4 *
  5 * Licensed under GNU General Public License v2
  6 *   (see COPYING for full license text)
  7 */
  8
  9#include "cgit.h"
 10#include <sys/types.h>
 11#include <sys/wait.h>
 12#include <unistd.h>
 13#include <string.h>
 14#include <stdlib.h>
 15
 16static int open_exec_filter(struct cgit_filter *base, va_list ap)
 17{
 18	struct cgit_exec_filter *filter = (struct cgit_exec_filter *) base;
 19	int i;
 20
 21	for (i = 0; i < filter->extra_args; i++)
 22		filter->argv[i+1] = va_arg(ap, char *);
 23
 24	filter->old_stdout = chk_positive(dup(STDOUT_FILENO),
 25		"Unable to duplicate STDOUT");
 26	chk_zero(pipe(filter->pipe_fh), "Unable to create pipe to subprocess");
 27	filter->pid = chk_non_negative(fork(), "Unable to create subprocess");
 28	if (filter->pid == 0) {
 29		close(filter->pipe_fh[1]);
 30		chk_non_negative(dup2(filter->pipe_fh[0], STDIN_FILENO),
 31			"Unable to use pipe as STDIN");
 32		execvp(filter->cmd, filter->argv);
 33		die_errno("Unable to exec subprocess %s", filter->cmd);
 34	}
 35	close(filter->pipe_fh[0]);
 36	chk_non_negative(dup2(filter->pipe_fh[1], STDOUT_FILENO),
 37		"Unable to use pipe as STDOUT");
 38	close(filter->pipe_fh[1]);
 39	return 0;
 40}
 41
 42static int close_exec_filter(struct cgit_filter *base)
 43{
 44	struct cgit_exec_filter *filter = (struct cgit_exec_filter *) base;
 45	int i, exit_status;
 46
 47	chk_non_negative(dup2(filter->old_stdout, STDOUT_FILENO),
 48		"Unable to restore STDOUT");
 49	close(filter->old_stdout);
 50	if (filter->pid < 0)
 51		goto done;
 52	waitpid(filter->pid, &exit_status, 0);
 53	if (WIFEXITED(exit_status) && !WEXITSTATUS(exit_status))
 54		goto done;
 55	die("Subprocess %s exited abnormally", filter->cmd);
 56
 57done:
 58	for (i = 0; i < filter->extra_args; i++)
 59		filter->argv[i+1] = NULL;
 60	return 0;
 61
 62}
 63
 64static void fprintf_exec_filter(struct cgit_filter *base, FILE *f, const char *prefix)
 65{
 66	struct cgit_exec_filter *filter = (struct cgit_exec_filter *) base;
 67	fprintf(f, "%s%s\n", prefix, filter->cmd);
 68}
 69
 70int cgit_open_filter(struct cgit_filter *filter, ...)
 71{
 72	int result;
 73	va_list ap;
 74	va_start(ap, filter);
 75	result = filter->open(filter, ap);
 76	va_end(ap);
 77	return result;
 78}
 79
 80int cgit_close_filter(struct cgit_filter *filter)
 81{
 82	return filter->close(filter);
 83}
 84
 85void cgit_fprintf_filter(struct cgit_filter *filter, FILE *f, const char *prefix)
 86{
 87	filter->fprintf(filter, f, prefix);
 88}
 89
 90void cgit_exec_filter_init(struct cgit_exec_filter *filter, char *cmd, char **argv)
 91{
 92	memset(filter, 0, sizeof(*filter));
 93	filter->base.open = open_exec_filter;
 94	filter->base.close = close_exec_filter;
 95	filter->base.fprintf = fprintf_exec_filter;
 96	filter->cmd = cmd;
 97	filter->argv = argv;
 98}
 99
100static struct cgit_filter *new_exec_filter(const char *cmd, filter_type filtertype)
101{
102	struct cgit_exec_filter *f;
103	int args_size = 0;
104
105	f = xmalloc(sizeof(*f));
106	/* We leave argv for now and assign it below. */
107	cgit_exec_filter_init(f, xstrdup(cmd), NULL);
108
109	switch (filtertype) {
110		case SOURCE:
111		case ABOUT:
112			f->extra_args = 1;
113			break;
114
115		case COMMIT:
116		default:
117			f->extra_args = 0;
118			break;
119	}
120
121	args_size = (2 + f->extra_args) * sizeof(char *);
122	f->argv = xmalloc(args_size);
123	memset(f->argv, 0, args_size);
124	f->argv[0] = f->cmd;
125	return &f->base;
126}
127
128struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype)
129{
130	if (!cmd || !cmd[0])
131		return NULL;
132
133	return new_exec_filter(cmd, filtertype);
134}