blob: 80cf68956bc5291a74cbe029ebf449af625bedb0 [file] [log] [blame]
Jason A. Donenfeld3eae4062014-01-10 05:19:05 +01001/* 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
John Keeping3d8a6502014-01-12 17:13:50 +000016int cgit_open_filter(struct cgit_filter *filter, ...)
Jason A. Donenfeld3eae4062014-01-10 05:19:05 +010017{
John Keeping3d8a6502014-01-12 17:13:50 +000018 int i;
19 va_list ap;
20
21 va_start(ap, filter);
22 for (i = 0; i < filter->extra_args; i++)
23 filter->argv[i+1] = va_arg(ap, char *);
24 va_end(ap);
25
Jason A. Donenfeld3eae4062014-01-10 05:19:05 +010026 filter->old_stdout = chk_positive(dup(STDOUT_FILENO),
27 "Unable to duplicate STDOUT");
28 chk_zero(pipe(filter->pipe_fh), "Unable to create pipe to subprocess");
29 filter->pid = chk_non_negative(fork(), "Unable to create subprocess");
30 if (filter->pid == 0) {
31 close(filter->pipe_fh[1]);
32 chk_non_negative(dup2(filter->pipe_fh[0], STDIN_FILENO),
33 "Unable to use pipe as STDIN");
34 execvp(filter->cmd, filter->argv);
35 die_errno("Unable to exec subprocess %s", filter->cmd);
36 }
37 close(filter->pipe_fh[0]);
38 chk_non_negative(dup2(filter->pipe_fh[1], STDOUT_FILENO),
39 "Unable to use pipe as STDOUT");
40 close(filter->pipe_fh[1]);
41 return 0;
42}
43
44
45int cgit_close_filter(struct cgit_filter *filter)
46{
John Keeping3d8a6502014-01-12 17:13:50 +000047 int i, exit_status;
Jason A. Donenfeld3eae4062014-01-10 05:19:05 +010048
49 chk_non_negative(dup2(filter->old_stdout, STDOUT_FILENO),
50 "Unable to restore STDOUT");
51 close(filter->old_stdout);
52 if (filter->pid < 0)
John Keeping3d8a6502014-01-12 17:13:50 +000053 goto done;
Jason A. Donenfeld3eae4062014-01-10 05:19:05 +010054 waitpid(filter->pid, &exit_status, 0);
55 if (WIFEXITED(exit_status) && !WEXITSTATUS(exit_status))
John Keeping3d8a6502014-01-12 17:13:50 +000056 goto done;
Jason A. Donenfeld3eae4062014-01-10 05:19:05 +010057 die("Subprocess %s exited abnormally", filter->cmd);
John Keeping3d8a6502014-01-12 17:13:50 +000058
59done:
60 for (i = 0; i < filter->extra_args; i++)
61 filter->argv[i+1] = NULL;
62 return 0;
63
Jason A. Donenfeld3eae4062014-01-10 05:19:05 +010064}
65
John Keeping632efb22014-01-12 17:13:51 +000066void cgit_fprintf_filter(struct cgit_filter *filter, FILE *f, const char *prefix)
67{
68 fprintf(f, "%s%s\n", prefix, filter->cmd);
69}
70
Jason A. Donenfeld3eae4062014-01-10 05:19:05 +010071struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype)
72{
73 struct cgit_filter *f;
74 int args_size = 0;
Jason A. Donenfeld3eae4062014-01-10 05:19:05 +010075
76 if (!cmd || !cmd[0])
77 return NULL;
78
John Keeping3d8a6502014-01-12 17:13:50 +000079 f = xmalloc(sizeof(struct cgit_filter));
80 memset(f, 0, sizeof(struct cgit_filter));
81
Jason A. Donenfeld3eae4062014-01-10 05:19:05 +010082 switch (filtertype) {
83 case SOURCE:
84 case ABOUT:
John Keeping3d8a6502014-01-12 17:13:50 +000085 f->extra_args = 1;
Jason A. Donenfeld3eae4062014-01-10 05:19:05 +010086 break;
87
88 case COMMIT:
89 default:
John Keeping3d8a6502014-01-12 17:13:50 +000090 f->extra_args = 0;
Jason A. Donenfeld3eae4062014-01-10 05:19:05 +010091 break;
92 }
Jason A. Donenfeld3eae4062014-01-10 05:19:05 +010093
94 f->cmd = xstrdup(cmd);
John Keeping3d8a6502014-01-12 17:13:50 +000095 args_size = (2 + f->extra_args) * sizeof(char *);
Jason A. Donenfeld3eae4062014-01-10 05:19:05 +010096 f->argv = xmalloc(args_size);
97 memset(f->argv, 0, args_size);
98 f->argv[0] = f->cmd;
99 return f;
100}