diff options
context:
space:
mode:
Diffstat (limited to 'source/filter.c')
-rw-r--r--source/filter.c22
1 file changed, 17 insertions, 5 deletions
diff --git a/source/filter.c b/source/filter.c
index 81c4681..1cfdde2 100644
--- a/source/filter.c
+++ b/source/filter.c
@@ -18,6 +18,10 @@
#include <lauxlib.h>
#endif
+// Exit status of a child that could not run the filter, the shell's own value
+// for a command not found.
+#define EXEC_FAILED 127
+
static int open_exec_filter(struct cgit_filter *base, va_list ap)
{
struct cgit_exec_filter *filter = (struct cgit_exec_filter *)base;
@@ -32,11 +36,18 @@ static int open_exec_filter(struct cgit_filter *base, va_list ap)
filter->pid = cgit_die_unless_non_negative(fork(), "Unable to create subprocess");
if (filter->pid == 0) {
close(pipefd[1]);
- cgit_die_unless_non_negative(dup2(pipefd[0], STDIN_FILENO), "Unable to use pipe as STDIN");
+ if (dup2(pipefd[0], STDIN_FILENO) < 0)
+ _exit(EXEC_FAILED);
execvp(filter->cmd, filter->argv);
- die_errno("Unable to exec subprocess %s", filter->cmd);
+ // The child shares the parent's page buffer, cache lock and exit
+ // handlers, so it must not die through them.
+ fprintf(stderr, "[cgit] Unable to exec filter %s: %s\n", filter->cmd, strerror(errno));
+ _exit(EXEC_FAILED);
}
close(pipefd[0]);
+ // 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_non_negative(dup2(pipefd[1], STDOUT_FILENO), "Unable to use pipe as STDOUT");
close(pipefd[1]);
return 0;
@@ -52,9 +63,10 @@ static int close_exec_filter(struct cgit_filter *base)
if (filter->pid < 0)
goto done;
waitpid(filter->pid, &exit_status, 0);
- if (WIFEXITED(exit_status))
- goto done;
- die("Subprocess %s exited abnormally", filter->cmd);
+ 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++)