/*
 * Wrapper for git-shell that only allows it to access ~/source.git.
 *
 * Also allows running a very few other special commands:
 *
 *   logview   tails site logs
 *   logdump   dumps site logs
 *
 * In C for speed.
 *
 * Use in .ssh/authorized_keys:
 * command="iki-git-shell",no-agent-forwarding,no-port-forwarding,no-X11-forwarding,no-pty,no-user-rc <key>
 *
 */

#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <pwd.h>

/* A "parked" flag file in the repo disables remote access.
 * The file content explains why. */
void checkparked (const char *repo) {
	char *flagfile;
	FILE *f;
	if (asprintf(&flagfile, "%s/parked", repo) == -1) {
		perror("asprintf");
		exit(1);
	}
	if ((f=fopen(flagfile, "r")) != NULL) {
		int bufsize=1024;
		char *buf=malloc(bufsize);
		while (fread(buf, bufsize, 1, f) > 0) {
			fwrite(buf, bufsize, 1, stderr);
		}
		exit(1);
	}
}

void logs (const char *param) {
	execlp("ikisite", "ikisite", "logs", param, NULL);
	perror("ikisite");
	exit(1);
}

int main (int argc, char **argv) {
	char *repo, *command, *subcommand, *s;
	struct passwd *passwd;

	passwd=getpwuid(geteuid());
	if (! passwd || ! passwd->pw_dir || ! strlen(passwd->pw_dir)) {
		fprintf(stderr, "error: failed to determine home directory\n");
		exit(1);
	}
	if (asprintf(&repo, "%s/source.git", passwd->pw_dir) == -1) {
		perror("asprintf");
		exit(1);
	}

	checkparked(repo);

	/*
	 * The original command passed to ssh will be
	 * "git subcommand path" or "git-subcommand path".
	 * Pass the subcommand on to git-shell, along with the path to the
	 * repository.
	 */

	command=getenv("SSH_ORIGINAL_COMMAND");
	if (! command) {
		fprintf(stderr, "error: SSH_ORIGINAL_COMMAND not set\n");
		exit(1);
	}

	s=strtok(command, " -"); /* handle "git-" and "git " */
	if (! s) {
		fprintf(stderr, "error: missing command\n");
		exit(1);
	}
	if (strcmp(s, "logview") == 0) {
		logs("--tail");
		exit(0);
	}
	if (strcmp(s, "logdump") == 0) {
		logs("--dump");
		exit(0);
	}
	if (strcmp(s, "git") != 0) {
		fprintf(stderr, "error: unknown command \"%s\"\n", s);
		exit(1);
	}

	s=strtok(NULL, " ");
	if (! s || ! strlen(s)) {
		fprintf(stderr, "error: missing git subcommand\n");
	}
	if (asprintf(&subcommand, "git-%s", s) == -1) {
		perror("asprintf");
		exit(1);
	}

	/* git-shell currently needs some wacky quoting around the
	 * subcommand and repo that its man page does not show */
	if (asprintf(&subcommand, "%s '%s'", subcommand, repo) == -1) {
		perror("asprintf");
		exit(1);
	}

	/* this variable is used to communicate to iki-git-hook-update
	 * that the commit is coming in from an external source */
	setenv("UNTRUSTED_COMMIT", "1", 1);

	execlp("git-shell", "git-shell", "-c", subcommand, NULL);
	perror("git-shell");
	exit(1);
}
